]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/chr/relations/CHRConstraint.java
Refactoring CHR handling code
[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.internal.codegen.chr.CHRCodeGenerationConstants;
20 import org.simantics.scl.compiler.internal.codegen.chr.CHRRuntimeRulesetCodeGenerator;
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 import gnu.trove.set.hash.THashSet;
34
35 public class CHRConstraint extends Symbol implements CHRRelation {
36     public final String name;
37     public final Type[] parameterTypes;
38     public String[] fieldNames;
39     
40     public boolean implicitlyDeclared;
41
42     // Analysis
43     //public int firstPriorityAdded;
44     public int lastPriorityAdded;
45     //public int firstPriorityRemoved;
46     public int lastPriorityRemoved;
47     
48     // Transient info
49     public CHRRuleset parentRuleset;
50     public String factClassName;
51     public Type factType;
52     public TypeDesc factTypeDesc;
53     
54     public TCon typeConstructor;
55     public Constant constructor;
56     public Constant accessId;
57     public Constant[] accessors;
58     public Constant addProcedure;
59     public Constant removeProcedure;
60     
61     public String nextContainerFieldName;
62     
63     public TIntObjectHashMap<IndexInfo> indices;
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 setParent(CHRRuleset parentRuleset) {
86         this.parentRuleset = parentRuleset;
87     }
88
89     public void initializeCodeGeneration(CompilationContext context, CHRRuleset parentRuleset) {
90         JavaTypeTranslator jtt = context.javaTypeTranslator;
91         
92         this.factClassName = parentRuleset.runtimeRulesetClassName + "$" + name;
93         TCon factTypeConstructor = Types.con(parentRuleset.runtimeRulesetType.module, parentRuleset.runtimeRulesetType.name + "$" + name); 
94         this.factType = Types.apply(factTypeConstructor, TVar.EMPTY_ARRAY);
95         this.factTypeDesc = TypeDesc.forClass(factClassName);
96         
97         Type[] constructorTypes = new Type[parameterTypes.length+1];
98         constructorTypes[0] = Types.INTEGER;
99         ArrayList<StackItem> stackItems = new ArrayList<StackItem>(constructorTypes.length);
100         stackItems.add(new ParameterStackItem(0, Types.INTEGER));
101         for(int i=0;i<parameterTypes.length;++i) {
102             Type parameterType = parameterTypes[i];
103             constructorTypes[i+1] = parameterType;
104             if(!parameterType.equals(Types.UNIT))
105                 stackItems.add(new ParameterStackItem(stackItems.size(), parameterType));
106         }
107         TypeDesc[] constructorTypeDescs = JavaTypeTranslator.filterVoid(jtt.toTypeDescs(constructorTypes));
108         this.constructor = new CallJava(TVar.EMPTY_ARRAY, Types.PROC, factType, constructorTypes,
109                 stackItems.toArray(new StackItem[stackItems.size()]),
110                 new ConstructorRef(factClassName, constructorTypeDescs),
111                 null);
112         //this.constructor = new JavaConstructor(factClassName, Types.PROC, factType, constructorTypes);
113         this.accessId = new CallJava(TVar.EMPTY_ARRAY, Types.NO_EFFECTS, Types.INTEGER, new Type[] {factType},
114                 null, new FieldRef(CHRCodeGenerationConstants.CHRFact_name, "id", CHRRuntimeRulesetCodeGenerator.FACT_ID_TYPE), null);
115         this.accessors = new Constant[parameterTypes.length];
116         for(int i=0;i<parameterTypes.length;++i) {
117             TypeDesc typeDesc = jtt.toTypeDesc(parameterTypes[i]);
118             if(typeDesc.equals(TypeDesc.VOID))
119                 continue;
120             this.accessors[i] = new CallJava(TVar.EMPTY_ARRAY, Types.NO_EFFECTS, parameterTypes[i], new Type[] {factType},
121                     null, new FieldRef(factClassName, CHRCodeGenerationConstants.fieldName(i), jtt.toTypeDesc(parameterTypes[i])), null);
122         }
123         this.addProcedure = new CallJava(TVar.EMPTY_ARRAY, Types.PROC, Types.UNIT, new Type[] {parentRuleset.runtimeRulesetType, Types.CHRContext, factType},
124                 new StackItem[] {new ParameterStackItem(2, factType), new ParameterStackItem(0, parentRuleset.runtimeRulesetType), new ParameterStackItem(1, Types.CHRContext)},
125                 new ObjectMethodRef(false, factClassName, "add", TypeDesc.VOID, new TypeDesc[] {parentRuleset.runtimeRulesetTypeDesc, CHRCodeGenerationConstants.CHRContext}),
126                 null);
127         
128         this.indices = new TIntObjectHashMap<IndexInfo>(Math.min(10, 1 << parameterTypes.length));
129         
130         if(context.module != null) // for unit testing
131             context.module.addTypeDescriptor(factTypeConstructor.name, new StandardTypeConstructor(factTypeConstructor, TVar.EMPTY_ARRAY, factTypeDesc));
132         
133         // next container
134         if(parentRuleset.extensible) {
135             nextContainerFieldName = CHRCodeGenerationConstants.nextContainerName(name);
136         }
137     }
138
139     @Override
140     public TVar[] getTypeVariables() {
141         return TVar.EMPTY_ARRAY;
142     }
143
144     @Override
145     public Type[] getParameterTypes() {
146         return parameterTypes;
147     }
148     
149     @Override
150     public String toString() {
151         return name;
152     }
153     
154     public Collection<IndexInfo> getIndices() {
155         return indices.valueCollection();
156     }
157     
158     public boolean mayBeRemoved() {
159         return removeProcedure != null;
160     }
161
162     private IndexInfo createIndexInfo(CompilationContext context, int indexMask) {
163         ArrayList<Type> keyTypeList = new ArrayList<Type>(parameterTypes.length+1);
164         keyTypeList.add(parentRuleset.runtimeRulesetType);
165         for(int i=0;i<parameterTypes.length;++i)
166             if(((indexMask>>i)&1)==1)
167                 keyTypeList.add(parameterTypes[i]);
168         String indexName = nameOfIndex(indexMask, parameterTypes.length);
169         Constant accessIndex;
170         if(indexMask == 0) {
171             accessIndex = new CallJava(TVar.EMPTY_ARRAY, Types.PROC, factType, new Type[] {parentRuleset.runtimeRulesetType},
172                     null, new FieldRef(parentRuleset.runtimeRulesetClassName, name + "$" + indexName, factTypeDesc), null);
173         }
174         else {
175             Type[] keyTypes = keyTypeList.toArray(new Type[keyTypeList.size()]);
176             accessIndex = new JavaMethod(true, parentRuleset.runtimeRulesetClassName, name + "$" + indexName, Types.PROC, factType, keyTypes);
177         }
178         return new IndexInfo(
179                 indexMask,
180                 indexName,
181                 accessIndex,
182                 new CallJava(TVar.EMPTY_ARRAY, Types.PROC, factType, new Type[] {factType},
183                         null, new FieldRef(factClassName, indexName + "Next", factTypeDesc), null)
184                 );
185     }
186     
187     public IndexInfo getOrCreateIndex(CompilationContext context, int boundMask) {
188         IndexInfo indexInfo = indices.get(boundMask);
189         if(indexInfo == null) {
190             indexInfo = createIndexInfo(context, boundMask);
191             indices.put(boundMask, indexInfo);
192         }
193         return indexInfo;
194     }
195     
196     public IVal fetchFromIndex(CompilationContext context, int boundMask) {
197         return getOrCreateIndex(context, boundMask).firstFact;
198     }
199
200     public Constant nextElement(CompilationContext context, int boundMask) {
201         IndexInfo indexInfo = indices.get(boundMask);
202         if(indexInfo == null) {
203             indexInfo = createIndexInfo(context, boundMask);
204             indices.put(boundMask, indexInfo);
205         }
206         return getOrCreateIndex(context, boundMask).nextFact;
207     }
208
209     
210     public static String nameOfIndex(int indexMask, int length) {
211         char[] chars = new char[length];
212         for(int i=0;i<length;++i)
213             chars[i] = ((indexMask>>i)&1) == 1 ? 'b' : 'f';
214         return new String(chars);
215     }
216
217     public void setMayBeRemoved() {
218         if(removeProcedure == null) {
219             removeProcedure = new CallJava(TVar.EMPTY_ARRAY, Types.PROC, Types.UNIT, new Type[] {parentRuleset.runtimeRulesetType, factType},
220                     new StackItem[] {new ParameterStackItem(1, factType), new ParameterStackItem(0, parentRuleset.runtimeRulesetType)},
221                     new ObjectMethodRef(false, factClassName, "remove", TypeDesc.VOID, new TypeDesc[] {parentRuleset.runtimeRulesetTypeDesc}),
222                     null);
223         }
224     }
225
226     public TPred[] getTypeConstraints() {
227         return TPred.EMPTY_ARRAY;
228     }
229
230     public IVal accessComponent(long location, CodeWriter w, IVal fact, int i) {
231         Constant accessor = accessors[i];
232         if(accessor == null)
233             return NoRepConstant.UNIT;
234         else
235             return w.apply(location, accessor, fact);
236     }
237     
238     @Override
239     public String[] getFieldNames() {
240         return fieldNames;
241     }
242
243     @Override
244     public void collectEnforceEffects(THashSet<Type> effects) {
245         effects.add(Types.PROC);
246     }
247
248     @Override
249     public void collectQueryEffects(THashSet<Type> effects) {
250         effects.add(Types.PROC);
251     }
252 }