9e8c7a0f2310c79b0bc28c26fc505bdb07ae394c
[simantics/platform.git] / bundles / org.simantics.scl.compiler / src / org / simantics / scl / compiler / constants / SCLConstructor.java
1 package org.simantics.scl.compiler.constants;
2
3 import org.cojen.classfile.TypeDesc;
4 import org.objectweb.asm.Label;
5 import org.simantics.scl.compiler.internal.codegen.continuations.Cont;
6 import org.simantics.scl.compiler.internal.codegen.references.BoundVar;
7 import org.simantics.scl.compiler.internal.codegen.references.IVal;
8 import org.simantics.scl.compiler.internal.codegen.references.Val;
9 import org.simantics.scl.compiler.internal.codegen.types.JavaTypeTranslator;
10 import org.simantics.scl.compiler.internal.codegen.utils.ClassBuilder;
11 import org.simantics.scl.compiler.internal.codegen.utils.CodeBuilderUtils;
12 import org.simantics.scl.compiler.internal.codegen.utils.Constants;
13 import org.simantics.scl.compiler.internal.codegen.utils.MethodBuilder;
14 import org.simantics.scl.compiler.types.TVar;
15 import org.simantics.scl.compiler.types.Type;
16 import org.simantics.scl.compiler.types.Types;
17
18 public class SCLConstructor extends FunctionValue {
19     
20     private static int MAX_FIELD_COUNT = Constants.MAX_TUPLE_LENGTH;
21     public static String[][] DEFAULT_FIELD_NAMES = new String[MAX_FIELD_COUNT+1][];
22     
23     static {
24         for(int i=0;i<=MAX_FIELD_COUNT;++i) {
25             String[] fieldNames = new String[i];
26             for(int j=0;j<i;++j)
27                 fieldNames[j] = "c" + j;
28             DEFAULT_FIELD_NAMES[i] = fieldNames;
29         }
30     }
31     
32     String name; // For debugging
33     String className;
34     String[] fieldNames;
35     boolean onlyConstructor;
36     int constructorTag;
37     public final String[] recordFieldNames;
38        
39     public SCLConstructor(String name, String className, TVar[] typeParameters, int constructorTag,
40             Type returnType, String[] fieldNames, String[] recordFieldNames, Type... parameterTypes) {
41         super(typeParameters, Types.NO_EFFECTS, returnType, parameterTypes);
42         ClassBuilder.checkClassName(className);
43         this.name = name;
44         this.className = className;
45         this.fieldNames = fieldNames;
46         this.constructorTag = constructorTag;
47         this.recordFieldNames = recordFieldNames;
48     }    
49     
50     public SCLConstructor(String name, String className, TVar[] typeParameters, int constructorTag,
51             Type returnType,
52             Type ... parameterTypes) {     
53         this(name, className, typeParameters, constructorTag, returnType,
54                 DEFAULT_FIELD_NAMES[parameterTypes.length], null, parameterTypes);
55     }
56     
57     public void setOnlyConstructor(boolean onlyConstructor) {
58         this.onlyConstructor = onlyConstructor;
59     }
60         
61     @Override
62     public Type applyExact(MethodBuilder mb, Val[] parameters) {
63         if(className == null) {
64             mb.push(parameters[0], parameterTypes[0]);
65             return getReturnType();
66         }
67         else {
68             TypeDesc typeDesc = TypeDesc.forClass(className);
69             CodeBuilderUtils.constructRecord(typeDesc, mb, 
70                     parameterTypes, parameters);
71             return getReturnType();
72         }
73     }
74     
75     @Override
76     public void deconstruct(MethodBuilder mb, IVal parameter, Cont success,
77             Label failure) {
78         JavaTypeTranslator javaTypeTranslator = mb.getJavaTypeTranslator();
79
80         if(onlyConstructor) {
81             if(className == null) {
82                 TypeDesc parameterDesc = javaTypeTranslator.getTypeDesc(parameter);
83                 Type expectedType = success.getParameterType(0);
84                 TypeDesc expectedDesc = javaTypeTranslator.toTypeDesc(expectedType);
85                 if(parameterDesc.equals(expectedDesc))
86                     mb.jump(success, parameter);
87                 else {
88                     parameter.push(mb);
89                     mb.unbox(expectedType);
90                     BoundVar boundVar = new BoundVar(expectedType);
91                     mb.store(boundVar);
92                     mb.jump(success, boundVar);
93                 }
94                 return;
95             }
96             failure = null;
97         }
98         
99         Label failureLabel = mb.createLabel();
100         
101         TypeDesc constructorType = TypeDesc.forClass(className);
102         
103         // Test if deconstructing is possible
104         mb.push(parameter, returnType);
105         if(failure != null) {
106             mb.dup();
107             mb.instanceOf(constructorType);
108             mb.ifZeroComparisonBranch(failureLabel, "==");
109         }
110         
111         // Success
112         if(!onlyConstructor)
113             mb.checkCast(constructorType);
114         Val[] parameters = new Val[parameterTypes.length];
115         for(int i=0;i<parameterTypes.length;++i) {
116             TypeDesc typeDesc = javaTypeTranslator.toTypeDesc(parameterTypes[i]);            
117             Type contType = success.getParameterType(i);
118             
119             if(!typeDesc.equals(TypeDesc.VOID)) {
120                 mb.dup();
121                 mb.loadField(MethodBuilder.getClassName(constructorType), fieldNames[i], typeDesc);                
122                 if(typeDesc == TypeDesc.OBJECT)
123                     mb.unbox(contType);      
124             }
125             
126             BoundVar boundVar = new BoundVar(contType);
127             mb.store(boundVar);            
128             parameters[i] = boundVar;
129         }
130         mb.pop();
131         mb.jump(success, parameters);
132         
133         // Failure
134         if(failure != null) {
135             mb.setLocation(failureLabel);
136             mb.pop();
137             mb.branch(failure);
138         }
139     }
140     public int constructorTag() {
141         return constructorTag;
142     }
143     
144     @Override
145     public String toString() {
146         return name;
147     }
148     
149 }