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

prompto.java.JavaIdentifierExpression Maven / Gradle / Ivy

The newest version!
package prompto.java;

import java.lang.reflect.Field;
import java.lang.reflect.Type;
import java.net.URL;
import java.net.URLClassLoader;

import prompto.compiler.ClassConstant;
import prompto.compiler.CompilerUtils;
import prompto.compiler.FieldConstant;
import prompto.compiler.IOperand;
import prompto.compiler.MethodInfo;
import prompto.compiler.Opcode;
import prompto.compiler.ResultInfo;
import prompto.compiler.ResultInfo.Flag;
import prompto.compiler.StackLocal;
import prompto.error.PromptoError;
import prompto.error.SyntaxError;
import prompto.grammar.INamed;
import prompto.grammar.Identifier;
import prompto.parser.CodeSection;
import prompto.runtime.Context;
import prompto.type.IType;
import prompto.utils.CodeWriter;


public class JavaIdentifierExpression extends CodeSection implements JavaExpression {

	
	public static JavaIdentifierExpression parse(String ids) {
		String[] parts = ids.split("\\.");
		JavaIdentifierExpression result = null;
		for(String part : parts)
			result = new JavaIdentifierExpression(result,part);
		return result;
	}
	
	JavaIdentifierExpression parent = null;
	String name;
	boolean isChildClass = false;
	
	public JavaIdentifierExpression(String name) {
		this.name = name;
	}

	public JavaIdentifierExpression(JavaIdentifierExpression parent, String name) {
		this.parent = parent;
		this.name = name;
	}
	
	public JavaIdentifierExpression(JavaIdentifierExpression parent, String name, boolean isChildClass) {
		this.parent = parent;
		this.name = name;
		this.isChildClass = isChildClass;
	}

	public JavaIdentifierExpression getParent() {
		return parent;
	}
	
	public String getName() {
		return name;
	}
	
	@Override
	public void toDialect(CodeWriter writer) {
		if(parent!=null) {
			parent.toDialect(writer);
			writer.append(isChildClass ? '$' : '.');
		}
		writer.append(name);
	}
	
	@Override
	public String toString() {
		if(parent==null)
			return name;
		else 
			return parent.toString() + (isChildClass ? '$' : '.') + name;
	}
	
	@Override
	public ResultInfo compile(Context context, MethodInfo method) {
		if(parent==null)
			return compile_root(context, method);
		else
			return compile_child(context, method);
	}
	
	private ResultInfo compile_root(Context context, MethodInfo method) {
		ResultInfo info = compile_prompto(context, method);
		if(info!=null)
			return info;
		else
			info = compile_instance(context, method);
		if(info!=null)
			return info;
		else
			return compile_class(context, method);
	}

	private ResultInfo compile_prompto(Context context, MethodInfo method) {
		JavaIdentifierProcessor processor = JavaIdentifierProcessor.processors.get(name);
		if(processor==null)
			return null;
		else
			return processor.compile(context, method);
	}

