add global scope

This commit is contained in:
cajun
2024-09-29 14:07:07 -05:00
parent 8709e69bcc
commit ebc4c4fa8d
6 changed files with 39 additions and 8 deletions
+19 -1
View File
@@ -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,15 +275,28 @@ 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) {
ScriptValueP value = variables[string_to_variable(name)].value;
if (!value) throw ScriptErrorNoVariable(name);
+2
View File
@@ -54,6 +54,7 @@ public:
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 setGlobalVariable(Variable name, const ScriptValueP& value);
/// Get the value of a variable, throws if it not set
ScriptValueP getVariable(const String& name);
@@ -89,6 +90,7 @@ public:// public for FOR_EACH
VariableValue() : level(0) {}
unsigned int level; ///< Scope level on which this variable was set
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 {
+5
View File
@@ -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: {
+8 -4
View File
@@ -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
@@ -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 // + -
@@ -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();
@@ -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."));
}
+2 -1
View File
@@ -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;
}
+1
View File
@@ -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)