All Downloads are FREE. Search and download functionalities are using the official Maven repository.

prompto.statement.UnresolvedCall Maven / Gradle / Ivy

The newest version!
package prompto.statement;

import prompto.compiler.Flags;
import prompto.compiler.MethodInfo;
import prompto.compiler.ResultInfo;
import prompto.declaration.CategoryDeclaration;
import prompto.declaration.ConcreteCategoryDeclaration;
import prompto.declaration.IDeclaration;
import prompto.declaration.TestMethodDeclaration;
import prompto.error.PromptoError;
import prompto.error.SyntaxError;
import prompto.expression.ConstructorExpression;
import prompto.expression.IAssertion;
import prompto.expression.IExpression;
import prompto.expression.MemberSelector;
import prompto.expression.MethodSelector;
import prompto.expression.SelectorBase;
import prompto.expression.UnresolvedIdentifier;
import prompto.expression.UnresolvedSelector;
import prompto.grammar.ArgumentList;
import prompto.grammar.INamed;
import prompto.grammar.Identifier;
import prompto.parser.Dialect;
import prompto.parser.ICodeSection;
import prompto.runtime.Context;
import prompto.runtime.Context.InstanceContext;
import prompto.runtime.Context.MethodDeclarationMap;
import prompto.transpiler.Transpiler;
import prompto.type.CategoryType;
import prompto.type.IType;
import prompto.type.MethodType;
import prompto.utils.CodeWriter;
import prompto.value.IValue;
import prompto.value.NullValue;

public class UnresolvedCall extends BaseStatement implements IAssertion {
	
	IExpression caller;
	IExpression resolved;
	ArgumentList arguments;
	
	public UnresolvedCall(IExpression caller, ArgumentList arguments) {
		this.caller = caller;
		this.arguments = arguments;
	}
	
	public void setParent(IExpression parent) {
		if(parent!=null) {
			if(caller instanceof UnresolvedIdentifier)
				caller = new MethodSelector(parent, ((UnresolvedIdentifier)caller).getId());
			else if(caller instanceof SelectorBase)
				((SelectorBase)caller).setParent(parent);
			else
				throw new IllegalStateException("Should never happen!");
		}
	}
	
	@Override
	public boolean isSimple() {
		return true;
	}
	
	@Override
	public String toString() {
		return caller.toString();
	}
	
	public void setCaller(IExpression caller) {
		this.caller = caller;
	}
	
	public IExpression getCaller() {
		return caller;
	}
	
	public ArgumentList getArguments() {
		return arguments;
	}
	
	@Override
	public void toDialect(CodeWriter writer) {
		try {
			doResolve(writer.getContext());
			resolved.toDialect(writer);
		} catch(SyntaxError error) {
			caller.toDialect(writer);
			if(arguments!=null)
				arguments.toDialect(writer);
			else if(writer.getDialect() != Dialect.E)
				writer.append("()");
		}
	}
	
	@Override
	public IType check(Context context) {
		return resolveAndCheck(context);
	}
	
	@Override
	public IValue interpret(Context context) throws PromptoError {
		resolveAndCheck(context);
		if(resolved==null) {
			context.getProblemListener().reportUnknownMethod(this, caller.toString());
			return NullValue.instance();
		} else
			return resolved.interpret(context);
	}
	
	@Override
	public ResultInfo compile(Context context, MethodInfo method, Flags flags) {
		resolveAndCheck(context);
		return resolved.compile(context, method, flags);
	}

	@Override
	public boolean interpretAssert(Context context, TestMethodDeclaration test) throws PromptoError {
		if(resolved==null)
			resolveAndCheck(context);
		if(resolved instanceof IAssertion)
			return ((IAssertion)resolved).interpretAssert(context, test);
		else {
			CodeWriter writer = new CodeWriter(this.getDialect(), context);
			resolved.toDialect(writer);
			throw new SyntaxError("Cannot test '" + writer.toString() + "'");
		}
	}
	
	@Override
	public void compileAssert(Context context, MethodInfo method, Flags flags, TestMethodDeclaration test) {
		if(resolved==null)
			resolveAndCheck(context);
		if(resolved instanceof IAssertion)
			((IAssertion)resolved).compileAssert(context, method, flags, test);
		else {
			CodeWriter writer = new CodeWriter(this.getDialect(), context);
			resolved.toDialect(writer);
			throw new SyntaxError("Cannot test '" + writer.toString() + "'");
		}
	}
	
