diff --git a/lib/config/config_lexer.ll b/lib/config/config_lexer.ll index c21e3a1a1..6968f014b 100644 --- a/lib/config/config_lexer.ll +++ b/lib/config/config_lexer.ll @@ -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; diff --git a/lib/config/config_parser.yy b/lib/config/config_parser.yy index 0e68be630..f11d51b6e 100644 --- a/lib/config/config_parser.yy +++ b/lib/config/config_parser.yy @@ -99,6 +99,7 @@ static void MakeRBinaryOp(Expression** result, Expression *left, Expression *rig std::vector *elist; std::pair *cvitem; std::map *cvlist; + icinga::ScopeSpecifier scope; } %token T_NEWLINE "new-line" @@ -201,13 +202,14 @@ static void MakeRBinaryOp(Expression** result, Expression *left, Expression *rig %type use_specifier_items %type use_specifier_item %type object_declaration +%type 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($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($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(&$$, $1, $3, @1, @3); } | rterm T_MODULO rterm { MakeRBinaryOp(&$$, $1, $3, @1, @3); } | rterm T_XOR rterm { MakeRBinaryOp(&$$, $1, $3, @1, @3); } - | T_FUNCTION identifier '(' identifier_items ')' use_specifier rterm_scope - { - DictExpression *aexpr = dynamic_cast($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($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(), $3, DebugInfoRange(@1, @3)); + $$ = new FunctionExpression(args, new std::map(), $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(), $5, DebugInfoRange(@1, @5)); + $$ = new FunctionExpression(*$2, new std::map(), $5, DebugInfoRange(@1, @5)); delete $2; } ; diff --git a/lib/config/configitembuilder.cpp b/lib/config/configitembuilder.cpp index 8601760e5..02f8d65bc 100644 --- a/lib/config/configitembuilder.cpp +++ b/lib/config/configitembuilder.cpp @@ -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(); diff --git a/lib/config/expression.cpp b/lib/config/expression.cpp index 447b6201a..634fe745f 100644 --- a/lib/config/expression.cpp +++ b/lib/config/expression.cpp @@ -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 diff --git a/lib/config/expression.hpp b/lib/config/expression.hpp index 444e974f1..26b3979b6 100644 --- a/lib/config/expression.hpp +++ b/lib/config/expression.hpp @@ -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& 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& 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 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& args, + FunctionExpression(const std::vector& args, std::map *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 m_Args; std::map *m_ClosedVars; boost::shared_ptr m_Expression; diff --git a/lib/config/vmops.hpp b/lib/config/vmops.hpp index d4d7d6c76..58608a86d 100644 --- a/lib/config/vmops.hpp +++ b/lib/config/vmops.hpp @@ -85,16 +85,11 @@ public: return result; } - static inline Value NewFunction(ScriptFrame& frame, const String& name, const std::vector& args, + static inline Value NewFunction(ScriptFrame& frame, const std::vector& args, std::map *closedVars, const boost::shared_ptr& 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) diff --git a/lib/icinga/dependency-apply.cpp b/lib/icinga/dependency-apply.cpp index 3f7c8c824..97c88d446 100644 --- a/lib/icinga/dependency-apply.cpp +++ b/lib/icinga/dependency-apply.cpp @@ -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())); diff --git a/lib/icinga/notification-apply.cpp b/lib/icinga/notification-apply.cpp index ed829f1e5..0dccc5f80 100644 --- a/lib/icinga/notification-apply.cpp +++ b/lib/icinga/notification-apply.cpp @@ -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())); diff --git a/lib/icinga/scheduleddowntime-apply.cpp b/lib/icinga/scheduleddowntime-apply.cpp index 16e4bd29f..52b86d3bf 100644 --- a/lib/icinga/scheduleddowntime-apply.cpp +++ b/lib/icinga/scheduleddowntime-apply.cpp @@ -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())); diff --git a/lib/icinga/service-apply.cpp b/lib/icinga/service-apply.cpp index 9ce9000dc..39a6b5dbd 100644 --- a/lib/icinga/service-apply.cpp +++ b/lib/icinga/service-apply.cpp @@ -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()));