Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 19 additions & 1 deletion src/script/context.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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: {
Expand Down Expand Up @@ -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) {
Expand Down
6 changes: 4 additions & 2 deletions src/script/context.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,8 @@ class Context {
/// 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);
Expand Down Expand Up @@ -88,7 +89,8 @@ class Context {
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 {
Expand Down
5 changes: 5 additions & 0 deletions src/script/dependency.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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: {
Expand Down
12 changes: 8 additions & 4 deletions src/script/parser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ bool isOper (wxUniChar c) { return wxStrchr(_("+-*/!.@%^&:=<>;,"),c) != nullptr
bool isLparen(wxUniChar c) { return c==_('(') || c==_('[') || c==_('{'); }
bool isRparen(wxUniChar c) { return c==_(')') || c==_(']') || c==_('}'); }
bool isDigitOrDot(wxUniChar c) { return isDigit(c) || c==_('.'); }
bool isLongOper(StringView s) { return s==_(":=") || s==_("==") || s==_("!=") || s==_("<=") || s==_(">="); }
bool isLongOper(StringView s) { return s==_(":=") || s==_("==") || s==_("!=") || s==_("<=") || s==_(">=") || s==_("->"); }

// moveme
// ----------------------------------------------------------------------------- : Tokenizing
Expand Down Expand Up @@ -351,7 +351,7 @@ enum Precedence
{ PREC_ALL
, PREC_NEWLINE // newline ;
, PREC_SEQ // ;
, PREC_SET // :=
, PREC_SET // := ->
, PREC_AND // and or
, PREC_CMP // == != < > <= >=
, PREC_ADD // + -
Expand Down Expand Up @@ -736,7 +736,7 @@ ExprType parseOper(TokenIterator& input, Script& script, Precedence minPrec, Ins
}
script.addInstruction(I_POP); // discard result of first expression
type = parseOper(input, script, PREC_SET);
} else if (minPrec <= PREC_SET && token==_(":=")) {
} else if (minPrec <= PREC_SET && (token==_(":=") || token==_("->"))) {
// We made a mistake, the part before the := should be a variable name,
// not an expression. Remove that instruction.
Instruction& instr = script.getInstructions().back();
Expand All @@ -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."));
}
Expand Down
3 changes: 2 additions & 1 deletion src/script/script.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
}
Expand Down
1 change: 1 addition & 0 deletions src/script/script.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down