Implement the 'global' keyword to differentiate between variable scopes

refs #8074
This commit is contained in:
Gunnar Beutner 2014-12-13 17:48:58 +01:00
parent c0f6d65b66
commit dd4c04aa9b
10 changed files with 101 additions and 58 deletions

View File

@ -179,6 +179,7 @@ true { yylval->boolean = 1; return T_BOOLEAN; }
false { yylval->boolean = 0; return T_BOOLEAN; }
const return T_CONST;
local return T_LOCAL;
global return T_GLOBAL;
use return T_USE;
apply return T_APPLY;
to return T_TO;

View File

@ -99,6 +99,7 @@ static void MakeRBinaryOp(Expression** result, Expression *left, Expression *rig
std::vector<Expression *> *elist;
std::pair<String, Expression *> *cvitem;
std::map<String, Expression *> *cvlist;
icinga::ScopeSpecifier scope;
}
%token T_NEWLINE "new-line"
@ -201,13 +202,14 @@ static void MakeRBinaryOp(Expression** result, Expression *left, Expression *rig
%type <cvlist> use_specifier_items
%type <cvitem> use_specifier_item
%type <num> object_declaration
%type <scope> scope_specifier
%right T_FOLLOWS
%right T_INCLUDE T_INCLUDE_RECURSIVE T_OBJECT T_TEMPLATE T_APPLY T_IMPORT T_ASSIGN T_IGNORE T_WHERE
%right T_FUNCTION T_SIGNAL T_FOR
%left T_LOGICAL_OR
%left T_LOGICAL_AND
%left T_LOCAL T_RETURN
%left T_GLOBAL T_LOCAL T_RETURN
%left T_IDENTIFIER
%left T_SET T_SET_ADD T_SET_SUBTRACT T_SET_MULTIPLY T_SET_DIVIDE T_SET_MODULO T_SET_XOR T_SET_BINARY_AND T_SET_BINARY_OR
%nonassoc T_EQUAL T_NOT_EQUAL
@ -551,6 +553,16 @@ indexer_item: '.' identifier
}
;
scope_specifier: T_LOCAL
{
$$ = ScopeLocal;
}
| T_GLOBAL
{
$$ = ScopeGlobal;
}
;
combined_set_op: T_SET
| T_SET_ADD
| T_SET_SUBTRACT
@ -577,26 +589,26 @@ lterm: type
{
$$ = MakeLiteral(); // ASTify this
}
| T_LOCAL indexer combined_set_op rterm
{
$$ = new SetExpression(*$2, $3, $4, true, DebugInfoRange(@1, @4));
delete $2;
}
| indexer combined_set_op rterm
{
$$ = new SetExpression(*$1, $2, $3, false, DebugInfoRange(@1, @3));
$$ = new SetExpression(ScopeCurrent, *$1, $2, $3, DebugInfoRange(@1, @3));
delete $1;
}
| T_LOCAL identifier combined_set_op rterm
{
$$ = new SetExpression(MakeIndexer($2), $3, $4, true, DebugInfoRange(@1, @4));
free($2);
}
| identifier combined_set_op rterm
{
$$ = new SetExpression(MakeIndexer($1), $2, $3, false, DebugInfoRange(@1, @3));
$$ = new SetExpression(ScopeCurrent, MakeIndexer($1), $2, $3, DebugInfoRange(@1, @3));
free($1);
}
| scope_specifier indexer combined_set_op rterm
{
$$ = new SetExpression($1, *$2, $3, $4, DebugInfoRange(@1, @4));
delete $2;
}
| scope_specifier identifier combined_set_op rterm
{
$$ = new SetExpression($1, MakeIndexer($2), $3, $4, DebugInfoRange(@1, @4));
free($2);
}
| T_INCLUDE T_STRING
{
$$ = context->HandleInclude($2, false, DebugInfoRange(@1, @2));
@ -699,6 +711,28 @@ lterm: type
$$ = new ConditionalExpression($3, atrue, afalse, DebugInfoRange(@1, @7));
}
| T_FUNCTION identifier '(' identifier_items ')' use_specifier rterm_scope
{
DictExpression *aexpr = dynamic_cast<DictExpression *>($7);
aexpr->MakeInline();
FunctionExpression *fexpr = new FunctionExpression(*$4, $6, aexpr, DebugInfoRange(@1, @7));
delete $4;
$$ = new SetExpression(ScopeCurrent, MakeIndexer($2), OpSetLiteral, fexpr, DebugInfoRange(@1, @7));
free($2);
}
| scope_specifier T_FUNCTION identifier '(' identifier_items ')' use_specifier rterm_scope
{
DictExpression *aexpr = dynamic_cast<DictExpression *>($8);
aexpr->MakeInline();
FunctionExpression *fexpr = new FunctionExpression(*$5, $7, aexpr, DebugInfoRange(@1, @8));
delete $5;
$$ = new SetExpression($1, MakeIndexer($3), OpSetLiteral, fexpr, DebugInfoRange(@1, @8));
free($3);
}
| rterm
{
$$ = $1;
@ -853,21 +887,12 @@ rterm_without_indexer: T_STRING
| rterm T_DIVIDE_OP rterm { MakeRBinaryOp<DivideExpression>(&$$, $1, $3, @1, @3); }
| rterm T_MODULO rterm { MakeRBinaryOp<ModuloExpression>(&$$, $1, $3, @1, @3); }
| rterm T_XOR rterm { MakeRBinaryOp<XorExpression>(&$$, $1, $3, @1, @3); }
| T_FUNCTION identifier '(' identifier_items ')' use_specifier rterm_scope
{
DictExpression *aexpr = dynamic_cast<DictExpression *>($7);
aexpr->MakeInline();
$$ = new FunctionExpression($2, *$4, $6, aexpr, DebugInfoRange(@1, @6));
free($2);
delete $4;
}
| T_FUNCTION '(' identifier_items ')' use_specifier rterm_scope
{
DictExpression *aexpr = dynamic_cast<DictExpression *>($6);
aexpr->MakeInline();
$$ = new FunctionExpression("", *$3, $5, aexpr, DebugInfoRange(@1, @5));
$$ = new FunctionExpression(*$3, $5, aexpr, DebugInfoRange(@1, @5));
delete $3;
}
| identifier T_FOLLOWS rterm
@ -880,7 +905,7 @@ rterm_without_indexer: T_STRING
args.push_back($1);
free($1);
$$ = new FunctionExpression("", args, new std::map<String, Expression *>(), $3, DebugInfoRange(@1, @3));
$$ = new FunctionExpression(args, new std::map<String, Expression *>(), $3, DebugInfoRange(@1, @3));
}
| T_BINARY_OR identifier_items T_BINARY_OR T_FOLLOWS rterm
{
@ -888,7 +913,7 @@ rterm_without_indexer: T_STRING
if (aexpr)
aexpr->MakeInline();
$$ = new FunctionExpression("", *$2, new std::map<String, Expression *>(), $5, DebugInfoRange(@1, @5));
$$ = new FunctionExpression(*$2, new std::map<String, Expression *>(), $5, DebugInfoRange(@1, @5));
delete $2;
}
;