	private ResultInfo compile_instance(Context context, MethodInfo method) {
		if("null".equals(name)) {
			method.addInstruction(Opcode.ACONST_NULL);
			return new ResultInfo(Object.class);
		}
		INamed named = context.getRegisteredValue(INamed.class, new Identifier(name));
		if(named==null)
			return null;
		StackLocal local = method.getRegisteredLocal(name);
		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()); 
		}
	}

	private ResultInfo compile_child(Context context, MethodInfo method) {
		ResultInfo info = parent.compile(context, method);
		if(info!=null)
			return compile_field(context, method, info);
		else
			return compile_class(context, method);
	}

	private ResultInfo compile_field(Context context, MethodInfo method, ResultInfo info) {
		try {
			Class klass = (Class)info.getType();
			Field field = klass.getField(name);
			IOperand oper = new FieldConstant(info.getType(), name, field.getType());
			if(info.isStatic())
				method.addInstruction(Opcode.GETSTATIC, oper);
			else
				method.addInstruction(Opcode.GETFIELD, oper);
			return new ResultInfo(field.getType());
		} catch (NoSuchFieldException e) { 
			return null;
		}
	}

	private ResultInfo compile_class(Context context, MethodInfo method) {
		String fullName = this.toString();
		try {
			Class klass = addOnsClassLoader==null ? Class.forName(fullName) : addOnsClassLoader.loadClass(fullName);
			return new ResultInfo(klass, Flag.STATIC);
		} catch (ClassNotFoundException e1) {
			// package prefix not required for classes in java.lang package
			if(parent==null) try {
				fullName = "java.lang." + name;
				return new ResultInfo(Class.forName(fullName), Flag.STATIC);
			} catch (ClassNotFoundException e2) {
			}	
		}
		return null;
	}

	@Override
	public Object interpret(Context context) throws PromptoError {
		if(parent==null)
			return interpret_root(context);
		else
			return interpret_child(context);
	}
	
	Object interpret_root(Context context) throws PromptoError {
		Object o = interpret_prompto(context);
		if(o!=null)
			return o;
		o = interpret_instance(context);
		if(o!=null)
			return o;
		else
			return interpret_class(); // as an instance for static field/method
	}

	private Object interpret_prompto(Context context) {
		JavaIdentifierProcessor processor = JavaIdentifierProcessor.processors.get(name);
		if(processor==null)
			return null;
		else
			return processor.interpret(context);
	}

	Object interpret_instance(Context context) throws PromptoError {
		if("null".equals(name))
			return null;
		else try {
			return context.getValue(new Identifier(name)); 
		} catch (PromptoError e) {
			return null;
		}
	}

	public Class interpret_class() {
		String fullName = this.toString();
		try {
			return addOnsClassLoader==null ? Class.forName(fullName) : addOnsClassLoader.loadClass(fullName);
		} catch (ClassNotFoundException e1) {
			// package prefix not required for classes in java.lang package
			if(parent==null) try {
				fullName = "java.lang." + name;
				return Class.forName(fullName);
			} catch (ClassNotFoundException e2) {
			}	
		}
		return null;
	}

	Object interpret_child(Context context) throws PromptoError {
		Object o = parent.interpret(context); 
		if(o!=null)
			return interpret_field(o);
		else
			return interpret_class();
	}
	
	Object interpret_field(Object o) {
		Class klass = null;
		if(o instanceof Class) {
			klass = (Class)o;
			o = null;
		} else
			klass = o.getClass();
		try {
			Field field = klass.getField(name);
			return field.get(o);
		} catch (IllegalAccessException | IllegalArgumentException | NoSuchFieldException e) { 
			return null;
		}
	}

	@Override
	public IType check(Context context) {
		if(parent==null)
			return check_root(context);
		else
			return check_child(context);
	}
	
	IType check_root(Context context) {
		IType t = check_prompto(context);
		if(t!=null)
			return t;
		t = check_instance(context);
		if(t!=null)
			return t;
		else
			return check_class(); // as an instance for accessing static field/method
	}

	private IType check_prompto(Context context) {
		JavaIdentifierProcessor processor = JavaIdentifierProcessor.processors.get(name);
		if(processor==null)
			return null;
		else
			return processor.check(context);
	}

	IType check_instance(Context context) {
		INamed named = context.getRegisteredValue(INamed.class, new Identifier(name)); 
		if(named==null)
			return null;
		try {
			return named.getType(context);
		} catch (SyntaxError e) {
			return null;
		}
	}

	private static ClassLoader addOnsClassLoader; 

	public static void registerAddOns(URL[] addOnURLs, ClassLoader parent) {
		if(addOnURLs!=null && addOnURLs.length>0)
			addOnsClassLoader = new URLClassLoader(addOnURLs, parent);
	}

	IType check_class() {
		String fullName = this.toString();
		try {
			Class klass = addOnsClassLoader==null ? Class.forName(fullName) : addOnsClassLoader.loadClass(fullName);
			return new JavaClassType(klass);
		} catch (ClassNotFoundException e1) {
			// package prefix not required for classes in java.lang package
			if(parent==null) try {
				fullName = "java.lang." + name;
				Class klass = Class.forName(fullName);
				return new JavaClassType(klass);
			} catch (ClassNotFoundException e2) {
			}	
		}
		return null;
	}
	
	IType check_child(Context context) {
		IType t = parent.check(context); 
		if(t!=null)
			return check_field(context, t);
		else
			return check_class();
	}
	
	IType check_field(Context context, IType t) {
		if(!(t instanceof JavaClassType))
			return null;
		Type klass = t.toJavaType(context);
		if(klass instanceof Class) try {
			Field field = ((Class)klass).getField(name);
			return new JavaClassType(field.getType());
		} catch (NoSuchFieldException e) { 
			return null;
		} else {
			throw new UnsupportedOperationException();
		}
	}


}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy