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; } false { yylval->boolean = 0; return T_BOOLEAN; }
const return T_CONST; const return T_CONST;
local return T_LOCAL; local return T_LOCAL;
global return T_GLOBAL;
use return T_USE; use return T_USE;
apply return T_APPLY; apply return T_APPLY;
to return T_TO; to return T_TO;

View File

@ -99,6 +99,7 @@ static void MakeRBinaryOp(Expression** result, Expression *left, Expression *rig
std::vector<Expression *> *elist; std::vector<Expression *> *elist;
std::pair<String, Expression *> *cvitem; std::pair<String, Expression *> *cvitem;
std::map<String, Expression *> *cvlist; std::map<String, Expression *> *cvlist;
icinga::ScopeSpecifier scope;
} }
%token T_NEWLINE "new-line" %token T_NEWLINE "new-line"
@ -201,13 +202,14 @@ static void MakeRBinaryOp(Expression** result, Expression *left, Expression *rig
%type <cvlist> use_specifier_items %type <cvlist> use_specifier_items
%type <cvitem> use_specifier_item %type <cvitem> use_specifier_item
%type <num> object_declaration %type <num> object_declaration
%type <scope> scope_specifier
%right T_FOLLOWS %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_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 %right T_FUNCTION T_SIGNAL T_FOR
%left T_LOGICAL_OR %left T_LOGICAL_OR
%left T_LOGICAL_AND %left T_LOGICAL_AND
%left T_LOCAL T_RETURN %left T_GLOBAL T_LOCAL T_RETURN
%left T_IDENTIFIER %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 %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 %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 combined_set_op: T_SET
| T_SET_ADD | T_SET_ADD
| T_SET_SUBTRACT | T_SET_SUBTRACT
@ -577,26 +589,26 @@ lterm: type
{ {
$$ = MakeLiteral(); // ASTify this $$ = 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 | 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; 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 | 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); 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 | T_INCLUDE T_STRING
{ {
$$ = context->HandleInclude($2, false, DebugInfoRange(@1, @2)); $$ = context->HandleInclude($2, false, DebugInfoRange(@1, @2));
@ -699,6 +711,28 @@ lterm: type
$$ = new ConditionalExpression($3, atrue, afalse, DebugInfoRange(@1, @7)); $$ = 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 | rterm
{ {
$$ = $1; $$ = $1;
@ -853,21 +887,12 @@ rterm_without_indexer: T_STRING
| rterm T_DIVIDE_OP rterm { MakeRBinaryOp<DivideExpression>(&$$, $1, $3, @1, @3); } | rterm T_DIVIDE_OP rterm { MakeRBinaryOp<DivideExpression>(&$$, $1, $3, @1, @3); }
| rterm T_MODULO rterm { MakeRBinaryOp<ModuloExpression>(&$$, $1, $3, @1, @3); } | rterm T_MODULO rterm { MakeRBinaryOp<ModuloExpression>(&$$, $1, $3, @1, @3); }
| rterm T_XOR rterm { MakeRBinaryOp<XorExpression>(&$$, $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 | T_FUNCTION '(' identifier_items ')' use_specifier rterm_scope
{ {
DictExpression *aexpr = dynamic_cast<DictExpression *>($6); DictExpression *aexpr = dynamic_cast<DictExpression *>($6);
aexpr->MakeInline(); aexpr->MakeInline();
$$ = new FunctionExpression("", *$3, $5, aexpr, DebugInfoRange(@1, @5)); $$ = new FunctionExpression(*$3, $5, aexpr, DebugInfoRange(@1, @5));
delete $3; delete $3;
} }
| identifier T_FOLLOWS rterm | identifier T_FOLLOWS rterm
@ -880,7 +905,7 @@ rterm_without_indexer: T_STRING
args.push_back($1); args.push_back($1);
free($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 | T_BINARY_OR identifier_items T_BINARY_OR T_FOLLOWS rterm
{ {
@ -888,7 +913,7 @@ rterm_without_indexer: T_STRING
if (aexpr) if (aexpr)
aexpr->MakeInline(); 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; delete $2;
} }
; ;

View File

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

View File

@ -333,10 +333,20 @@ Value SetExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const
} }
if (i == 0) { if (i == 0) {
if (m_Local) if (m_ScopeSpec == ScopeLocal)
parent = frame.Locals; parent = frame.Locals;
else else if (m_ScopeSpec == ScopeCurrent)
parent = frame.Self; 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 } else
parent = object; parent = object;
@ -353,7 +363,10 @@ Value SetExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const
if (i != m_Indexer.size() - 1 && object.IsEmpty()) { if (i != m_Indexer.size() - 1 && object.IsEmpty()) {
object = new Dictionary(); 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) if (psdhint)
psdhint->AddMessage("=", m_DebugInfo); psdhint->AddMessage("=", m_DebugInfo);
@ -438,7 +454,7 @@ Value ImportExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const
Value FunctionExpression::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 Value SlotExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const

View File

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

View File

@ -85,16 +85,11 @@ public:
return result; 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) 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)); 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) 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; Service::Ptr service;
tie(host, service) = GetHostService(checkable); tie(host, service) = GetHostService(checkable);
builder->AddExpression(new SetExpression(MakeIndexer("parent_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(MakeIndexer("child_host_name"), OpSetLiteral, MakeLiteral(host->GetName()), false, di)); builder->AddExpression(new SetExpression(ScopeCurrent, MakeIndexer("child_host_name"), OpSetLiteral, MakeLiteral(host->GetName()), di));
if (service) 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(); String zone = checkable->GetZone();
if (!zone.IsEmpty()) 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())); builder->AddExpression(new OwnedExpression(rule.GetExpression()));

View File

@ -58,15 +58,15 @@ void Notification::EvaluateApplyRuleInstance(const Checkable::Ptr& checkable, co
Service::Ptr service; Service::Ptr service;
tie(host, service) = GetHostService(checkable); 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) 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(); String zone = checkable->GetZone();
if (!zone.IsEmpty()) 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())); builder->AddExpression(new OwnedExpression(rule.GetExpression()));

View File

@ -57,15 +57,15 @@ void ScheduledDowntime::EvaluateApplyRuleInstance(const Checkable::Ptr& checkabl
Service::Ptr service; Service::Ptr service;
tie(host, service) = GetHostService(checkable); 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) 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(); String zone = checkable->GetZone();
if (!zone.IsEmpty()) 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())); 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->SetName(name);
builder->SetScope(frame.Locals); 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(); String zone = host->GetZone();
if (!zone.IsEmpty()) 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())); builder->AddExpression(new OwnedExpression(rule.GetExpression()));