View File

@ -100,8 +100,8 @@ ConfigItem::Ptr ConfigItemBuilder::Compile(void)
Array::Ptr templateArray = new Array();
templateArray->Add(m_Name);
exprs.push_back(new SetExpression(MakeIndexer("templates"), OpSetAdd,
new LiteralExpression(templateArray), false, m_DebugInfo));
exprs.push_back(new SetExpression(ScopeCurrent, MakeIndexer("templates"), OpSetAdd,
new LiteralExpression(templateArray), m_DebugInfo));
DictExpression *dexpr = new DictExpression(m_Expressions, m_DebugInfo);
dexpr->MakeInline();

View File

@ -333,10 +333,20 @@ Value SetExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const
}
if (i == 0) {
if (m_Local)
if (m_ScopeSpec == ScopeLocal)
parent = frame.Locals;
else
else if (m_ScopeSpec == ScopeCurrent)
parent = frame.Self;
else if (m_ScopeSpec == ScopeGlobal) {
ScriptVariable::Ptr sv = ScriptVariable::GetByName(tempindex);
Dictionary::Ptr fglobals = new Dictionary();
if (sv)
fglobals->Set(tempindex, sv->GetData());
parent = fglobals;
}
} else
parent = object;
@ -353,7 +363,10 @@ Value SetExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const
if (i != m_Indexer.size() - 1 && object.IsEmpty()) {
object = new Dictionary();
VMOps::SetField(parent, tempindex, object, m_DebugInfo);
if (i == 0 && m_ScopeSpec == ScopeGlobal)
ScriptVariable::Set(tempindex, object);
else
VMOps::SetField(parent, tempindex, object, m_DebugInfo);
}
}
@ -393,7 +406,10 @@ Value SetExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const
}
}
VMOps::SetField(parent, index, right, m_DebugInfo);
if (m_Indexer.size() == 1 && m_ScopeSpec == ScopeGlobal)
ScriptVariable::Set(index, right);
else
VMOps::SetField(parent, index, right, m_DebugInfo);
if (psdhint)
psdhint->AddMessage("=", m_DebugInfo);
@ -438,7 +454,7 @@ Value ImportExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const
Value FunctionExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const
{
return VMOps::NewFunction(frame, m_Name, m_Args, m_ClosedVars, m_Expression);
return VMOps::NewFunction(frame, m_Args, m_ClosedVars, m_Expression);
}
Value SlotExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const

