--- /dev/null
+package org.simantics.scl.compiler.elaboration.chr.relations;\r
+\r
+import java.util.ArrayList;\r
+import java.util.Collection;\r
+\r
+import org.cojen.classfile.TypeDesc;\r
+import org.simantics.scl.compiler.compilation.CompilationContext;\r
+import org.simantics.scl.compiler.constants.Constant;\r
+import org.simantics.scl.compiler.constants.JavaConstructor;\r
+import org.simantics.scl.compiler.constants.JavaMethod;\r
+import org.simantics.scl.compiler.constants.generic.CallJava;\r
+import org.simantics.scl.compiler.constants.generic.MethodRef.FieldRef;\r
+import org.simantics.scl.compiler.constants.generic.MethodRef.ObjectMethodRef;\r
+import org.simantics.scl.compiler.constants.generic.ParameterStackItem;\r
+import org.simantics.scl.compiler.constants.generic.StackItem;\r
+import org.simantics.scl.compiler.elaboration.chr.CHRRelation;\r
+import org.simantics.scl.compiler.elaboration.chr.CHRRuleset;\r
+import org.simantics.scl.compiler.elaboration.chr.plan.PrioritizedPlan;\r
+import org.simantics.scl.compiler.internal.codegen.chr.CHRCodeGenerator;\r
+import org.simantics.scl.compiler.internal.codegen.references.IVal;\r
+import org.simantics.scl.compiler.internal.codegen.types.JavaTypeTranslator;\r
+import org.simantics.scl.compiler.internal.codegen.types.StandardTypeConstructor;\r
+import org.simantics.scl.compiler.internal.parsing.Symbol;\r
+import org.simantics.scl.compiler.types.TCon;\r
+import org.simantics.scl.compiler.types.TVar;\r
+import org.simantics.scl.compiler.types.Type;\r
+import org.simantics.scl.compiler.types.Types;\r
+\r
+import gnu.trove.map.hash.TIntObjectHashMap;\r
+\r
+public class CHRConstraint extends Symbol implements CHRRelation {\r
+ public final String name;\r
+ public final Type[] parameterTypes;\r
+ \r
+ public boolean implicitlyDeclared;\r
+\r
+ // Analysis\r
+ public int firstPriorityAdded;\r
+ public int lastPriorityAdded;\r
+ public int firstPriorityRemoved;\r
+ public int lastPriorityRemoved;\r
+ \r
+ // Transient info\r
+ public CHRRuleset parentRuleset;\r
+ public String factClassName;\r
+ public Type factType;\r
+ public TypeDesc factTypeDesc;\r
+ \r
+ public TCon typeConstructor;\r
+ public Constant constructor;\r
+ public Constant accessId;\r
+ public Constant[] accessors;\r
+ public Constant addProcedure;\r
+ public Constant removeProcedure;\r
+ public Constant isAlive;\r
+ \r
+ public TIntObjectHashMap<IndexInfo> indices;\r
+ \r
+ // Query plans\r
+ public ArrayList<PrioritizedPlan> plans = new ArrayList<PrioritizedPlan>();\r
+ \r
+ public static class IndexInfo {\r
+ public final int indexMask;\r
+ public final String indexName;\r
+ public final Constant firstFact;\r
+ public final Constant nextFact;\r
+ \r
+ public IndexInfo(int indexMask, String indexName, Constant firstFact, Constant nextFact) {\r
+ this.indexMask = indexMask;\r
+ this.indexName = indexName;\r
+ this.firstFact = firstFact;\r
+ this.nextFact = nextFact;\r
+ }\r
+ }\r
+ \r
+ public CHRConstraint(long location, String name, Type[] parameterTypes) {\r
+ this.location = location;\r
+ this.name = name;\r
+ this.parameterTypes = parameterTypes;\r
+ }\r
+\r
+ public void initializeCodeGeneration(CompilationContext context, CHRRuleset parentRuleset) {\r
+ JavaTypeTranslator jtt = context.javaTypeTranslator;\r
+ \r
+ this.parentRuleset = parentRuleset;\r
+ this.factClassName = parentRuleset.storeClassName + "$" + name;\r
+ TCon factTypeConstructor = Types.con(parentRuleset.storeType.module, parentRuleset.storeType.name + "$" + name); \r
+ this.factType = Types.apply(factTypeConstructor, TVar.EMPTY_ARRAY);\r
+ this.factTypeDesc = TypeDesc.forClass(factClassName);\r
+ \r
+ Type[] constructorTypes = new Type[parameterTypes.length+1];\r
+ constructorTypes[0] = Types.INTEGER;\r
+ for(int i=0;i<parameterTypes.length;++i)\r
+ constructorTypes[i+1] = parameterTypes[i];\r
+ this.constructor = new JavaConstructor(factClassName, Types.PROC, factType, constructorTypes);\r
+ this.accessId = new CallJava(TVar.EMPTY_ARRAY, Types.NO_EFFECTS, Types.INTEGER, new Type[] {factType},\r
+ null, new FieldRef(factClassName, "id", CHRCodeGenerator.FACT_ID_TYPE), null);\r
+ this.accessors = new Constant[parameterTypes.length];\r
+ for(int i=0;i<parameterTypes.length;++i)\r
+ this.accessors[i] = new CallJava(TVar.EMPTY_ARRAY, Types.NO_EFFECTS, parameterTypes[i], new Type[] {factType},\r
+ null, new FieldRef(factClassName, "c" + i, jtt.toTypeDesc(parameterTypes[i])), null);\r
+ this.addProcedure = new CallJava(TVar.EMPTY_ARRAY, Types.PROC, Types.UNIT, new Type[] {parentRuleset.storeType, factType},\r
+ new StackItem[] {new ParameterStackItem(1, factType), new ParameterStackItem(0, parentRuleset.storeType)},\r
+ new ObjectMethodRef(false, factClassName, "add", TypeDesc.VOID, new TypeDesc[] {parentRuleset.storeTypeDesc}),\r
+ null);\r
+ \r
+ this.indices = new TIntObjectHashMap<IndexInfo>(Math.min(10, 1 << parameterTypes.length));\r
+ \r
+ if(context.module != null) // for unit testing\r
+ context.module.addTypeDescriptor(factTypeConstructor.name, new StandardTypeConstructor(factTypeConstructor, TVar.EMPTY_ARRAY, factTypeDesc));\r
+ }\r
+\r
+ @Override\r
+ public TVar[] getTypeVariables() {\r
+ return TVar.EMPTY_ARRAY;\r
+ }\r
+\r
+ @Override\r
+ public Type[] getParameterTypes() {\r
+ return parameterTypes;\r
+ }\r
+ \r
+ @Override\r
+ public String toString() {\r
+ return name;\r
+ }\r
+ \r
+ public Collection<IndexInfo> getIndices() {\r
+ return indices.valueCollection();\r
+ }\r
+ \r
+ public boolean mayBeRemoved() {\r
+ return removeProcedure != null;\r
+ }\r
+\r
+ private IndexInfo createIndexInfo(CompilationContext context, int indexMask) {\r
+ ArrayList<Type> keyTypeList = new ArrayList<Type>(parameterTypes.length+1);\r
+ keyTypeList.add(parentRuleset.storeType);\r
+ for(int i=0;i<parameterTypes.length;++i)\r
+ if(((indexMask>>i)&1)==1)\r
+ keyTypeList.add(parameterTypes[i]);\r
+ String indexName = nameOfIndex(indexMask, parameterTypes.length);\r
+ Constant accessIndex;\r
+ if(indexMask == 0) {\r
+ accessIndex = new CallJava(TVar.EMPTY_ARRAY, Types.PROC, factType, new Type[] {parentRuleset.storeType},\r
+ null, new FieldRef(parentRuleset.storeClassName, name + "$" + indexName, factTypeDesc), null);\r
+ }\r
+ else {\r
+ Type[] keyTypes = keyTypeList.toArray(new Type[keyTypeList.size()]);\r
+ accessIndex = new JavaMethod(true, parentRuleset.storeClassName, name + "$" + indexName, Types.PROC, factType, keyTypes);\r
+ }\r
+ return new IndexInfo(\r
+ indexMask,\r
+ indexName,\r
+ accessIndex,\r
+ new CallJava(TVar.EMPTY_ARRAY, Types.PROC, factType, new Type[] {factType},\r
+ null, new FieldRef(factClassName, indexName + "Next", factTypeDesc), null)\r
+ );\r
+ }\r
+\r
+ public Constant accessComponent(int i) {\r
+ return accessors[i];\r
+ }\r
+ \r
+ public IVal fetchFromIndex(CompilationContext context, int boundMask) {\r
+ IndexInfo indexInfo = indices.get(boundMask);\r
+ if(indexInfo == null) {\r
+ indexInfo = createIndexInfo(context, boundMask);\r
+ indices.put(boundMask, indexInfo);\r
+ }\r
+ return indexInfo.firstFact;\r
+ }\r
+\r
+ public Constant nextElement(CompilationContext context, int boundMask) {\r
+ IndexInfo indexInfo = indices.get(boundMask);\r
+ if(indexInfo == null) {\r
+ indexInfo = createIndexInfo(context, boundMask);\r
+ indices.put(boundMask, indexInfo);\r
+ }\r
+ return indexInfo.nextFact;\r
+ }\r
+\r
+ \r
+ public static String nameOfIndex(int indexMask, int length) {\r
+ char[] chars = new char[length];\r
+ for(int i=0;i<length;++i)\r
+ chars[i] = ((indexMask>>i)&1) == 1 ? 'b' : 'f';\r
+ return new String(chars);\r
+ }\r
+\r
+ public void setMayBeRemoved() {\r
+ if(removeProcedure == null) {\r
+ removeProcedure = new CallJava(TVar.EMPTY_ARRAY, Types.PROC, Types.UNIT, new Type[] {parentRuleset.storeType, factType},\r
+ new StackItem[] {new ParameterStackItem(1, factType), new ParameterStackItem(0, parentRuleset.storeType)},\r
+ new ObjectMethodRef(false, factClassName, "remove", TypeDesc.VOID, new TypeDesc[] {parentRuleset.storeTypeDesc}),\r
+ null);\r
+ isAlive = new JavaMethod(true, factClassName, "isAlive", Types.PROC, Types.BOOLEAN, factType);\r
+ }\r
+ }\r
+\r
+ public int getMinimumPriority() {\r
+ return plans.get(0).priority;\r
+ }\r
+ \r
+ public boolean isPassive() {\r
+ return plans.isEmpty();\r
+ }\r
+}\r