Example #1
0
Value IdentExpr::Evaluate(SymbolTable* scope, EvalContext& context, bool asbool)
{
	/// Scope override; must do this for every expression that might contain an identifier
	if(this->scope != NULL)
		scope = this->scope;

	//context.file = this->file;
	//context.line = this->linenumber;

	// To evaluate an identifier expression:
	// First, we have to look up the symbol and check the type of its value.
	// If it's a constant, we just evaluate the constant (provided there are no
	// parameters given; if there are parameters, we should report an error.)
	// If it's a command, we need to:
	//  - bind each argument expression to the corresponding symbol in the commands
	//     parameter list.
	//  - invoke the command.

	Module* module = context.module;
	
	SymbolTable* lookupScope = scope;

	// If the ident expr's "file" field is not empty, we'll look it up in a different module
	if(!file.empty()) {
		Module* mod = module->GetSiblingContext(file);
		if(!mod) {
			Error("reference to nonexistent module '" + file + "'");
			return Value::Null;
		}
		lookupScope = mod->GetRootTable();
	}

	Value found = lookupScope->Lookup(name);

	if(found != Value::Undefined) {
		// In most cases, we just return the value.
		if(found.GetType() != Type::Macro)
		{
			// However, evaluated vars are not importable.
			if(lookupScope != scope) {
				Error("cannot access local variable declaration '" + name + "' in module '" + file + "'");
				return Value::Null;
			}
			return found;
		}

		Node* node = found.GetNode();
		Value result;

		if(node->GetType() == conststmt)
		{
			if(hasparens) {
				Error("'" + GetFullName() + "' refers to a constant; cannot use parentheses");
				return Value();
			}
			result = dynamic_cast<ConstDef*>(node)->EvaluateExpr(scope, context, asbool);
		}
		else if(node->GetType() == commandstmt)
		{
			for(unsigned int i = 0; i < args.size(); ++i)
				args[i]->scope = scope;

			CommandDef* cmd = dynamic_cast<CommandDef*>(found.GetNode());

			if(cmd->GetArgCount() != args.size())
				Error("incorrect number of parameters to command '" + GetFullName() + "'");
			else
				result = cmd->Invoke(context, args);
		}
		else if(node->GetType() == ambiguousid)
		{
			AmbiguousID* ambig = dynamic_cast<AmbiguousID*>(found.GetNode());
			Error(ambig->ToString(""));
			result = Value::Null;
		}
		else if(node->IsExpression())
		{
			result = dynamic_cast<Expression*>(node)->Evaluate(scope, context, asbool);
		}
		else
		{
			Error("invalid type");
		}
		return result;
	}

	// Didn't find it in the symbol table, check the jumps table
	Anchor* foundanchor = lookupScope->LookupAnchor(name);

	if(foundanchor) {
		if(hasparens) {
			Error("'" + GetFullName() + "' refers to a label; cannot use parentheses");
			return Value();
		}

		String* val = new String();
		val->Long(foundanchor->GetTarget());

		// The targeted label might not have its address computed yet, so we register a
		// reference to the target label (unless refs are forbidden by the context)
		if(!context.norefs)
			val->AddReference(val->GetPos()-4, foundanchor);

		return Value(val);
	}

	Error("use of undefined identifier '" + GetFullName() + "'");
	return Value();
}