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
* - {@link StaticMethodRef}
* - {@link ObjectMethodRef}
* - {@link ConstructorRef}
* - {@link StaticFieldRef}
* - {@link FieldRef}
* - {@link SetStaticFieldRef}
* - {@link SetFieldRef}
*
*
* 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();
}