	public IExpression resolve(Context context) {
		doResolve(context);
		return resolved;
	}
	
	protected IType resolveAndCheck(Context context) {
		doResolve(context);
		if(resolved==null)
			return null;
		else
			return resolved.check(context);
	}
	
	
	protected void doResolve(Context context) {
		if(resolved==null) {
			if(caller instanceof UnresolvedIdentifier)
				resolved = resolveUnresolvedIdentifier(context, (UnresolvedIdentifier)caller);
			else if(caller instanceof UnresolvedSelector)
				resolved = resolveUnresolvedSelector(context, (UnresolvedSelector)caller);
			else if(caller instanceof MemberSelector)
				resolved = resolveMemberSelector(context, (MemberSelector)caller);
			if(resolved instanceof ICodeSection)
				((ICodeSection)resolved).setSectionFrom(this);
		}
		if(resolved==null)
	    	context.getProblemListener().reportUnknownMethod(this, this.toString());
	}
	
	private IExpression resolveUnresolvedSelector(Context context, UnresolvedSelector caller) {
		caller.resolveMethod(context, arguments);
		return caller.getResolved();
	}

	private IExpression resolveUnresolvedIdentifier(Context context, UnresolvedIdentifier caller) {
		Identifier id = caller.getId();
		IExpression call = null;
		// if this happens in the context of an instance, then we need to check for category members first
		call = resolveUnresolvedMemberMethod(context, id);
		if(call==null)
			call = resolveUnresolvedMethodReference(context, id);
		if(call==null) 
			call = resolveUnresolvedDeclaration(context, id);
		if(call==null)
			context.getProblemListener().reportUnknownMethod(id, id.toString());
		return call;
	}

	private IExpression resolveUnresolvedDeclaration(Context context, Identifier id) {
		IDeclaration decl = context.getRegisteredDeclaration(IDeclaration.class, id);
		if(decl==null)
			return null;
		else if(decl instanceof CategoryDeclaration)
			return new ConstructorExpression(new CategoryType(id), null, arguments);
		else
			return new MethodCall(new MethodSelector(id), arguments);
	}

	private IExpression resolveUnresolvedMethodReference(Context context, Identifier id) {
		INamed named = context.getRegisteredValue(INamed.class, id);
		if(named==null)
			return null;
		IType type = named.getType(context).resolve(context, null);
		if(type instanceof MethodType) {
			MethodCall call = new MethodCall(new MethodSelector(id), arguments);
			call.setVariableName(id.toString());
			return call;
		} else
			return null;
	}

	private IExpression resolveUnresolvedMemberMethod(Context context, Identifier id) {
		while(context!=null) {
			InstanceContext instance = context.getClosestInstanceContext();
			if(instance==null)
				return null;
			IDeclaration decl = resolveUnresolvedMember(instance, id);
			if(decl!=null)
				return new MethodCall(new MethodSelector(id), arguments);
			else
				context = instance.getParentContext();
		}
		return null;
	}

	private IDeclaration resolveUnresolvedMember(InstanceContext context, Identifier name) {
		ConcreteCategoryDeclaration decl = context.getRegisteredDeclaration(ConcreteCategoryDeclaration.class, context.getInstanceType().getTypeNameId());
		MethodDeclarationMap methods = decl.getMemberMethods(context, name, true);
		if(methods!=null && methods.size()>0)
			return methods;
		else
			return null;
	}

	private IExpression resolveMemberSelector(Context context, MemberSelector caller) {
		IExpression parent = caller.getParent();
		Identifier id = caller.getId();
		MethodSelector selector = new MethodSelector(parent, id);
		selector.setSectionFrom(caller);
		return new MethodCall(selector, arguments);
	}
	
	@Override
	public void declare(Transpiler transpiler) {
	    this.doResolve(transpiler.getContext());
	    if(this.resolved!=null)
	    	this.resolved.declare(transpiler);
	}
	
	@Override
	public boolean transpile(Transpiler transpiler) {
	    this.doResolve(transpiler.getContext());
	    if(this.resolved!=null)
	    	this.resolved.transpile(transpiler);
	    return false;
	}
	
	@Override
	public void transpileFound(Transpiler transpiler, Dialect dialect) {
		transpiler.append("''");
	}


}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy