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

prompto.declaration.NativeMethodDeclaration Maven / Gradle / Ivy

The newest version!
package prompto.declaration;

import prompto.compiler.ClassFile;
import prompto.compiler.CompilerException;
import prompto.compiler.Flags;
import prompto.compiler.MethodInfo;
import prompto.compiler.Opcode;
import prompto.compiler.ResultInfo;
import prompto.error.NullReferenceError;
import prompto.error.PromptoError;
import prompto.grammar.ArgumentList;
import prompto.grammar.Identifier;
import prompto.java.JavaNativeCall;
import prompto.param.ParameterList;
import prompto.runtime.Context;
import prompto.statement.IStatement;
import prompto.statement.NativeCall;
import prompto.statement.StatementList;
import prompto.type.IType;
import prompto.type.TypeMap;
import prompto.type.VoidType;
import prompto.utils.CodeWriter;
import prompto.value.IValue;

public class NativeMethodDeclaration extends ConcreteMethodDeclaration {

	JavaNativeCall statement;
	
	public NativeMethodDeclaration(Identifier name, ParameterList arguments, IType returnType, StatementList instructions) {
		super(name, arguments, returnType, instructions);
		statement = findCall(JavaNativeCall.class);
	}

	@SuppressWarnings("unchecked")
	public  T findCall(Class klass) {
		for(IStatement statement : statements) {
			if(klass.isAssignableFrom(statement.getClass()))
				return (T)statement;
		}
		return null;
	}

	@Override
	protected IType checkStatements(Context context) {
		if(statement!=null && context.getProblemListener().isCheckNative())
			return checkNative(context);
		else if(returnType!=null)
			return returnType;
		else
			return VoidType.instance();
	}
	
	private IType checkNative(Context context) {
		IType inferred;
		if(returnType==VoidType.instance())
			inferred = checkNativeVoid(context);
		else
			inferred = checkNativeType(context);
		return inferred.anyfy();
	}
	
	private IType checkNativeType(Context context) {
		TypeMap types = new TypeMap();
		if(returnType!=null)
			types.add(returnType);
		// TODO: ensure returnType is registered prior to the below 
		IType type = statement.checkNative(context, returnType);
		// TODO: remove the below workaround for unregistered native categories
		if(type==null)
			type = returnType;
		if(type!=VoidType.instance())
			types.add(type);
		type = types.inferType(context, statement);
		if(returnType!=null)
			return returnType;
		else
			return type;
	}

	private IType checkNativeVoid(Context context) {
		// don't check return type
		IType type = statement.checkNative(context, returnType);
		// TODO: remove the below workaround for unregistered native categories
		if(type==null)
			type = returnType;
		if(type!=VoidType.instance())
			context.getProblemListener().reportIllegalReturn(statement);
		return returnType;
	}

	@Override
	public IValue interpret(Context context) throws PromptoError {
		try {
			return doInterpretNative(context);
		} catch(NullPointerException e) {
			e.printStackTrace();
			throw new NullReferenceError();
		}
	}
	
	private IValue doInterpretNative(Context context) throws PromptoError {
		context.enterStatement(statement);
		try {
			IValue result = statement.interpretNative(context, returnType);
			if(result!=null)
				return result;
		} finally {
			context.leaveStatement(statement);
		}
		return null;
	}
	
	@Override
	public void compile(Context context, boolean isStart, ClassFile classFile) {
		compileGlobal(context, classFile);
	}
	
	
	public void compileGlobal(Context context, ClassFile classFile) {
		try {
			context = context.newLocalContext();
			registerParameters(context);
			IType returnType = this.checkNative(context);
			MethodInfo method = createMethodInfo(context, classFile, returnType, getName());
			registerLocals(context, classFile, method);
			if(statement!=null)
				statement.compile(context, method, new Flags());
			// ensure we always return
			if(returnType==VoidType.instance())
				method.addInstruction(Opcode.RETURN);
		} catch (PromptoError e) {
			throw new CompilerException(e);
		}
	}

	
	public ResultInfo compileMember(Context context, MethodInfo method, Flags flags, ArgumentList assignments) {
		try {
			// push arguments on the stack
			compileParameters(context, method, flags, assignments);
			return statement.compile(context, method, new Flags().withMember(true).withInline(true));
		} catch (PromptoError e) {
			throw new CompilerException(e);
		}
	}

	
	@Override
	protected void toMDialect(CodeWriter writer) {
		writer.append("def ");
		if(memberOf==null)
			writer.append("native ");
		writer.append(getName());
		writer.append(" (");
		parameters.toDialect(writer);
		writer.append(")");
		if(returnType!=null && returnType!=VoidType.instance()) {
			writer.append("->");
			returnType.toDialect(writer);
		}
		writer.append(":\n");
		writer.indent();
		statements.toDialect(writer);
		writer.dedent();
	}

	@Override
	protected void toODialect(CodeWriter writer) {
		if(returnType!=null  && returnType!=VoidType.instance()) {
			returnType.toDialect(writer);
			writer.append(" ");
		}
		if(memberOf==null)
			writer.append("native ");
		writer.append("method ");
		writer.append(getName());
		writer.append(" (");
		parameters.toDialect(writer);
		writer.append(") {\n");
		writer.indent();
		for(IStatement statement : statements) {
			statement.toDialect(writer);
			writer.newLine();
		}
		writer.dedent();
		writer.append("}\n");
	}
	
	@Override
	protected void toEDialect(CodeWriter writer) {
		writer.append("define ");
		writer.append(getName());
		writer.append(" as ");
		if(memberOf==null)
			writer.append("native ");
		writer.append("method ");
		parameters.toDialect(writer);
		if(returnType!=null && returnType!=VoidType.instance()) {
			writer.append("returning ");
			returnType.toDialect(writer);
			writer.append(" ");
		}
		writer.append("doing:\n");
		writer.indent();
		statements.toDialect(writer);
		writer.dedent();
		writer.append("\n");
	}

	
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy