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

prompto.grammar.Argument Maven / Gradle / Ivy

The newest version!
package prompto.grammar;

import java.util.List;
import java.util.Objects;
import java.util.Set;

import prompto.declaration.IMethodDeclaration;
import prompto.error.PromptoError;
import prompto.error.SyntaxError;
import prompto.expression.ArrowExpression;
import prompto.expression.ConstructorExpression;
import prompto.expression.IExpression;
import prompto.expression.InstanceExpression;
import prompto.expression.MemberSelector;
import prompto.param.IParameter;
import prompto.param.ParameterList;
import prompto.parser.CodeSection;
import prompto.runtime.Context;
import prompto.statement.UnresolvedCall;
import prompto.transpiler.ITranspilable;
import prompto.transpiler.Transpiler;
import prompto.type.CategoryType;
import prompto.type.IType;
import prompto.type.MethodType;
import prompto.type.VoidType;
import prompto.utils.CodeWriter;
import prompto.value.ContextualExpression;
import prompto.value.IInstance;

public class Argument extends CodeSection {
	
	IParameter parameter;
	IExpression expression;
	
	public Argument(IParameter parameter, IExpression expression) {
		this.parameter = parameter;
		this.expression = expression;
	}
	
	
	public void setParameter(IParameter parameter) {
		this.parameter = parameter;
	}
	
	
	public IParameter getParameter() {
		return parameter;
	}

	public Identifier getParameterId() {
		return parameter==null ? null : parameter.getId();
	} 
	
	public IExpression getExpression() {
		return expression!=null ? expression : new InstanceExpression(parameter.getId());
	}

	public void setExpression(IExpression expression) {
		this.expression = expression;
	}
	
	@Override
	public String toString() {
		if(parameter==null)
			return expression.toString();
		else if(expression==null)
			return parameter.getId().toString();
		else
			return parameter.getId() + " = " + expression.toString();
	}
	
	public void toDialect(CodeWriter writer) {
		switch(writer.getDialect()) {
		case E:
			toEDialect(writer);
			break;
		case O:
			toODialect(writer);
			break;
		case M:
			toMDialect(writer);
			break;
		}
	}
	
	private void toODialect(CodeWriter writer) {
		toMDialect(writer);
	}

	private void toMDialect(CodeWriter writer) {
		if(expression==null)
			writer.append(parameter.getId());
		else {
			if(parameter!=null) {
				writer.append(parameter.getId());
				writer.append(" = ");
			}
			expression.toDialect(writer);
		}
	}

	private void toEDialect(CodeWriter writer) {
		if(expression==null)
			writer.append(parameter.getId());
		else {
			expression.toDialect(writer);
			if(parameter!=null) {
				writer.append(" as ");
				writer.append(parameter.getId());
			}
		}
	}

	@Override
	public int hashCode() {
		return Objects.hash(expression, parameter);
	}


	@Override
	public boolean equals(Object obj) {
		return obj==this || (obj instanceof Argument && equals((Argument)obj));
	}
	
	
	public boolean equals(Argument other) {
		return this.getParameter().equals(other.getParameter())
				&& this.getExpression().equals(other.getExpression());
	}
	
	
	public void check(Context context) {
		if(expression==null)
			checkParameterOnly(context);
		else
			checkParameterAndExpression(context);
	}
	
	
	private void checkParameterOnly(Context context) {
		INamed registered = context.getRegisteredValue(INamed.class, parameter.getId());
		if(registered == null)
			context.getProblemListener().reportUnknownIdentifier(this, parameter.getId().toString());
		else {
			IType requiredType = this.parameter.check(context);
			IType actualType = registered.getType(context);
			requiredType.checkAssignableFrom(context, actualType, this);
		}
	}


	private void checkParameterAndExpression(Context context) {
		IType requiredType = this.parameter.check(context);
		IType actualType = getExpression().check(context);
		requiredType.checkAssignableFrom(context, actualType, this);
	}
	
	public IExpression resolve(Context context, IMethodDeclaration methodDeclaration, boolean checkInstance, boolean allowDerived) throws PromptoError {
		IParameter parameter = findParameter(methodDeclaration);
		return resolve(context, parameter, checkInstance, allowDerived);
	}
	
