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

prompto.expression.InstanceExpression Maven / Gradle / Ivy

The newest version!
package prompto.expression;

import prompto.compiler.ClassConstant;
import prompto.compiler.CompilerUtils;
import prompto.compiler.Flags;
import prompto.compiler.MethodInfo;
import prompto.compiler.Opcode;
import prompto.compiler.ResultInfo;
import prompto.compiler.StackLocal;
import prompto.declaration.AttributeDeclaration;
import prompto.declaration.CategoryDeclaration;
import prompto.declaration.ConcreteMethodDeclaration;
import prompto.declaration.IDeclaration;
import prompto.declaration.IMethodDeclaration;
import prompto.declaration.SingletonCategoryDeclaration;
import prompto.error.PromptoError;
import prompto.error.SyntaxError;
import prompto.grammar.EqOp;
import prompto.grammar.INamed;
import prompto.grammar.Identifier;
import prompto.literal.BooleanLiteral;
import prompto.param.IParameter;
import prompto.parser.CodeSection;
import prompto.parser.Dialect;
import prompto.parser.ICodeSection;
import prompto.runtime.Context;
import prompto.runtime.Context.ClosureContext;
import prompto.runtime.Context.InstanceContext;
import prompto.runtime.Context.MethodDeclarationMap;
import prompto.runtime.LinkedVariable;
import prompto.runtime.Variable;
import prompto.store.AttributeInfo;
import prompto.store.IQueryBuilder;
import prompto.store.IStore;
import prompto.transpiler.Transpiler;
import prompto.type.BooleanType;
import prompto.type.CategoryType;
import prompto.type.IType;
import prompto.type.MethodType;
import prompto.type.NullType;
import prompto.type.VoidType;
import prompto.utils.CodeWriter;
import prompto.utils.StoreUtils;
import prompto.value.ClosureValue;
import prompto.value.IValue;

public class InstanceExpression extends CodeSection implements IPredicate {

	Identifier id;
	
	public InstanceExpression(Identifier id) {
		this.id = id;
	}

	public Identifier getId() {
		return id;
	}
	
	public String getName() {
		return id.toString();
	}
	
	@Override
	public String toString() {
		return id.toString();
	}
	
	@Override
	public void toDialect(CodeWriter writer) {
		toDialect(writer, true);
	}
	
	public void toDialect(CodeWriter writer, boolean requireMethod) {
		if(requireMethod && requiresMethod(writer))
			writer.append("Method: ");
		writer.append(id);
	}
	
	private boolean requiresMethod(CodeWriter writer) {
		if(writer.getDialect()!=Dialect.E)
			return false;
		Object o = writer.getContext().getRegistered(id);
		if(o instanceof MethodDeclarationMap)
			return true;
		return false;
	}

	@Override
	public AttributeDeclaration checkAttribute(Context context, ICodeSection section) {
		AttributeDeclaration decl = context.findAttribute(id.toString());
		if(decl==null)
			context.getProblemListener().reportMissingAttribute(this, this.toString());
		return decl;
	}
	
	@Override
	public AttributeInfo checkAttributeInfo(Context context, ICodeSection section, IStore store) {
		return StoreUtils.getAttributeInfo(context, id.toString(), store);
	}
	
	
	@Override
	public IType check(Context context) {
		INamed named = context.getRegistered(id);
		if(named==null) 
			named = context.getRegisteredDeclaration(IDeclaration.class, id, true);
		if(named instanceof Variable // local variable
				|| named instanceof LinkedVariable // local variable with downcast
				|| named instanceof IParameter // named argument
				|| named instanceof CategoryDeclaration // any p with x
				|| named instanceof AttributeDeclaration) // in category method
			return named.getType(context);
		else if(named instanceof MethodDeclarationMap) { // global method or closure
			IMethodDeclaration decl = ((MethodDeclarationMap)named).values().iterator().next();
			return new MethodType(decl);
		} else if(named != null) {
			context.getProblemListener().reportIllegalValue(id, id.toString());
			return VoidType.instance();
		} else {
			context.getProblemListener().reportUnknownIdentifier(id, id.toString());
			return NullType.instance();
		}
	}
	
	@Override
	public IValue interpret(Context context) throws PromptoError {
		if(context.hasValue(id))
			return context.getValue(id);
		else {
			INamed named = context.getRegistered(id);
			if(named instanceof Context.MethodDeclarationMap) {
				ConcreteMethodDeclaration decl = (ConcreteMethodDeclaration)((MethodDeclarationMap)named).values().iterator().next();
				MethodType type = new MethodType(decl);
				return new ClosureValue(context, type);
			} else
				throw new SyntaxError("No value or method with name:" + id);
		}
	}
	
	@Override
	public ResultInfo compile(Context context, MethodInfo method, Flags flags) {
		ResultInfo info = compileLocal(context, method, flags);
		if(info!=null)
			return info;
		else
			info = compileRegistered(context, method, flags);
		if(info!=null)
			return info;
		else
			info = compileInstanceField(context, method, flags);
		if(info!=null)
			return info;
		else
			throw new SyntaxError("Unknown identifier: " + getName());
	}

