package org.simantics.scl.compiler.constants.generic; import org.cojen.classfile.TypeDesc; import org.simantics.scl.compiler.common.exceptions.InternalCompilerError; import org.simantics.scl.compiler.internal.codegen.references.Val; import org.simantics.scl.compiler.internal.codegen.utils.ClassBuilder; import org.simantics.scl.compiler.internal.codegen.utils.MethodBuilder; import org.simantics.scl.compiler.top.SCLCompilerConfiguration; /** * This interface represents a method for accessing the members of Java classes. * This interface is implemented by * * It provides the method {@link #invoke(MethodBuilder, StackItem[], Val[])} for creating the Java byte code * for calling the method or manipulating the field value. * * Parameter and return value type can be accessed using {@link #getParameterTypes()} and {@link #getReturnType()}. */ public interface MethodRef { /** * Build code for invoking the referenced function using a given MethodBuilder. * @param mb a method builder * @param stackItems a set of StackItem objects into which the call parameters are pushed * @param parameters the method call parameters */ void invoke(MethodBuilder mb, StackItem[] stackItems, Val[] parameters); /** * Get the parameter types for a method. For (non-static) object methods and field accessors, the first * parameter represents the object itself, as passed in the {@code this} variable. */ public TypeDesc[] getParameterTypes(); /** * Get the return type of the method. */ public TypeDesc getReturnType(); /** * This class represents a static Java class method. */ public static class StaticMethodRef implements MethodRef { String className; String methodName; TypeDesc ret; TypeDesc[] params; public StaticMethodRef(String className, String methodName, TypeDesc ret, TypeDesc[] params) { this.className = className; this.methodName = methodName; this.ret = ret; this.params = params; } @Override public void invoke(MethodBuilder mb, StackItem[] stackItems, Val[] parameters) { if(SCLCompilerConfiguration.DEBUG) if(stackItems.length != params.length) throw new InternalCompilerError(); for(StackItem stackItem : stackItems) stackItem.push(mb, parameters); mb.invokeStatic(className, methodName, ret, params); } @Override public TypeDesc[] getParameterTypes() { return params; } @Override public TypeDesc getReturnType() { return ret; } @Override public String toString() { StringBuilder b = new StringBuilder(); b.append("public static "); b.append(ret.getFullName()); b.append(" "); b.append(methodName); b.append("("); boolean first = true; for(TypeDesc param : params) { if(first) first = false; else b.append(", "); b.append(param.getFullName()); } b.append(")"); return b.toString(); } @Override public String getName() { return className + "." + methodName; } } /** * This class represents a (non-static) java object method. */ public static class ObjectMethodRef implements MethodRef { boolean isInterface; String className; String methodName; TypeDesc ret; TypeDesc[] params; TypeDesc[] realParams; public ObjectMethodRef(boolean isInterface, String className, String methodName, TypeDesc ret, TypeDesc[] params) { this.isInterface = isInterface; ClassBuilder.checkClassName(className); this.className = className; this.methodName = methodName; this.ret = ret; this.params = params; this.realParams = new TypeDesc[params.length+1]; realParams[0] = TypeDesc.forClass(className); for(int i=0;i"; } } /** * This class represents a read access to a static Java field, represented as a zero-arity {@link MethodRef}. */ public static class StaticFieldRef implements MethodRef { String className; String fieldName; TypeDesc ret; public StaticFieldRef(String className, String fieldName, TypeDesc ret) { this.className = className; this.fieldName = fieldName; this.ret = ret; } @Override public void invoke(MethodBuilder mb, StackItem[] stackItems, Val[] parameters) { if(SCLCompilerConfiguration.DEBUG) if(stackItems.length != 0) throw new InternalCompilerError(); mb.loadStaticField(className, fieldName, ret); } @Override public TypeDesc[] getParameterTypes() { return ClassRef.NO_PARAMS; } @Override public TypeDesc getReturnType() { return ret; } @Override public String toString() { StringBuilder b = new StringBuilder(); b.append("public static "); b.append(ret.getFullName()); b.append(" "); b.append(fieldName); return b.toString(); } @Override public String getName() { return className + "." + fieldName; } } /** * This class represents read access to a Java (non-static) object field as a one-parameter {@link MethodRef}. */ public static class FieldRef implements MethodRef { String className; String fieldName; TypeDesc[] params; TypeDesc ret; public FieldRef(String className, String fieldName, TypeDesc ret) { this.className = className; this.fieldName = fieldName; this.ret = ret; this.params = new TypeDesc[] {TypeDesc.forClass(className)}; } @Override public void invoke(MethodBuilder mb, StackItem[] stackItems, Val[] parameters) { if(SCLCompilerConfiguration.DEBUG) if(stackItems.length != 1) throw new InternalCompilerError(); stackItems[0].push(mb, parameters); mb.loadField(className, fieldName, ret); } @Override public TypeDesc[] getParameterTypes() { return params; } @Override public TypeDesc getReturnType() { return ret; } @Override public String toString() { StringBuilder b = new StringBuilder(); b.append("public "); b.append(ret.getFullName()); b.append(" "); b.append(fieldName); return b.toString(); } @Override public String getName() { return className + "." + fieldName; } } /** * This class represents a method for setting a static Java field value as a one-parameter {@link MethodRef} */ public static class SetStaticFieldRef implements MethodRef { String className; String fieldName; TypeDesc ret; TypeDesc[] params; public SetStaticFieldRef(String className, String fieldName, TypeDesc ret) { this.className = className; this.fieldName = fieldName; this.ret = ret; this.params = new TypeDesc[] {ret}; } @Override public void invoke(MethodBuilder mb, StackItem[] stackItems, Val[] parameters) { if(SCLCompilerConfiguration.DEBUG) if(stackItems.length != 1) throw new InternalCompilerError(); stackItems[0].push(mb, parameters); mb.storeStaticField(className, fieldName, ret); } @Override public TypeDesc[] getParameterTypes() { return params; } @Override public TypeDesc getReturnType() { return TypeDesc.VOID; } @Override public String toString() { StringBuilder b = new StringBuilder(); b.append("public static "); b.append(ret.getFullName()); b.append(" "); b.append(fieldName); return b.toString(); } @Override public String getName() { return className + "." + fieldName; } } /** * This class represents a method for setting the value of a Java (non-static) object field as a two-parameter * {@link MethodRef}. The first parameter is the object reference and the second parameter is the field value. */ public static class SetFieldRef implements MethodRef { String className; String fieldName; TypeDesc ret; TypeDesc[] params; public SetFieldRef(String className, String fieldName, TypeDesc ret) { this.className = className; this.fieldName = fieldName; this.ret = ret; this.params = new TypeDesc[] {TypeDesc.forClass(className), ret}; } @Override public void invoke(MethodBuilder mb, StackItem[] stackItems, Val[] parameters) { if(SCLCompilerConfiguration.DEBUG) if(stackItems.length != 2) throw new InternalCompilerError(); stackItems[0].push(mb, parameters); stackItems[1].push(mb, parameters); mb.storeField(className, fieldName, ret); } @Override public TypeDesc[] getParameterTypes() { return params; } @Override public TypeDesc getReturnType() { return TypeDesc.VOID; } @Override public String toString() { StringBuilder b = new StringBuilder(); b.append("public "); b.append(ret.getFullName()); b.append(" "); b.append(fieldName); return b.toString(); } @Override public String getName() { return className + "." + fieldName; } } public abstract String getName(); }