package org.simantics.scl.compiler.common.datatypes;
import org.simantics.scl.compiler.common.names.Name;
+import org.simantics.scl.compiler.constants.componentaccess.ComponentAccess;
import org.simantics.scl.compiler.elaboration.modules.TypeConstructor;
import org.simantics.scl.compiler.internal.codegen.utils.ClassBuilder;
import org.simantics.scl.compiler.types.TVar;
public final TVar[] typeVariables;
public final Type type;
- public String[] fieldNames;
+ public ComponentAccess[] componentAccesses;
public String[] recordFieldNames;
import org.simantics.scl.compiler.constants.JavaTypeInstanceConstructor;
import org.simantics.scl.compiler.constants.SCLConstructor;
import org.simantics.scl.compiler.constants.StringConstant;
+import org.simantics.scl.compiler.constants.componentaccess.ComponentAccess;
+import org.simantics.scl.compiler.constants.componentaccess.FieldComponentAccess;
import org.simantics.scl.compiler.constants.generic.CallJava;
import org.simantics.scl.compiler.constants.generic.ClassRef;
import org.simantics.scl.compiler.constants.generic.ConvertToListFilter;
import org.simantics.scl.compiler.constants.generic.MethodRef;
-import org.simantics.scl.compiler.constants.generic.MethodRef.FieldRef;
import org.simantics.scl.compiler.constants.generic.OutputFilter;
import org.simantics.scl.compiler.constants.generic.ParameterStackItem;
import org.simantics.scl.compiler.constants.generic.Pop2OutputFilter;
import org.simantics.scl.compiler.internal.elaboration.profiling.BranchPointInjector;
import org.simantics.scl.compiler.internal.elaboration.utils.StronglyConnectedComponents;
import org.simantics.scl.compiler.internal.header.ModuleHeader;
-import org.simantics.scl.compiler.internal.parsing.Token;
import org.simantics.scl.compiler.internal.parsing.declarations.ConstructorAst;
import org.simantics.scl.compiler.internal.parsing.declarations.DAnnotationAst;
import org.simantics.scl.compiler.internal.parsing.declarations.DClassAst;
import org.simantics.scl.compiler.internal.parsing.declarations.DValueAst;
import org.simantics.scl.compiler.internal.parsing.declarations.DValueTypeAst;
import org.simantics.scl.compiler.internal.parsing.exceptions.SCLSyntaxErrorException;
-import org.simantics.scl.compiler.internal.parsing.parser.SCLTerminals;
import org.simantics.scl.compiler.internal.parsing.translation.ProcessedDClassAst;
import org.simantics.scl.compiler.internal.parsing.translation.ProcessedDInstanceAst;
import org.simantics.scl.compiler.internal.parsing.translation.RelationRepository;
import org.simantics.scl.compiler.module.debug.ModuleDebugInfo;
import org.simantics.scl.compiler.module.repository.ImportFailure;
import org.simantics.scl.compiler.module.repository.ImportFailureException;
-import org.simantics.scl.compiler.top.SCLCompilerConfiguration;
import org.simantics.scl.compiler.types.TCon;
import org.simantics.scl.compiler.types.TForAll;
import org.simantics.scl.compiler.types.TFun;
parameterTypes[i] = context.toType(constructor.parameters[i]);
String javaName = constructors.length == 1 ? className
: compilationContext.namingPolicy.getConstructorClassName(name);
- String[] fieldNames = null;
+ ComponentAccess[] componentAccesses = null;
for(DAnnotationAst annotation : constructor.annotations)
if(annotation.id.text.equals("@JavaType")) {
try {
else if(annotation.id.text.equals("@FieldNames")) {
try {
EListLiteral literal = (EListLiteral)annotation.parameters[0];
- fieldNames = new String[literal.getComponents().length];
- for(int i=0;i<fieldNames.length;++i) {
+ componentAccesses = new ComponentAccess[literal.getComponents().length];
+ for(int i=0;i<componentAccesses.length;++i) {
Expression component = literal.getComponents()[i];
if(component instanceof EVar)
- fieldNames[i] = ((EVar)component).name;
+ componentAccesses[i] = new FieldComponentAccess(((EVar)component).name);
else if(component instanceof ELiteral)
- fieldNames[i] = ((StringConstant)((ELiteral)component).getValue()).getValue();
+ componentAccesses[i] = new FieldComponentAccess(((StringConstant)((ELiteral)component).getValue()).getValue());
}
} catch(Exception e) {
errorLog.log(annotation.parameters[0].location, "Invalid annotation parameter.");
- fieldNames = null;
+ componentAccesses = null;
}
}
constructors[j] = new Constructor(constructor.location, dataType,
Name.create(moduleName, name),
parameterTypes, javaName);
- constructors[j].fieldNames = fieldNames;
+ constructors[j].componentAccesses = componentAccesses;
constructors[j].recordFieldNames = constructor.fieldNames;
}
if(constructors.length == 1) {
@Override
public void run() {
Type in = Types.apply(dataType.name, dataType.parameters);
+
+ ComponentAccess[] componentAccesses = constructor.componentAccesses != null
+ ? constructor.componentAccesses
+ : SCLConstructor.DEFAULT_FIELD_NAMES[constructor.recordFieldNames.length];
for(int i=0;i<constructor.recordFieldNames.length;++i) {
Type out = constructor.parameterTypes[i];
Constant accessor;
if(trivialDataType)
accessor = new SafeCoerce(dataType.parameters, in, out);
- else
+ else
accessor = new CallJava(dataType.parameters, Types.NO_EFFECTS, out,
new Type[] {in}, new StackItem[] {new ParameterStackItem(0, in)},
- new FieldRef(constructor.javaName, constructor.fieldNames != null ? constructor.fieldNames[i] : "c" + i,
- javaTypeTranslator.toTypeDesc(out)),
+ componentAccesses[i].toMethodRef(constructor.javaName, javaTypeTranslator.toTypeDesc(out)),
null);
module.addFieldAccessor(constructor.recordFieldNames[i], accessor);
}
int constructorTag = 0;
for(Constructor constructor : dataType.constructors) {
SCLValue value = new SCLValue(constructor.name);
+ value.parameterNames = constructor.recordFieldNames;
value.definitionLocation = constructor.loc;
SCLConstructor sclConstructor =
new SCLConstructor(
constructor.getTypeVariables(),
constructorTag++,
constructor.getReturnType(),
- constructor.fieldNames == null
+ constructor.componentAccesses == null
? SCLConstructor.DEFAULT_FIELD_NAMES[constructor.getParameterTypes().length]
- : constructor.fieldNames,
- constructor.recordFieldNames,
+ : constructor.componentAccesses,
constructor.getParameterTypes());
if(dataType.constructors.length == 1 && (
dataType.getTypeDesc() == null ||
import org.cojen.classfile.TypeDesc;
import org.objectweb.asm.Label;
+import org.simantics.scl.compiler.constants.componentaccess.ComponentAccess;
+import org.simantics.scl.compiler.constants.componentaccess.FieldComponentAccess;
import org.simantics.scl.compiler.internal.codegen.continuations.Cont;
import org.simantics.scl.compiler.internal.codegen.references.BoundVar;
import org.simantics.scl.compiler.internal.codegen.references.IVal;
public class SCLConstructor extends FunctionValue {
private static int MAX_FIELD_COUNT = Constants.MAX_TUPLE_LENGTH;
- public static String[][] DEFAULT_FIELD_NAMES = new String[MAX_FIELD_COUNT+1][];
+ public static ComponentAccess[][] DEFAULT_FIELD_NAMES = new ComponentAccess[MAX_FIELD_COUNT+1][];
static {
for(int i=0;i<=MAX_FIELD_COUNT;++i) {
- String[] fieldNames = new String[i];
+ ComponentAccess[] fieldNames = new ComponentAccess[i];
for(int j=0;j<i;++j)
- fieldNames[j] = "c" + j;
+ fieldNames[j] = new FieldComponentAccess("c" + j);
DEFAULT_FIELD_NAMES[i] = fieldNames;
}
}
- String name; // For debugging
- String className;
- String[] fieldNames;
+ private final String name; // For debugging
+ private final String className;
+ private final ComponentAccess[] componentAccesses;
boolean onlyConstructor;
- int constructorTag;
- public final String[] recordFieldNames;
+ private final int constructorTag;
public SCLConstructor(String name, String className, TVar[] typeParameters, int constructorTag,
- Type returnType, String[] fieldNames, String[] recordFieldNames, Type... parameterTypes) {
+ Type returnType, ComponentAccess[] componentAccesses, Type... parameterTypes) {
super(typeParameters, Types.NO_EFFECTS, returnType, parameterTypes);
ClassBuilder.checkClassName(className);
this.name = name;
this.className = className;
- this.fieldNames = fieldNames;
+ this.componentAccesses = componentAccesses;
this.constructorTag = constructorTag;
- this.recordFieldNames = recordFieldNames;
}
public SCLConstructor(String name, String className, TVar[] typeParameters, int constructorTag,
Type returnType,
Type ... parameterTypes) {
this(name, className, typeParameters, constructorTag, returnType,
- DEFAULT_FIELD_NAMES[parameterTypes.length], null, parameterTypes);
+ DEFAULT_FIELD_NAMES[parameterTypes.length], parameterTypes);
}
public void setOnlyConstructor(boolean onlyConstructor) {
if(!typeDesc.equals(TypeDesc.VOID)) {
mb.dup();
- mb.loadField(MethodBuilder.getClassName(constructorType), fieldNames[i], typeDesc);
+ componentAccesses[i].load(mb, MethodBuilder.getClassName(constructorType), typeDesc);
if(typeDesc == TypeDesc.OBJECT)
mb.unbox(contType);
}
--- /dev/null
+package org.simantics.scl.compiler.constants.componentaccess;
+
+import org.cojen.classfile.TypeDesc;
+import org.simantics.scl.compiler.constants.generic.MethodRef;
+import org.simantics.scl.compiler.internal.codegen.utils.MethodBuilder;
+
+public interface ComponentAccess {
+
+ MethodRef toMethodRef(String baseClass, TypeDesc returnType);
+ void load(MethodBuilder mb, String baseClass, TypeDesc returnType);
+
+}
--- /dev/null
+package org.simantics.scl.compiler.constants.componentaccess;
+
+import org.cojen.classfile.TypeDesc;
+import org.simantics.scl.compiler.constants.generic.MethodRef;
+import org.simantics.scl.compiler.constants.generic.MethodRef.FieldRef;
+import org.simantics.scl.compiler.internal.codegen.utils.MethodBuilder;
+
+public class FieldComponentAccess implements ComponentAccess {
+ public final String fieldName;
+
+ public FieldComponentAccess(String fieldName) {
+ this.fieldName = fieldName;
+ }
+
+ @Override
+ public void load(MethodBuilder mb, String baseClass, TypeDesc returnType) {
+ mb.loadField(baseClass, fieldName, returnType);
+ }
+
+ @Override
+ public MethodRef toMethodRef(String baseClass, TypeDesc returnType) {
+ return new FieldRef(baseClass, fieldName, returnType);
+ }
+}
--- /dev/null
+package org.simantics.scl.compiler.constants.componentaccess;
+
+import org.cojen.classfile.TypeDesc;
+import org.simantics.scl.compiler.constants.generic.MethodRef;
+import org.simantics.scl.compiler.constants.generic.MethodRef.ObjectMethodRef;
+import org.simantics.scl.compiler.internal.codegen.utils.Constants;
+import org.simantics.scl.compiler.internal.codegen.utils.MethodBuilder;
+
+public class MethodComponentAccess implements ComponentAccess {
+ public final String methodName;
+ public final boolean isInterface;
+
+ public MethodComponentAccess(String fieldName, boolean isInterface) {
+ this.methodName = fieldName;
+ this.isInterface = isInterface;
+ }
+
+ @Override
+ public void load(MethodBuilder mb, String baseClass, TypeDesc returnType) {
+ if(isInterface)
+ mb.invokeInterface(baseClass, methodName, returnType, Constants.EMPTY_TYPEDESC_ARRAY);
+ else
+ mb.invokeVirtual(baseClass, methodName, returnType, Constants.EMPTY_TYPEDESC_ARRAY);
+ }
+
+ @Override
+ public MethodRef toMethodRef(String baseClass, TypeDesc returnType) {
+ return new ObjectMethodRef(isInterface, baseClass, methodName, returnType, Constants.EMPTY_TYPEDESC_ARRAY);
+ }
+}
context.getErrorLog().log(constructor.location, "Couldn't resolve the record constructor " + constructor.name + ".");
return new EError(constructor.location);
}
- if(!(constructorValue.getValue() instanceof SCLConstructor)) {
+ String[] parameterNames = constructorValue.parameterNames;
+ if(parameterNames == null) {
context.getErrorLog().log(constructor.location, "Value " + constructor.name + " is not a record constructor.");
return new EError(constructor.location);
}
- String[] fieldNames = ((SCLConstructor)constructorValue.getValue()).recordFieldNames;
- if(fieldNames == null) {
- context.getErrorLog().log(constructor.location, "Value " + constructor.name + " is not a record constructor.");
- return new EError(constructor.location);
- }
- Expression[] parameters = translateFieldsToFunctionParameters(context, fields, fieldNames, false);
+ Expression[] parameters = translateFieldsToFunctionParameters(context, fields, parameterNames, false);
if(parameters == null)
return new EError(location);
if(asPattern)
if(parameter == null) {
ExistentialFrame frame = context.getCurrentExistentialFrame();
if(frame == null || frame.disallowNewExistentials) {
- context.getErrorLog().log(location, "Field " + fieldNames[i] + " not defined.");
+ context.getErrorLog().log(location, "Field " + parameterNames[i] + " not defined.");
error = true;
}
else
private ArrayList<SCLValueProperty> properties = new ArrayList<SCLValueProperty>(2);
public String documentation;
public long definitionLocation = Locations.NO_LOCATION;
+ public String[] parameterNames;
public SCLValue(Name name) {
this.name = name;