	private ResultInfo compileRegistered(Context context, MethodInfo method, Flags flags) {
		INamed named = context.getRegistered(getId());
		if(named instanceof Context.MethodDeclarationMap) {
			ConcreteMethodDeclaration decl = (ConcreteMethodDeclaration)((MethodDeclarationMap)named).values().iterator().next();
			return decl.compileMethodInstance(context, method, flags);
		} else
			return null;
	}

	private ResultInfo compileInstanceField(Context context, MethodInfo method, Flags flags) {
		// deal with singleton fields
		Context actual = context.contextForValue(id);
		if(actual instanceof InstanceContext) {
			IType type = ((InstanceContext)actual).getInstanceType();
			if(type instanceof CategoryType) { // could be a closure
				IDeclaration decl = ((CategoryType)type).getDeclaration(context);
				if(decl instanceof SingletonCategoryDeclaration)
					return type.compileGetStaticMember(context, method, flags, id);
			}
		}
		StackLocal local = method.getRegisteredLocal("this");
		if(local==null)
			return null;
		IExpression parent = new ThisExpression();
		if(context instanceof ClosureContext) {
			Context owner = context.contextForValue(id);
			if(owner instanceof InstanceContext)
				parent = new MemberSelector(parent, new Identifier("this$0"));
		}
		MemberSelector selector = new MemberSelector(parent, id);
		return selector.compile(context, method, flags);
	}
	
	private ResultInfo compileLocal(Context context, MethodInfo method, Flags flags) {
		StackLocal local = method.getRegisteredLocal(getName());
		if(local==null)
			return null;
		ClassConstant downcastTo = null;
		if(local instanceof StackLocal.ObjectLocal)
			downcastTo = ((StackLocal.ObjectLocal)local).getDowncastTo();
		ResultInfo info = CompilerUtils.compileALOAD(method, local);
		if(downcastTo==null)
			return info;
		else {
			method.addInstruction(Opcode.CHECKCAST, downcastTo);
			return new ResultInfo(downcastTo.getType());
		}
	}
	
	@Override
	public void declare(Transpiler transpiler) {
		INamed named = transpiler.getContext().getRegistered(id);
		if(named instanceof MethodDeclarationMap) {
			IMethodDeclaration decl = ((MethodDeclarationMap)named).getFirst();
			// don't declare member methods
			if(decl.getMemberOf()!=null)
				return;
			// don't declare closures
			if(decl instanceof ConcreteMethodDeclaration && ((ConcreteMethodDeclaration)decl).getDeclarationOf()!=null)
				return;
			decl.declare(transpiler);
		}
	}
	

	@Override
	public boolean transpile(Transpiler transpiler) {
		Context context = transpiler.getContext().contextForValue(this.id);
	    if(context instanceof InstanceContext) {
	        ((InstanceContext)context).getInstanceType().transpileInstance(transpiler);
	        transpiler.append(".");
	    }
		INamed named = transpiler.getContext().getRegistered(id);
		if(named instanceof MethodDeclarationMap) {
			transpiler.append(((MethodDeclarationMap)named).getFirst().getTranspiledName(context));
			// need to bind instance methods
			if(context instanceof InstanceContext) {
		        transpiler.append(".bind(");
		        ((InstanceContext)context).getInstanceType().transpileInstance(transpiler);
		        transpiler.append(")");
		    }
		} else {
		    if(this.getName().equals(transpiler.getGetterName()))
		        transpiler.append("$");
		    transpiler.append(this.getName());
		}
		return false;
	}
	
	private EqualsExpression toPredicate(Context context) {
	    AttributeDeclaration decl = context.findAttribute(id.toString());
		if(decl==null) {
			context.getProblemListener().reportUnknownIdentifier(id, id.toString());
			return null;
		} else if(!(decl instanceof AttributeDeclaration) || ((AttributeDeclaration)decl).getType()!=BooleanType.instance()) {
			context.getProblemListener().reportIllegalValue(id, "Expected a Boolean, got " + decl.getType().getTypeName());
			return null;
		} else
			return new EqualsExpression(this, EqOp.EQUALS, new BooleanLiteral("true"));
	}


	@Override
	public void checkQuery(Context context) throws PromptoError {
		IPredicate predicate = toPredicate(context);
		if(predicate!=null)
			predicate.checkQuery(context);
	}
	
	
	@Override
	public void interpretQuery(Context context, IQueryBuilder query, IStore store) throws PromptoError {
		IPredicate predicate = toPredicate(context);
		if(predicate!=null)
			predicate.interpretQuery(context, query, store);
	}
	
	@Override
	public void compileQuery(Context context, MethodInfo method, Flags flags) {
		IPredicate predicate = toPredicate(context);
		if(predicate!=null)
			predicate.compileQuery(context, method, flags);
	}
	

	@Override
	public void declareQuery(Transpiler transpiler) {
		IPredicate predicate = toPredicate(transpiler.getContext());
		if(predicate!=null)
			predicate.declareQuery(transpiler);
	}
	
	@Override
	public void transpileQuery(Transpiler transpiler, String builderName) {
		IPredicate predicate = toPredicate(transpiler.getContext());
		if(predicate!=null)
			predicate.transpileQuery(transpiler, builderName);
	}

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy