--- /dev/null
+package org.simantics.scl.compiler.constants;
+
+import org.cojen.classfile.TypeDesc;
+import org.objectweb.asm.Label;
+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;
+import org.simantics.scl.compiler.internal.codegen.references.Val;
+import org.simantics.scl.compiler.internal.codegen.types.JavaTypeTranslator;
+import org.simantics.scl.compiler.internal.codegen.utils.ClassBuilder;
+import org.simantics.scl.compiler.internal.codegen.utils.CodeBuilderUtils;
+import org.simantics.scl.compiler.internal.codegen.utils.Constants;
+import org.simantics.scl.compiler.internal.codegen.utils.MethodBuilder;
+import org.simantics.scl.compiler.types.TVar;
+import org.simantics.scl.compiler.types.Type;
+import org.simantics.scl.compiler.types.Types;
+
+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][];
+
+ static {
+ for(int i=0;i<=MAX_FIELD_COUNT;++i) {
+ String[] fieldNames = new String[i];
+ for(int j=0;j<i;++j)
+ fieldNames[j] = "c" + j;
+ DEFAULT_FIELD_NAMES[i] = fieldNames;
+ }
+ }
+
+ String name; // For debugging
+ String className;
+ String[] fieldNames;
+ boolean onlyConstructor;
+ int constructorTag;
+ public final String[] recordFieldNames;
+
+ public SCLConstructor(String name, String className, TVar[] typeParameters, int constructorTag,
+ Type returnType, String[] fieldNames, String[] recordFieldNames, Type... parameterTypes) {
+ super(typeParameters, Types.NO_EFFECTS, returnType, parameterTypes);
+ ClassBuilder.checkClassName(className);
+ this.name = name;
+ this.className = className;
+ this.fieldNames = fieldNames;
+ 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);
+ }
+
+ public void setOnlyConstructor(boolean onlyConstructor) {
+ this.onlyConstructor = onlyConstructor;
+ }
+
+ @Override
+ public Type applyExact(MethodBuilder mb, Val[] parameters) {
+ if(className == null) {
+ mb.push(parameters[0], parameterTypes[0]);
+ return getReturnType();
+ }
+ else {
+ TypeDesc typeDesc = TypeDesc.forClass(className);
+ CodeBuilderUtils.constructRecord(typeDesc, mb,
+ parameterTypes, parameters);
+ return getReturnType();
+ }
+ }
+
+ @Override
+ public void deconstruct(MethodBuilder mb, IVal parameter, Cont success,
+ Label failure) {
+ JavaTypeTranslator javaTypeTranslator = mb.getJavaTypeTranslator();
+
+ if(onlyConstructor) {
+ if(className == null) {
+ TypeDesc parameterDesc = javaTypeTranslator.getTypeDesc(parameter);
+ Type expectedType = success.getParameterType(0);
+ TypeDesc expectedDesc = javaTypeTranslator.toTypeDesc(expectedType);
+ if(parameterDesc.equals(expectedDesc))
+ mb.jump(success, parameter);
+ else {
+ parameter.push(mb);
+ mb.unbox(expectedType);
+ BoundVar boundVar = new BoundVar(expectedType);
+ mb.store(boundVar);
+ mb.jump(success, boundVar);
+ }
+ return;
+ }
+ failure = null;
+ }
+
+ Label failureLabel = mb.createLabel();
+
+ TypeDesc constructorType = TypeDesc.forClass(className);
+
+ // Test if deconstructing is possible
+ mb.push(parameter, returnType);
+ if(failure != null) {
+ mb.dup();
+ mb.instanceOf(constructorType);
+ mb.ifZeroComparisonBranch(failureLabel, "==");
+ }
+
+ // Success
+ if(!onlyConstructor)
+ mb.checkCast(constructorType);
+ Val[] parameters = new Val[parameterTypes.length];
+ for(int i=0;i<parameterTypes.length;++i) {
+ TypeDesc typeDesc = javaTypeTranslator.toTypeDesc(parameterTypes[i]);
+ Type contType = success.getParameterType(i);
+
+ if(!typeDesc.equals(TypeDesc.VOID)) {
+ mb.dup();
+ mb.loadField(MethodBuilder.getClassName(constructorType), fieldNames[i], typeDesc);
+ if(typeDesc == TypeDesc.OBJECT)
+ mb.unbox(contType);
+ }
+
+ BoundVar boundVar = new BoundVar(contType);
+ mb.store(boundVar);
+ parameters[i] = boundVar;
+ }
+ mb.pop();
+ mb.jump(success, parameters);
+
+ // Failure
+ if(failure != null) {
+ mb.setLocation(failureLabel);
+ mb.pop();
+ mb.branch(failure);
+ }
+ }
+ public int constructorTag() {
+ return constructorTag;
+ }
+
+ @Override
+ public String toString() {
+ return name;
+ }
+
+}