View File

@ -106,6 +106,13 @@ enum CombinedSetOp
OpSetBinaryOr
};
enum ScopeSpecifier
{
ScopeLocal,
ScopeCurrent,
ScopeGlobal
};
class InterruptExecutionError : virtual public std::exception, virtual public boost::exception
{
public:
@ -586,8 +593,8 @@ private:
class I2_CONFIG_API SetExpression : public DebuggableExpression
{
public:
SetExpression(const std::vector<Expression *>& indexer, CombinedSetOp op, Expression *operand2, bool local, const DebugInfo& debugInfo = DebugInfo())
: DebuggableExpression(debugInfo), m_Op(op), m_Indexer(indexer), m_Operand2(operand2), m_Local(local)
SetExpression(ScopeSpecifier scopeSpec, const std::vector<Expression *>& indexer, CombinedSetOp op, Expression *operand2, const DebugInfo& debugInfo = DebugInfo())
: DebuggableExpression(debugInfo), m_ScopeSpec(scopeSpec), m_Op(op), m_Indexer(indexer), m_Operand2(operand2)
{ }
~SetExpression(void)
@ -602,10 +609,10 @@ protected:
virtual Value DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const;
private:
ScopeSpecifier m_ScopeSpec;
CombinedSetOp m_Op;
std::vector<Expression *> m_Indexer;
Expression *m_Operand2;
bool m_Local;
};
@ -685,16 +692,15 @@ private:
class I2_CONFIG_API FunctionExpression : public DebuggableExpression
{
public:
FunctionExpression(const String& name, const std::vector<String>& args,
FunctionExpression(const std::vector<String>& args,
std::map<String, Expression *> *closedVars, Expression *expression, const DebugInfo& debugInfo = DebugInfo())
: DebuggableExpression(debugInfo), m_Name(name), m_Args(args), m_ClosedVars(closedVars), m_Expression(expression)
: DebuggableExpression(debugInfo), m_Args(args), m_ClosedVars(closedVars), m_Expression(expression)
{ }
protected:
virtual Value DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const;
private:
String m_Name;
std::vector<String> m_Args;
std::map<String, Expression *> *m_ClosedVars;
boost::shared_ptr<Expression> m_Expression;

View File

@ -85,16 +85,11 @@ public:
return result;
}
static inline Value NewFunction(ScriptFrame& frame, const String& name, const std::vector<String>& args,
static inline Value NewFunction(ScriptFrame& frame, const std::vector<String>& args,
std::map<String, Expression *> *closedVars, const boost::shared_ptr<Expression>& expression)
{
ScriptFunction::Ptr func = new ScriptFunction(boost::bind(&FunctionWrapper, _1, args,
return new ScriptFunction(boost::bind(&FunctionWrapper, _1, args,
EvaluateClosedVars(frame, closedVars), expression));
if (!name.IsEmpty())
ScriptFunction::Register(name, func);
return func;
}
static inline Value NewSlot(ScriptFrame& frame, const String& signal, const Value& slot)

View File

@ -58,16 +58,16 @@ void Dependency::EvaluateApplyRuleInstance(const Checkable::Ptr& checkable, cons
Service::Ptr service;
tie(host, service) = GetHostService(checkable);
builder->AddExpression(new SetExpression(MakeIndexer("parent_host_name"), OpSetLiteral, MakeLiteral(host->GetName()), false, di));
builder->AddExpression(new SetExpression(MakeIndexer("child_host_name"), OpSetLiteral, MakeLiteral(host->GetName()), false, di));
builder->AddExpression(new SetExpression(ScopeCurrent, MakeIndexer("parent_host_name"), OpSetLiteral, MakeLiteral(host->GetName()), di));
builder->AddExpression(new SetExpression(ScopeCurrent, MakeIndexer("child_host_name"), OpSetLiteral, MakeLiteral(host->GetName()), di));
if (service)
builder->AddExpression(new SetExpression(MakeIndexer("child_service_name"), OpSetLiteral, MakeLiteral(service->GetShortName()), false, di));
builder->AddExpression(new SetExpression(ScopeCurrent, MakeIndexer("child_service_name"), OpSetLiteral, MakeLiteral(service->GetShortName()), di));
String zone = checkable->GetZone();
if (!zone.IsEmpty())
builder->AddExpression(new SetExpression(MakeIndexer("zone"), OpSetLiteral, MakeLiteral(zone), false, di));
builder->AddExpression(new SetExpression(ScopeCurrent, MakeIndexer("zone"), OpSetLiteral, MakeLiteral(zone), di));
builder->AddExpression(new OwnedExpression(rule.GetExpression()));

View File

@ -58,15 +58,15 @@ void Notification::EvaluateApplyRuleInstance(const Checkable::Ptr& checkable, co
Service::Ptr service;
tie(host, service) = GetHostService(checkable);
builder->AddExpression(new SetExpression(MakeIndexer("host_name"), OpSetLiteral, MakeLiteral(host->GetName()), false, di));
builder->AddExpression(new SetExpression(ScopeCurrent, MakeIndexer("host_name"), OpSetLiteral, MakeLiteral(host->GetName()), di));
if (service)
builder->AddExpression(new SetExpression(MakeIndexer("service_name"), OpSetLiteral, MakeLiteral(service->GetShortName()), false, di));
builder->AddExpression(new SetExpression(ScopeCurrent, MakeIndexer("service_name"), OpSetLiteral, MakeLiteral(service->GetShortName()), di));
String zone = checkable->GetZone();
if (!zone.IsEmpty())
builder->AddExpression(new SetExpression(MakeIndexer("zone"), OpSetLiteral, MakeLiteral(zone), false, di));
builder->AddExpression(new SetExpression(ScopeCurrent, MakeIndexer("zone"), OpSetLiteral, MakeLiteral(zone), di));
builder->AddExpression(new OwnedExpression(rule.GetExpression()));

View File

@ -57,15 +57,15 @@ void ScheduledDowntime::EvaluateApplyRuleInstance(const Checkable::Ptr& checkabl
Service::Ptr service;
tie(host, service) = GetHostService(checkable);
builder->AddExpression(new SetExpression(MakeIndexer("host_name"), OpSetLiteral, MakeLiteral(host->GetName()), false, di));
builder->AddExpression(new SetExpression(ScopeCurrent, MakeIndexer("host_name"), OpSetLiteral, MakeLiteral(host->GetName()), di));
if (service)
builder->AddExpression(new SetExpression(MakeIndexer("service_name"), OpSetLiteral, MakeLiteral(service->GetShortName()), false, di));
builder->AddExpression(new SetExpression(ScopeCurrent, MakeIndexer("service_name"), OpSetLiteral, MakeLiteral(service->GetShortName()), di));
String zone = checkable->GetZone();
if (!zone.IsEmpty())
builder->AddExpression(new SetExpression(MakeIndexer("zone"), OpSetLiteral, MakeLiteral(zone), false, di));
builder->AddExpression(new SetExpression(ScopeCurrent, MakeIndexer("zone"), OpSetLiteral, MakeLiteral(zone), di));
builder->AddExpression(new OwnedExpression(rule.GetExpression()));

View File

@ -52,14 +52,14 @@ void Service::EvaluateApplyRuleInstance(const Host::Ptr& host, const String& nam
builder->SetName(name);
builder->SetScope(frame.Locals);
builder->AddExpression(new SetExpression(MakeIndexer("host_name"), OpSetLiteral, MakeLiteral(host->GetName()), false, di));
builder->AddExpression(new SetExpression(ScopeCurrent, MakeIndexer("host_name"), OpSetLiteral, MakeLiteral(host->GetName()), di));
builder->AddExpression(new SetExpression(MakeIndexer("name"), OpSetLiteral, MakeLiteral(name), false, di));
builder->AddExpression(new SetExpression(ScopeCurrent, MakeIndexer("name"), OpSetLiteral, MakeLiteral(name), di));
String zone = host->GetZone();
if (!zone.IsEmpty())
builder->AddExpression(new SetExpression(MakeIndexer("zone"), OpSetLiteral, MakeLiteral(zone), false, di));
builder->AddExpression(new SetExpression(ScopeCurrent, MakeIndexer("zone"), OpSetLiteral, MakeLiteral(zone), di));
builder->AddExpression(new OwnedExpression(rule.GetExpression()));