Example #1
0
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();
}
Example #3
0
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;
}