	public IExpression resolve(Context context, IParameter parameter, boolean checkInstance, boolean allowDerived) throws PromptoError {
		// since we support implicit members, it's time to resolve them
		IType requiredType = parameter.getType(context);
		IType actualType = checkActualType(context, requiredType, checkInstance);
		boolean assignable = requiredType.isAssignableFrom(context, actualType);
		// when in dispatch, allow derived
		if(!assignable && allowDerived)
	        assignable = actualType.isAssignableFrom(context, requiredType);
		// try passing category member
		if(!assignable && (actualType instanceof CategoryType)) 
			expression = new MemberSelector(expression, parameter.getId());
		return expression; 
	}

	public IType checkActualType(Context context, IType requiredType, boolean checkInstance) {
		IType actualType = null;
		IExpression expression = getExpression();
		boolean isArrow = isArrowExpression(expression);
		if(isArrow) {
			if(requiredType instanceof MethodType)
				actualType = checkArrowExpression(context, (MethodType)requiredType, expression);
			else
				actualType = VoidType.instance();
		} else if(requiredType instanceof MethodType)
			actualType = expression.checkReference(context.getCallingContext());
		else
			actualType = expression.check(context.getCallingContext());
		if(checkInstance && actualType instanceof CategoryType) {
			Object value = expression.interpret(context.getCallingContext());
			if(value instanceof IInstance)
				actualType = ((IInstance)value).getType();
		}
		return actualType;
	}


	private static IType checkArrowExpression(Context context, MethodType requiredType, IExpression expression) {
		context = expression instanceof ContextualExpression ? ((ContextualExpression)expression).getCalling() : context.getCallingContext();
		ArrowExpression arrow = (ArrowExpression)(expression instanceof ArrowExpression ? expression : ((ContextualExpression)expression).getExpression());
		return requiredType.checkArrowExpression(context, arrow);
	}


	private static boolean isArrowExpression(IExpression expression) {
		if(expression instanceof ContextualExpression)
			expression = ((ContextualExpression)expression).getExpression();
		return expression instanceof ArrowExpression;
	}


	private IParameter findParameter(IMethodDeclaration methodDeclaration) {
		return methodDeclaration.getParameters().find(this.parameter.getId());
	}


	public Argument resolveAndCheck(Context context, ParameterList argumentList) {
		IParameter parameter = this.parameter;
		// when 1st argument, can be unnamed
		if(parameter==null) {
			if(argumentList.size()==0)
				throw new SyntaxError("Method has no parameter");
			parameter = argumentList.get(0);
		} else
			parameter = argumentList.find(this.getParameterId());
		if(parameter==null)
			throw new SyntaxError("Method has no parameter:" + this.getParameterId());
		IExpression expression = new ContextualExpression(context, getExpression());
		return new Argument(parameter,expression);
	}


	public void declare(Transpiler transpiler, IMethodDeclaration methodDeclaration) {
		if(this.expression!=null && !this.declareArrowExpression(transpiler, methodDeclaration))
			this.expression.declare(transpiler);
	}

	public void ensureDeclarationOrder(Context context, List list, Set set) {
		IExpression expression = this.expression;
		if(expression instanceof UnresolvedCall)
			expression = ((UnresolvedCall)expression).resolve(context);
		if(expression instanceof ConstructorExpression)
			((ConstructorExpression)expression).ensureDeclarationOrder(context, list, set);
		// TODO else if(expression instanceof MethodCall)
	}

	private boolean declareArrowExpression(Transpiler transpiler, IMethodDeclaration methodDeclaration) {
		if(this.parameter==null || methodDeclaration==null)
			return false;
		IParameter parameter = findParameter(methodDeclaration);
		IType requiredType = parameter.getType(transpiler.getContext());
		boolean isArrow = requiredType instanceof MethodType && expression instanceof ArrowExpression;
		if(isArrow) {
			((MethodType)requiredType).declareArrowExpression(transpiler, (ArrowExpression)expression);
			return true;
		} else
			return false;
	}


	public void transpile(Transpiler transpiler, IMethodDeclaration methodDeclaration) {
		if(this.expression!=null && !this.transpileArrowExpression(transpiler, methodDeclaration))
			this.expression.transpile(transpiler);
	}


	private boolean transpileArrowExpression(Transpiler transpiler, IMethodDeclaration methodDeclaration) {
		// TODO Auto-generated method stub
		return false;
	}


}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy