void CommandDef::PreTypecheck(SymbolTable* root, bool atroot) { if(!atroot) { Error("commands can only be defined at global scope"); return; } if(root->Lookup(this->name) != Value::Undefined) { string err = "repeat definition of identifier '" + name + "'"; Error(err); return; } root->Define(this->name, Value(this)); this->parentScope = root; // Create a temporary scope, just to check for repeat parameter definitions SymbolTable* scope = new SymbolTable(root); for(unsigned int i = 0; i < args.size(); ++i) { if(scope->Define(args[i], Value::Null)) { string err = "repeat definition of parameter '" + args[i] + "'"; Error(err); } } delete scope; }
void TestAssembler() { Compiler comp("Methods"); { SymbolTable<Variable> args; args.Define(make_shared<Variable>("a", ATOMIC_TYPE::TYPE_INT)); args.Define(make_shared<Variable>("b", ATOMIC_TYPE::TYPE_INT)); auto fn = comp.NewFunction(DataType(ATOMIC_TYPE::TYPE_INT), "DoSum", args); fn->ldarg("a"); fn->ldarg("b"); fn->add(); fn->ret(); } { SymbolTable<Variable> args; args.Define(make_shared<Variable>("value", ATOMIC_TYPE::TYPE_INT)); auto fn = comp.NewFunction(DataType(ATOMIC_TYPE::TYPE_VOID), "PrintSum", args); fn->ldstr("The Result is: "); fn->call(comp.GetFunction("PrintString")); fn->ldarg("value"); fn->call(comp.GetFunction("PrintInt")); fn->ret(); } { auto fn = comp.NewFunction(DataType(ATOMIC_TYPE::TYPE_VOID), "main", SymbolTable<Variable>()); fn->ldc(10); fn->ldc(20); fn->call(comp.GetFunction("DoSum")); fn->call(comp.GetFunction("PrintSum")); fn->ret(); } comp.Compile(); }
Value CommandDef::Invoke(EvalContext& context, const vector<Expression*>& args) { if(executing) { // TODO: this recursion protection also prevents simple composition, // e.g., foo(foo("hi")). We should try to find a better way of detecting // recursion. // Basically, we should notice that while we _are_ evaluating the function // within itself, or rather, evaluating one of its argument expressions // requires making another call to the function, this will not lead to // infinite recursion. // It only looks that way because of lazy evaluation. Bottom line, when // evaluating a parameter ID, we should turn off the recursion check. Error("recursion detected in evaluation of command '" + this->name + "'"); return Value(); // return invalid value } /* NOTE: args check responsibility moved to caller if(args.size() != this->args.size()) { Error("incorrect number of parameters to command '" + this->name + "'"); return; }*/ executing = true; SymbolTable* scope = new SymbolTable( this->parentScope ); // First, bind the args to the local scope for(unsigned int i = 0; i < args.size(); ++i) { scope->Define(this->args[i], args[i]); } // First, build the command scope body->PreTypecheck(scope, false); string oldname = context.localscopename; context.localscopename = name; // Then evaluate the body of the command in the local scope Value result = body->Evaluate(scope, context); context.localscopename = oldname; delete scope; executing = false; return result; }