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