868d70a6f1b51faa2765fc14961d87c1007cd5e5
[simantics/platform.git] / bundles / org.simantics.scl.compiler / src / org / simantics / scl / compiler / elaboration / chr / relations / CHRConstraint.java
1 package org.simantics.scl.compiler.elaboration.chr.relations;
2
3 import java.util.ArrayList;
4 import java.util.Collection;
5
6 import org.cojen.classfile.TypeDesc;
7 import org.simantics.scl.compiler.compilation.CompilationContext;
8 import org.simantics.scl.compiler.constants.Constant;
9 import org.simantics.scl.compiler.constants.JavaMethod;
10 import org.simantics.scl.compiler.constants.NoRepConstant;
11 import org.simantics.scl.compiler.constants.generic.CallJava;
12 import org.simantics.scl.compiler.constants.generic.MethodRef.ConstructorRef;
13 import org.simantics.scl.compiler.constants.generic.MethodRef.FieldRef;
14 import org.simantics.scl.compiler.constants.generic.MethodRef.ObjectMethodRef;
15 import org.simantics.scl.compiler.constants.generic.ParameterStackItem;
16 import org.simantics.scl.compiler.constants.generic.StackItem;
17 import org.simantics.scl.compiler.elaboration.chr.CHRRelation;
18 import org.simantics.scl.compiler.elaboration.chr.CHRRuleset;
19 import org.simantics.scl.compiler.elaboration.chr.plan.PrioritizedPlan;
20 import org.simantics.scl.compiler.internal.codegen.chr.CHRCodeGenerator;
21 import org.simantics.scl.compiler.internal.codegen.chr.CHRFactCodeGenerator;
22 import org.simantics.scl.compiler.internal.codegen.references.IVal;
23 import org.simantics.scl.compiler.internal.codegen.types.JavaTypeTranslator;
24 import org.simantics.scl.compiler.internal.codegen.types.StandardTypeConstructor;
25 import org.simantics.scl.compiler.internal.codegen.writer.CodeWriter;
26 import org.simantics.scl.compiler.internal.parsing.Symbol;
27 import org.simantics.scl.compiler.types.TCon;
28 import org.simantics.scl.compiler.types.TPred;
29 import org.simantics.scl.compiler.types.TVar;
30 import org.simantics.scl.compiler.types.Type;
31 import org.simantics.scl.compiler.types.Types;
32
33 import gnu.trove.map.hash.TIntObjectHashMap;
34
35 public class CHRConstraint extends Symbol implements CHRRelation {
36     public final String name;
37     public final Type[] parameterTypes;
38     
39     public boolean implicitlyDeclared;
40
41     // Analysis
42     public int firstPriorityAdded;
43     public int lastPriorityAdded;
44     public int firstPriorityRemoved;
45     public int lastPriorityRemoved;
46     
47     // Transient info
48     public CHRRuleset parentRuleset;
49     public String factClassName;
50     public Type factType;
51     public TypeDesc factTypeDesc;
52     
53     public TCon typeConstructor;
54     public Constant constructor;
55     public Constant accessId;
56     public Constant[] accessors;
57     public Constant addProcedure;
58     public Constant removeProcedure;
59     public Constant isAlive;
60     
61     public TIntObjectHashMap<IndexInfo> indices;
62     
63     // Query plans
64     public ArrayList<PrioritizedPlan> plans = new ArrayList<PrioritizedPlan>();
65     
66     public static class IndexInfo {
67         public final int indexMask;
68         public final String indexName;
69         public final Constant firstFact;
70         public final Constant nextFact;
71         
72         public IndexInfo(int indexMask, String indexName, Constant firstFact, Constant nextFact) {
73             this.indexMask = indexMask;
74             this.indexName = indexName;
75             this.firstFact = firstFact;
76             this.nextFact = nextFact;
77         }
78     }
79     
80     public CHRConstraint(long location, String name, Type[] parameterTypes) {
81         this.location = location;
82         this.name = name;
83         this.parameterTypes = parameterTypes;
84     }
85
86     public void initializeCodeGeneration(CompilationContext context, CHRRuleset parentRuleset) {
87         JavaTypeTranslator jtt = context.javaTypeTranslator;
88         
89         this.parentRuleset = parentRuleset;
90         this.factClassName = parentRuleset.storeClassName + "$" + name;
91         TCon factTypeConstructor = Types.con(parentRuleset.storeType.module, parentRuleset.storeType.name + "$" + name); 
92         this.factType = Types.apply(factTypeConstructor, TVar.EMPTY_ARRAY);
93         this.factTypeDesc = TypeDesc.forClass(factClassName);
94         
95         Type[] constructorTypes = new Type[parameterTypes.length+1];
96         constructorTypes[0] = Types.INTEGER;
97         ArrayList<StackItem> stackItems = new ArrayList<StackItem>(constructorTypes.length);
98         stackItems.add(new ParameterStackItem(0, Types.INTEGER));
99         for(int i=0;i<parameterTypes.length;++i) {
100             Type parameterType = parameterTypes[i];
101             constructorTypes[i+1] = parameterType;
102             if(!parameterType.equals(Types.UNIT))
103                 stackItems.add(new ParameterStackItem(stackItems.size(), parameterType));
104         }
105         TypeDesc[] constructorTypeDescs = JavaTypeTranslator.filterVoid(jtt.toTypeDescs(constructorTypes));
106         this.constructor = new CallJava(TVar.EMPTY_ARRAY, Types.PROC, factType, constructorTypes,
107                 stackItems.toArray(new StackItem[stackItems.size()]),
108                 new ConstructorRef(factClassName, constructorTypeDescs),
109                 null);
110         //this.constructor = new JavaConstructor(factClassName, Types.PROC, factType, constructorTypes);
111         this.accessId = new CallJava(TVar.EMPTY_ARRAY, Types.NO_EFFECTS, Types.INTEGER, new Type[] {factType},
112                 null, new FieldRef(factClassName, "id", CHRCodeGenerator.FACT_ID_TYPE), null);
113         this.accessors = new Constant[parameterTypes.length];
114         for(int i=0;i<parameterTypes.length;++i) {
115             TypeDesc typeDesc = jtt.toTypeDesc(parameterTypes[i]);
116             if(typeDesc.equals(TypeDesc.VOID))
117                 continue;
118             this.accessors[i] = new CallJava(TVar.EMPTY_ARRAY, Types.NO_EFFECTS, parameterTypes[i], new Type[] {factType},
119                     null, new FieldRef(factClassName, CHRFactCodeGenerator.fieldName(i), jtt.toTypeDesc(parameterTypes[i])), null);
120         }
121         this.addProcedure = new CallJava(TVar.EMPTY_ARRAY, Types.PROC, Types.UNIT, new Type[] {parentRuleset.storeType, factType},
122                 new StackItem[] {new ParameterStackItem(1, factType), new ParameterStackItem(0, parentRuleset.storeType)},
123                 new ObjectMethodRef(false, factClassName, "add", TypeDesc.VOID, new TypeDesc[] {parentRuleset.storeTypeDesc}),
124                 null);
125         
126         this.indices = new TIntObjectHashMap<IndexInfo>(Math.min(10, 1 << parameterTypes.length));
127         
128         if(context.module != null) // for unit testing
129             context.module.addTypeDescriptor(factTypeConstructor.name, new StandardTypeConstructor(factTypeConstructor, TVar.EMPTY_ARRAY, factTypeDesc));
130     }
131
132     @Override
133     public TVar[] getTypeVariables() {
134         return TVar.EMPTY_ARRAY;
135     }
136
137     @Override
138     public Type[] getParameterTypes() {
139         return parameterTypes;
140     }
141     
142     @Override
143     public String toString() {
144         return name;
145     }
146     
147     public Collection<IndexInfo> getIndices() {
148         return indices.valueCollection();
149     }
150     
151     public boolean mayBeRemoved() {
152         return removeProcedure != null;
153     }
154
155     private IndexInfo createIndexInfo(CompilationContext context, int indexMask) {
156         ArrayList<Type> keyTypeList = new ArrayList<Type>(parameterTypes.length+1);
157         keyTypeList.add(parentRuleset.storeType);
158         for(int i=0;i<parameterTypes.length;++i)
159             if(((indexMask>>i)&1)==1)
160                 keyTypeList.add(parameterTypes[i]);
161         String indexName = nameOfIndex(indexMask, parameterTypes.length);
162         Constant accessIndex;
163         if(indexMask == 0) {
164             accessIndex = new CallJava(TVar.EMPTY_ARRAY, Types.PROC, factType, new Type[] {parentRuleset.storeType},
165                     null, new FieldRef(parentRuleset.storeClassName, name + "$" + indexName, factTypeDesc), null);
166         }
167         else {
168             Type[] keyTypes = keyTypeList.toArray(new Type[keyTypeList.size()]);
169             accessIndex = new JavaMethod(true, parentRuleset.storeClassName, name + "$" + indexName, Types.PROC, factType, keyTypes);
170         }
171         return new IndexInfo(
172                 indexMask,
173                 indexName,
174                 accessIndex,
175                 new CallJava(TVar.EMPTY_ARRAY, Types.PROC, factType, new Type[] {factType},
176                         null, new FieldRef(factClassName, indexName + "Next", factTypeDesc), null)
177                 );
178     }
179     
180     public IVal fetchFromIndex(CompilationContext context, int boundMask) {
181         IndexInfo indexInfo = indices.get(boundMask);
182         if(indexInfo == null) {
183             indexInfo = createIndexInfo(context, boundMask);
184             indices.put(boundMask, indexInfo);
185         }
186         return indexInfo.firstFact;
187     }
188
189     public Constant nextElement(CompilationContext context, int boundMask) {
190         IndexInfo indexInfo = indices.get(boundMask);
191         if(indexInfo == null) {
192             indexInfo = createIndexInfo(context, boundMask);
193             indices.put(boundMask, indexInfo);
194         }
195         return indexInfo.nextFact;
196     }
197
198     
199     public static String nameOfIndex(int indexMask, int length) {
200         char[] chars = new char[length];
201         for(int i=0;i<length;++i)
202             chars[i] = ((indexMask>>i)&1) == 1 ? 'b' : 'f';
203         return new String(chars);
204     }
205
206     public void setMayBeRemoved() {
207         if(removeProcedure == null) {
208             removeProcedure = new CallJava(TVar.EMPTY_ARRAY, Types.PROC, Types.UNIT, new Type[] {parentRuleset.storeType, factType},
209                     new StackItem[] {new ParameterStackItem(1, factType), new ParameterStackItem(0, parentRuleset.storeType)},
210                     new ObjectMethodRef(false, factClassName, "remove", TypeDesc.VOID, new TypeDesc[] {parentRuleset.storeTypeDesc}),
211                     null);
212             isAlive = new JavaMethod(true, factClassName, "isAlive", Types.PROC, Types.BOOLEAN, factType);
213         }
214     }
215
216     public int getMinimumPriority() {
217         return plans.get(0).priority;
218     }
219     
220     public boolean isPassive() {
221         return plans.isEmpty();
222     }
223
224     public TPred[] getTypeConstraints() {
225         return TPred.EMPTY_ARRAY;
226     }
227
228     public IVal accessComponent(long location, CodeWriter w, IVal fact, int i) {
229         Constant accessor = accessors[i];
230         if(accessor == null)
231             return NoRepConstant.UNIT;
232         else
233             return w.apply(location, accessor, fact);
234     }
235 }