diff --git a/src/script/context.cpp b/src/script/context.cpp index c73813fc..11b891df 100644 --- a/src/script/context.cpp +++ b/src/script/context.cpp @@ -106,6 +106,11 @@ ScriptValueP Context::eval(const Script& script, bool useScope) { setVariable((Variable)i.data, stack.back()); break; } + // Set a global variable + case I_SET_GLB: { + setGlobalVariable((Variable)i.data, stack.back()); + break; + } // Get an object member case I_MEMBER_C: { @@ -270,13 +275,26 @@ void Context::setVariable(Variable name, const ScriptValueP& value) { assert((size_t)name < variable_names.size()); #endif VariableValue& var = variables[name]; - if (var.level < level) { + if (var.level < level && !var.global_scope) { // keep shadow copy Binding bind = {name, var}; shadowed.push_back(bind); + } + if (!var.global_scope) { + var.global_scope = false; } var.level = level; var.value = value; +} + +void Context::setGlobalVariable(Variable name, const ScriptValueP& value) { +#ifdef _DEBUG + assert((size_t)name < variable_names.size()); +#endif + VariableValue& var = variables[name]; + var.level = level; + var.value = value; + var.global_scope = true; } ScriptValueP Context::getVariable(const String& name) { diff --git a/src/script/context.hpp b/src/script/context.hpp index e687fa31..d70bf426 100644 --- a/src/script/context.hpp +++ b/src/script/context.hpp @@ -53,7 +53,8 @@ public: /// Set a variable to a new value (in the current scope) void setVariable(const String& name, const ScriptValueP& value); /// Set a variable to a new value (in the current scope) - void setVariable(Variable name, const ScriptValueP& value); + void setVariable(Variable name, const ScriptValueP& value); + void setGlobalVariable(Variable name, const ScriptValueP& value); /// Get the value of a variable, throws if it not set ScriptValueP getVariable(const String& name); @@ -88,7 +89,8 @@ public:// public for FOR_EACH struct VariableValue { VariableValue() : level(0) {} unsigned int level; ///< Scope level on which this variable was set - ScriptValueP value; ///< Value of this variable + ScriptValueP value; ///< Value of this variable + bool global_scope = false; ///< Is this variable globally scoped? }; /// Record of a variable binding that is being shadowed (overwritten) by another binding struct Binding { diff --git a/src/script/dependency.cpp b/src/script/dependency.cpp index 69911589..e0281a03 100644 --- a/src/script/dependency.cpp +++ b/src/script/dependency.cpp @@ -301,6 +301,11 @@ ScriptValueP Context::dependencies(const Dependency& dep, const Script& script) setVariable((Variable)i.data, stack.back()); break; } + // Set a global variable (as normal) + case I_SET_GLB: { + setGlobalVariable((Variable)i.data, stack.back()); + break; + } // Simple instruction: unary case I_UNARY: { diff --git a/src/script/parser.cpp b/src/script/parser.cpp index b47410c3..e0596731 100644 --- a/src/script/parser.cpp +++ b/src/script/parser.cpp @@ -745,7 +745,11 @@ ExprType parseOper(TokenIterator& input, Script& script, Precedence minPrec, Ins return EXPR_FAILED; } script.getInstructions().pop_back(); - type = parseOper(input, script, PREC_SET, I_SET_VAR, instr.data); + if(token==_("->")) { + type = parseOper(input, script, PREC_SET, I_SET_GLB, instr.data); + } else { + type = parseOper(input, script, PREC_SET, I_SET_VAR, instr.data); + } if (type == EXPR_STATEMENT) { input.add_error(_("Warning: the right hand side of an assignment should always yield a value.")); } diff --git a/src/script/script.cpp b/src/script/script.cpp index 2679d1d9..00befdb1 100644 --- a/src/script/script.cpp +++ b/src/script/script.cpp @@ -176,6 +176,7 @@ String Script::dumpInstr(unsigned int pos, Instruction i) const { case I_JUMP_SC_OR: ret += _("jump sc or"); break; case I_GET_VAR: ret += _("get"); break; case I_SET_VAR: ret += _("set"); break; + case I_SET_GLB: ret += _("set_global"); break; case I_MEMBER_C: ret += _("member_c"); break; case I_LOOP: ret += _("loop"); break; case I_LOOP_WITH_KEY:ret += _("loop with key"); break; @@ -236,7 +237,7 @@ String Script::dumpInstr(unsigned int pos, Instruction i) const { case I_CALL: case I_CLOSURE: case I_DUP: // int ret += String::Format(_("\t%d"), i.data); break; - case I_GET_VAR: case I_SET_VAR: case I_NOP: // variable + case I_GET_VAR: case I_SET_VAR: case I_NOP: case I_SET_GLB: // variable ret += _("\t") + variable_to_string((Variable)i.data); break; } diff --git a/src/script/script.hpp b/src/script/script.hpp index 12db619e..f0919dfa 100644 --- a/src/script/script.hpp +++ b/src/script/script.hpp @@ -30,6 +30,7 @@ enum InstructionType // Variables , I_GET_VAR = 4 ///< arg = var : find a variable, push its value onto the stack, it is an error if the variable is not found , I_SET_VAR = 5 ///< arg = var : assign the top value from the stack to a variable (doesn't pop) +, I_SET_GLB = 21 ///< arg = var : assign the top value from the stack to a global variable (doesn't pop) // Objects , I_MEMBER_C = 6 ///< arg = const name : finds a member of the top of the stack replaces the top of the stack with the member , I_LOOP = 7 ///< arg = address : loop over the elements of an iterator, which is the *second* element of the stack (this allows for combing the results of multiple iterations)