package org.simantics.scl.compiler.elaboration.chr.relations; import java.util.ArrayList; import java.util.Collection; import org.cojen.classfile.TypeDesc; import org.simantics.scl.compiler.compilation.CompilationContext; import org.simantics.scl.compiler.constants.Constant; import org.simantics.scl.compiler.constants.JavaMethod; import org.simantics.scl.compiler.constants.NoRepConstant; import org.simantics.scl.compiler.constants.generic.CallJava; import org.simantics.scl.compiler.constants.generic.MethodRef.ConstructorRef; import org.simantics.scl.compiler.constants.generic.MethodRef.FieldRef; import org.simantics.scl.compiler.constants.generic.MethodRef.ObjectMethodRef; import org.simantics.scl.compiler.constants.generic.ParameterStackItem; import org.simantics.scl.compiler.constants.generic.StackItem; import org.simantics.scl.compiler.elaboration.chr.CHRRelation; import org.simantics.scl.compiler.elaboration.chr.CHRRuleset; import org.simantics.scl.compiler.internal.codegen.chr.CHRCodeGenerationConstants; import org.simantics.scl.compiler.internal.codegen.chr.CHRRuntimeRulesetCodeGenerator; import org.simantics.scl.compiler.internal.codegen.references.IVal; import org.simantics.scl.compiler.internal.codegen.types.JavaTypeTranslator; import org.simantics.scl.compiler.internal.codegen.types.StandardTypeConstructor; import org.simantics.scl.compiler.internal.codegen.writer.CodeWriter; import org.simantics.scl.compiler.internal.parsing.Symbol; import org.simantics.scl.compiler.types.TCon; import org.simantics.scl.compiler.types.TPred; import org.simantics.scl.compiler.types.TVar; import org.simantics.scl.compiler.types.Type; import org.simantics.scl.compiler.types.Types; import gnu.trove.map.hash.TIntObjectHashMap; import gnu.trove.set.hash.THashSet; public class CHRConstraint extends Symbol implements CHRRelation { public final String name; public final Type[] parameterTypes; public String[] fieldNames; public boolean implicitlyDeclared; // Analysis //public int firstPriorityAdded; public int lastPriorityAdded; //public int firstPriorityRemoved; public int lastPriorityRemoved; // Transient info public CHRRuleset parentRuleset; public String factClassName; public Type factType; public TypeDesc factTypeDesc; public TCon typeConstructor; public Constant constructor; public Constant accessId; public Constant[] accessors; public Constant addProcedure; public Constant removeProcedure; public String nextContainerFieldName; public TIntObjectHashMap indices; public static class IndexInfo { public final int indexMask; public final String indexName; public final Constant firstFact; public final Constant nextFact; public IndexInfo(int indexMask, String indexName, Constant firstFact, Constant nextFact) { this.indexMask = indexMask; this.indexName = indexName; this.firstFact = firstFact; this.nextFact = nextFact; } } public CHRConstraint(long location, String name, Type[] parameterTypes) { this.location = location; this.name = name; this.parameterTypes = parameterTypes; } public void setParent(CHRRuleset parentRuleset) { this.parentRuleset = parentRuleset; } public void initializeCodeGeneration(CompilationContext context, CHRRuleset parentRuleset) { JavaTypeTranslator jtt = context.javaTypeTranslator; this.factClassName = parentRuleset.runtimeRulesetClassName + "$" + name; TCon factTypeConstructor = Types.con(parentRuleset.runtimeRulesetType.module, parentRuleset.runtimeRulesetType.name + "$" + name); this.factType = Types.apply(factTypeConstructor, TVar.EMPTY_ARRAY); this.factTypeDesc = TypeDesc.forClass(factClassName); Type[] constructorTypes = new Type[parameterTypes.length+1]; constructorTypes[0] = Types.INTEGER; ArrayList stackItems = new ArrayList(constructorTypes.length); stackItems.add(new ParameterStackItem(0, Types.INTEGER)); for(int i=0;i(Math.min(10, 1 << parameterTypes.length)); if(context.module != null) // for unit testing context.module.addTypeDescriptor(factTypeConstructor.name, new StandardTypeConstructor(factTypeConstructor, TVar.EMPTY_ARRAY, factTypeDesc)); // next container if(parentRuleset.extensible) { nextContainerFieldName = CHRCodeGenerationConstants.nextContainerName(name); } } @Override public TVar[] getTypeVariables() { return TVar.EMPTY_ARRAY; } @Override public Type[] getParameterTypes() { return parameterTypes; } @Override public String toString() { return name; } public Collection getIndices() { return indices.valueCollection(); } public boolean mayBeRemoved() { return removeProcedure != null; } private IndexInfo createIndexInfo(CompilationContext context, int indexMask) { ArrayList keyTypeList = new ArrayList(parameterTypes.length+1); keyTypeList.add(parentRuleset.runtimeRulesetType); for(int i=0;i>i)&1)==1) keyTypeList.add(parameterTypes[i]); String indexName = nameOfIndex(indexMask, parameterTypes.length); Constant accessIndex; if(indexMask == 0) { accessIndex = new CallJava(TVar.EMPTY_ARRAY, Types.PROC, factType, new Type[] {parentRuleset.runtimeRulesetType}, null, new FieldRef(parentRuleset.runtimeRulesetClassName, name + "$" + indexName, factTypeDesc), null); } else { Type[] keyTypes = keyTypeList.toArray(new Type[keyTypeList.size()]); accessIndex = new JavaMethod(true, parentRuleset.runtimeRulesetClassName, name + "$" + indexName, Types.PROC, factType, keyTypes); } return new IndexInfo( indexMask, indexName, accessIndex, new CallJava(TVar.EMPTY_ARRAY, Types.PROC, factType, new Type[] {factType}, null, new FieldRef(factClassName, indexName + "Next", factTypeDesc), null) ); } public IndexInfo getOrCreateIndex(CompilationContext context, int boundMask) { IndexInfo indexInfo = indices.get(boundMask); if(indexInfo == null) { indexInfo = createIndexInfo(context, boundMask); indices.put(boundMask, indexInfo); } return indexInfo; } public IVal fetchFromIndex(CompilationContext context, int boundMask) { return getOrCreateIndex(context, boundMask).firstFact; } public Constant nextElement(CompilationContext context, int boundMask) { IndexInfo indexInfo = indices.get(boundMask); if(indexInfo == null) { indexInfo = createIndexInfo(context, boundMask); indices.put(boundMask, indexInfo); } return getOrCreateIndex(context, boundMask).nextFact; } public static String nameOfIndex(int indexMask, int length) { char[] chars = new char[length]; for(int i=0;i>i)&1) == 1 ? 'b' : 'f'; return new String(chars); } public void setMayBeRemoved() { if(removeProcedure == null) { removeProcedure = new CallJava(TVar.EMPTY_ARRAY, Types.PROC, Types.UNIT, new Type[] {parentRuleset.runtimeRulesetType, factType}, new StackItem[] {new ParameterStackItem(1, factType), new ParameterStackItem(0, parentRuleset.runtimeRulesetType)}, new ObjectMethodRef(false, factClassName, "remove", TypeDesc.VOID, new TypeDesc[] {parentRuleset.runtimeRulesetTypeDesc}), null); } } public TPred[] getTypeConstraints() { return TPred.EMPTY_ARRAY; } public IVal accessComponent(long location, CodeWriter w, IVal fact, int i) { Constant accessor = accessors[i]; if(accessor == null) return NoRepConstant.UNIT; else return w.apply(location, accessor, fact); } @Override public String[] getFieldNames() { return fieldNames; } @Override public void collectEnforceEffects(THashSet effects) { effects.add(Types.PROC); } @Override public void collectQueryEffects(THashSet effects) { effects.add(Types.PROC); } }