]> gerrit.simantics Code Review - simantics/platform.git/blobdiff - bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/constants/SCLConstructor.java
Migrated source code from Simantics SVN
[simantics/platform.git] / bundles / org.simantics.scl.compiler / src / org / simantics / scl / compiler / constants / SCLConstructor.java
diff --git a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/constants/SCLConstructor.java b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/constants/SCLConstructor.java
new file mode 100644 (file)
index 0000000..9e8c7a0
--- /dev/null
@@ -0,0 +1,149 @@
+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;
+    }
+    
+}