X-Git-Url: https://gerrit.simantics.org/r/gitweb?p=simantics%2Fplatform.git;a=blobdiff_plain;f=bundles%2Forg.simantics.scl.compiler%2Fsrc%2Forg%2Fsimantics%2Fscl%2Fcompiler%2Felaboration%2Fchr%2FCHRRuleset.java;h=bb00f08850f8fa3cd6f21586a8b60a6e052ff640;hp=a2b5c2196df7ca02c4529994c8689eccf6a474a6;hb=fad36d463b75c3a9944d875fc627c3533f6da74d;hpb=ca40974f87c9db00eb77aaf1acc1e9937b37261b diff --git a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/chr/CHRRuleset.java b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/chr/CHRRuleset.java index a2b5c2196..bb00f0885 100644 --- a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/chr/CHRRuleset.java +++ b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/chr/CHRRuleset.java @@ -1,197 +1,333 @@ -package org.simantics.scl.compiler.elaboration.chr; - -import java.util.ArrayList; - -import org.cojen.classfile.TypeDesc; -import org.simantics.scl.compiler.compilation.CompilationContext; -import org.simantics.scl.compiler.constants.BooleanConstant; -import org.simantics.scl.compiler.constants.Constant; -import org.simantics.scl.compiler.constants.IntegerConstant; -import org.simantics.scl.compiler.constants.JavaMethod; -import org.simantics.scl.compiler.constants.generic.CallJava; -import org.simantics.scl.compiler.constants.generic.MethodRef.FieldRef; -import org.simantics.scl.compiler.constants.generic.MethodRef.SetFieldRef; -import org.simantics.scl.compiler.elaboration.chr.analysis.UsageAnalysis; -import org.simantics.scl.compiler.elaboration.chr.plan.PlanOp; -import org.simantics.scl.compiler.elaboration.chr.plan.PlanRealizer; -import org.simantics.scl.compiler.elaboration.chr.plan.PrioritizedPlan; -import org.simantics.scl.compiler.elaboration.chr.relations.CHRConstraint; -import org.simantics.scl.compiler.elaboration.contexts.SimplificationContext; -import org.simantics.scl.compiler.elaboration.contexts.TranslationContext; -import org.simantics.scl.compiler.elaboration.contexts.TypingContext; -import org.simantics.scl.compiler.elaboration.expressions.Variable; -import org.simantics.scl.compiler.elaboration.expressions.VariableProcedure; -import org.simantics.scl.compiler.errors.Locations; -import org.simantics.scl.compiler.internal.codegen.chr.CHRCodeGenerator; -import org.simantics.scl.compiler.internal.codegen.references.BoundVar; -import org.simantics.scl.compiler.internal.codegen.references.IVal; -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.TVar; -import org.simantics.scl.compiler.types.Type; -import org.simantics.scl.compiler.types.Types; - -import gnu.trove.map.hash.TObjectIntHashMap; -import gnu.trove.set.hash.THashSet; -import gnu.trove.set.hash.TIntHashSet; - -public class CHRRuleset extends Symbol { - - public static final String INIT_CONSTRAINT = "__INIT__"; - - public ArrayList constraints = new ArrayList(); - public ArrayList rules = new ArrayList(); - - public CHRConstraint initConstraint; - public int priorityCount; - - public String storeClassName; - public TCon storeType; - public BoundVar storeVariable; - public TypeDesc storeTypeDesc; - public Constant activateProcedure; - public Constant readCurrentId; - public Constant writeCurrentId; - - // FIXME remove and change the parameter of Expression.toVal - private CompilationContext cachedContext; - - // For code generation - public BoundVar this_; - public BoundVar[] parameters; - public TypeDesc[] parameterTypeDescs; - - public CHRRuleset() { - initConstraint = new CHRConstraint(Locations.NO_LOCATION, INIT_CONSTRAINT, Type.EMPTY_ARRAY); - constraints.add(initConstraint); - } - - public void resolve(TranslationContext context) { - for(CHRConstraint constraint : constraints) - context.newCHRConstraint(constraint.name, constraint); - priorityCount = 0; - for(CHRRule rule : rules) { - rule.resolve(context); - rule.priority = priorityCount++; - } - /*for(CHRConstraint constraint : constraints) { - Variable newVariable = context.newVariable("claim" + constraint.factClassName); - }*/ - } - - public void collectRefs(TObjectIntHashMap allRefs, TIntHashSet refs) { - for(CHRRule rule : rules) - rule.collectRefs(allRefs, refs); - } - - public void checkType(TypingContext context) { - for(CHRRule rule : rules) - rule.checkType(context); - } - - public void collectVars(TObjectIntHashMap allVars, TIntHashSet vars) { - for(CHRRule rule : rules) - rule.collectVars(allVars, vars); - } - - public void forVariables(VariableProcedure procedure) { - for(CHRRule rule : rules) - rule.forVariables(procedure); - } - - public void collectFreeVariables(THashSet vars) { - for(CHRRule rule : rules) - rule.collectFreeVariables(vars); - } - - public void setLocationDeep(long loc) { - if(location == Locations.NO_LOCATION) { - this.location = loc; - for(CHRRule rule : rules) - rule.setLocationDeep(loc); - } - } - - public void compile(SimplificationContext context) { - initializeCodeGeneration(context.getCompilationContext()); - UsageAnalysis.analyzeUsage(this); - for(CHRRule rule : rules) - rule.compile(context.getCompilationContext(), initConstraint); - // remove init constraint if it is not useful - if(initConstraint.plans.isEmpty()) { - constraints.remove(0); - initConstraint = null; - } - for(CHRConstraint constraint : constraints) { - constraint.plans.sort((PrioritizedPlan a, PrioritizedPlan b) -> { - return Integer.compare(a.priority, b.priority); - }); - /*System.out.println(constraint.name); - for(PrioritizedPlan plan : constraint.plans) { - System.out.println(" priority " + plan.priority); - for(PlanOp op : plan.ops) - System.out.println(" " + op); - }*/ - } - } - - public void simplify(SimplificationContext context) { - for(CHRRule rule : rules) - rule.simplify(context); - } - - public void initializeCodeGeneration(CompilationContext context) { - cachedContext = context; // FIXME remove - - String suffix = context.namingPolicy.getFreshClosureClassNameSuffix(); - storeType = Types.con(context.namingPolicy.getModuleName(), "CHR" + suffix); - storeClassName = context.namingPolicy.getModuleClassName() + suffix; - storeTypeDesc = TypeDesc.forClass(storeClassName); - storeVariable = new BoundVar(storeType); - for(CHRConstraint constraint : constraints) - constraint.initializeCodeGeneration(context, this); - activateProcedure = new JavaMethod(true, storeClassName, "activate", Types.PROC, Types.UNIT, storeType, Types.INTEGER); - readCurrentId = new CallJava(TVar.EMPTY_ARRAY, Types.PROC, Types.INTEGER, new Type[] {storeType}, - null, new FieldRef(storeClassName, "currentId", CHRCodeGenerator.FACT_ID_TYPE), null); - writeCurrentId = new CallJava(TVar.EMPTY_ARRAY, Types.PROC, Types.UNIT, new Type[] {storeType, Types.INTEGER}, - null, new SetFieldRef(storeClassName, "currentId", CHRCodeGenerator.FACT_ID_TYPE), null); - if(context.module != null) // for unit testing - context.module.addTypeDescriptor(storeType.name, new StandardTypeConstructor(storeType, TVar.EMPTY_ARRAY, storeTypeDesc)); - } - - public void generateCode(CodeWriter w) { - CHRRulesetObject object = new CHRRulesetObject(storeVariable, this); - w.defineObject(object); - for(CHRConstraint constraint : constraints) { - //System.out.println(constraint); - for(PrioritizedPlan plan : constraint.plans) { - /*System.out.println(" plan " + plan.priority); - for(PlanOp planOp : plan.ops) - System.out.println(" " + planOp);*/ - PlanRealizer realizer = new PlanRealizer(cachedContext, this, storeVariable, plan.ops); - CodeWriter methodWriter = object.createMethod(w.getModuleWriter(), TVar.EMPTY_ARRAY, Types.PROC, Types.BOOLEAN, new Type[] {constraint.factType}); - plan.implementation = methodWriter.getFunction(); - plan.activeFact.setVal(methodWriter.getParameters()[0]); - realizer.nextOp(methodWriter); - if(methodWriter.isUnfinished()) - methodWriter.return_(BooleanConstant.TRUE); - } - } - if(initConstraint != null) { - IVal initFact = w.apply(location, initConstraint.constructor, IntegerConstant.ZERO); - w.apply(location, initConstraint.addProcedure, storeVariable, initFact); - w.apply(location, activateProcedure, storeVariable, new IntegerConstant(Integer.MAX_VALUE)); - } - } - - public void collectEffects(THashSet effects) { - for(CHRRule rule : rules) { - for(CHRLiteral literal : rule.head.literals) - literal.collectQueryEffects(effects); - for(CHRLiteral literal : rule.head.literals) - literal.collectEnforceEffects(effects); - } - } -} +package org.simantics.scl.compiler.elaboration.chr; + +import java.util.ArrayList; + +import org.cojen.classfile.TypeDesc; +import org.simantics.scl.compiler.compilation.CompilationContext; +import org.simantics.scl.compiler.constants.BooleanConstant; +import org.simantics.scl.compiler.constants.Constant; +import org.simantics.scl.compiler.constants.IntegerConstant; +import org.simantics.scl.compiler.constants.JavaConstructor; +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.FieldRef; +import org.simantics.scl.compiler.constants.generic.MethodRef.SetFieldRef; +import org.simantics.scl.compiler.elaboration.chr.analysis.CHRConstraintGGInfo; +import org.simantics.scl.compiler.elaboration.chr.analysis.UsageAnalysis; +import org.simantics.scl.compiler.elaboration.chr.plan.CHRSearchPlan; +import org.simantics.scl.compiler.elaboration.chr.plan.PlanRealizer; +import org.simantics.scl.compiler.elaboration.chr.relations.CHRConstraint; +import org.simantics.scl.compiler.elaboration.contexts.SimplificationContext; +import org.simantics.scl.compiler.elaboration.contexts.TranslationContext; +import org.simantics.scl.compiler.elaboration.contexts.TypingContext; +import org.simantics.scl.compiler.elaboration.expressions.Variable; +import org.simantics.scl.compiler.elaboration.expressions.VariableProcedure; +import org.simantics.scl.compiler.elaboration.expressions.block.IncludeStatement; +import org.simantics.scl.compiler.environment.AmbiguousNameException; +import org.simantics.scl.compiler.errors.Locations; +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.BoundVar; +import org.simantics.scl.compiler.internal.codegen.references.IVal; +import org.simantics.scl.compiler.internal.codegen.ssa.SSAFunction; +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.TVar; +import org.simantics.scl.compiler.types.Type; +import org.simantics.scl.compiler.types.Types; +import org.simantics.scl.runtime.chr.CHRContext; + +import gnu.trove.map.hash.THashMap; +import gnu.trove.map.hash.TObjectIntHashMap; +import gnu.trove.set.hash.THashSet; +import gnu.trove.set.hash.TIntHashSet; + +public class CHRRuleset extends Symbol { + + public static final String INIT_CONSTRAINT = "__INIT__"; + + public ArrayList constraints = new ArrayList(); + public ArrayList rules = new ArrayList(); + public ArrayList includes = new ArrayList(); + public THashMap constraintSourceMap = new THashMap(); + public THashMap activeConstraintGGInfo = new THashMap(); // contains also imported constraints + public THashMap> inverseActiveConstraintSourceMap = new THashMap>(); + + public boolean extensible; + + public CHRConstraint initConstraint; + public int priorityCount; + + public int initialPriorityNumber = 0; + + public String runtimeRulesetClassName; + public TCon runtimeRulesetType; + public BoundVar runtimeRulesetVariable; + public TypeDesc runtimeRulesetTypeDesc; + public Constant readCurrentId; + public Constant writeCurrentId; + + // FIXME remove and change the parameter of Expression.toVal + private CompilationContext cachedContext; + + // For code generation + public CHRRulesetObject rulesetObject; + public SSAFunction initializer; + public SSAFunction deinitializer; + + public CHRRuleset() { + initConstraint = new CHRConstraint(Locations.NO_LOCATION, INIT_CONSTRAINT, Type.EMPTY_ARRAY); + constraints.add(initConstraint); + } + + public void resolve(TranslationContext context) { + boolean failedIncludes = false; + for(IncludeStatement include : includes) { + try { + include.ruleset = context.resolveRuleset(include.name.text); + if(include.ruleset == null) { + failedIncludes = true; + context.getErrorLog().log(include.name.location, "Couldn't resolve ruleset " + include.name + "."); + continue; + } + include.value = include.value.resolve(context); + for(CHRConstraint constraint : include.ruleset.constraints) { + context.newCHRConstraint(constraint.name, constraint); + constraintSourceMap.put(constraint, include); + } + } catch (AmbiguousNameException e) { + failedIncludes = true; + context.getErrorLog().log(include.name.location, e.getMessage()); + } + } + if(failedIncludes) + return; + for(CHRConstraint constraint : constraints) + context.newCHRConstraint(constraint.name, constraint); + priorityCount = 0; + for(CHRRule rule : rules) { + rule.resolve(context); + rule.priority = priorityCount++; + } + /*for(CHRConstraint constraint : constraints) { + Variable newVariable = context.newVariable("claim" + constraint.factClassName); + }*/ + } + + public void collectRefs(TObjectIntHashMap allRefs, TIntHashSet refs) { + for(IncludeStatement include : includes) + include.value.collectRefs(allRefs, refs); + for(CHRRule rule : rules) + rule.collectRefs(allRefs, refs); + } + + public void checkType(TypingContext context) { + for(IncludeStatement include : includes) + include.value = include.value.checkType(context, include.ruleset.runtimeRulesetType); + for(CHRRule rule : rules) + rule.checkType(context); + } + + public void collectVars(TObjectIntHashMap allVars, TIntHashSet vars) { + for(IncludeStatement include : includes) + include.value.collectVars(allVars, vars); + for(CHRRule rule : rules) + rule.collectVars(allVars, vars); + } + + public void forVariables(VariableProcedure procedure) { + for(IncludeStatement include : includes) + include.value.forVariables(procedure); + for(CHRRule rule : rules) + rule.forVariables(procedure); + } + + public void collectFreeVariables(THashSet vars) { + for(IncludeStatement include : includes) + include.value.collectFreeVariables(vars); + for(CHRRule rule : rules) + rule.collectFreeVariables(vars); + } + + public void setLocationDeep(long loc) { + if(location == Locations.NO_LOCATION) { + this.location = loc; + for(CHRRule rule : rules) + rule.setLocationDeep(loc); + } + } + + public int getMinimumPriority(CHRConstraint constraint) { + CHRConstraintGGInfo info = activeConstraintGGInfo.get(constraint); + if(info == null) + return Integer.MAX_VALUE; + else + return info.minimumPriority; + } + + public int getAndUpdateNextPriority(CHRConstraint constraint, int nextPriority) { + CHRConstraintGGInfo info = activeConstraintGGInfo.get(constraint); + if(info == null) + return Integer.MAX_VALUE; + else { + int result = info.nextPriority; + info.nextPriority = nextPriority; + return result; + } + } + + public void compile(SimplificationContext context) { + initializeCodeGeneration(context.getCompilationContext()); + if(extensible) + applyExtensibleDefaults(); + UsageAnalysis.analyzeUsage(this); + for(CHRRule rule : rules) { + rule.compile(context.getCompilationContext(), initConstraint); + for(CHRSearchPlan plan : rule.plans) { + CHRConstraint constraint = plan.constraint; + if(!activeConstraintGGInfo.containsKey(constraint)) { + activeConstraintGGInfo.put(constraint, new CHRConstraintGGInfo(rule.priority)); + IncludeStatement include = constraintSourceMap.get(constraint); + if(include != null) { + ArrayList list = inverseActiveConstraintSourceMap.get(include); + if(list == null) { + list = new ArrayList(4); + inverseActiveConstraintSourceMap.put(include, list); + } + list.add(constraint); + } + } + } + } + // remove init constraint if it is not useful + if(getMinimumPriority(initConstraint) == Integer.MAX_VALUE) { + constraints.remove(0); + initConstraint = null; + } + } + + private void applyExtensibleDefaults() { + for(CHRConstraint constraint : constraints) { + // FIXME Too much indexing!!! + int max = 1 << constraint.parameterTypes.length; + for(int i=0;i 0) + constraint.getOrCreateIndex(cachedContext, 1);*/ + } + } + + public void simplify(SimplificationContext context) { + for(IncludeStatement include : includes) + include.value = include.value.simplify(context); + for(CHRRule rule : rules) + rule.simplify(context); + } + + public void setRulesetType(TCon type, String className) { + this.runtimeRulesetType = type; + this.runtimeRulesetClassName = className; + } + + public void initializeCodeGeneration(CompilationContext context) { + cachedContext = context; // FIXME remove + + boolean createTypeDesc = false; + if(runtimeRulesetType == null) { + String suffix = context.namingPolicy.getFreshClosureClassNameSuffix(); + setRulesetType(Types.con(context.namingPolicy.getModuleName(), "CHR" + suffix), context.namingPolicy.getModuleClassName() + suffix); + createTypeDesc = true; + } + runtimeRulesetTypeDesc = TypeDesc.forClass(runtimeRulesetClassName); + runtimeRulesetVariable = new BoundVar(runtimeRulesetType); + for(CHRConstraint constraint : constraints) + constraint.initializeCodeGeneration(context, this); + readCurrentId = new CallJava(TVar.EMPTY_ARRAY, Types.PROC, Types.INTEGER, new Type[] {Types.CHRContext}, + null, new FieldRef(CHRCodeGenerationConstants.CHRContext_name, "currentId", CHRRuntimeRulesetCodeGenerator.FACT_ID_TYPE), null); + writeCurrentId = new CallJava(TVar.EMPTY_ARRAY, Types.PROC, Types.UNIT, new Type[] {Types.CHRContext, Types.INTEGER}, + null, new SetFieldRef(CHRCodeGenerationConstants.CHRContext_name, "currentId", CHRRuntimeRulesetCodeGenerator.FACT_ID_TYPE), null); + if(createTypeDesc && context.module != null) // for unit testing + context.module.addTypeDescriptor(runtimeRulesetType.name, new StandardTypeConstructor(runtimeRulesetType, TVar.EMPTY_ARRAY, runtimeRulesetTypeDesc)); + } + + public static final Constant ACTIVATE = new JavaMethod(true, CHRCodeGenerationConstants.CHRContext_name, "activate", Types.PROC, Types.UNIT, Types.CHRContext, Types.INTEGER); + private static final Constant CREATE_CHR_CONTEXT = new JavaConstructor("org/simantics/scl/runtime/chr/CHRContext", Types.PROC, Types.CHRContext); + + public IVal generateCode(CodeWriter w) { + for(IncludeStatement include : includes) { + include.storeVar = include.value.toVal(cachedContext.environment, w); + initialPriorityNumber = Math.max(initialPriorityNumber, include.ruleset.initialPriorityNumber + include.ruleset.priorityCount); + } + CHRRulesetObject object = new CHRRulesetObject(runtimeRulesetVariable, this); + w.defineObject(object); + for(CHRRule rule : rules) { + for(CHRSearchPlan plan : rule.plans) { + /*System.out.println(" plan " + plan.priority); + for(PlanOp planOp : plan.ops) + System.out.println(" " + planOp);*/ + CodeWriter methodWriter = object.createMethod(w.getModuleWriter(), TVar.EMPTY_ARRAY, Types.PROC, Types.BOOLEAN, new Type[] {Types.CHRContext, plan.constraint.factType}); + plan.implementation = methodWriter.getFunction(); + IVal[] implementationParameters = methodWriter.getParameters(); + plan.activeFact.setVal(implementationParameters[1]); + PlanRealizer realizer = new PlanRealizer(cachedContext, this, runtimeRulesetVariable, implementationParameters[0], plan.ops); + realizer.nextOp(methodWriter); + if(methodWriter.isUnfinished()) + methodWriter.return_(BooleanConstant.TRUE); + } + } + if(!includes.isEmpty()) { + { + CodeWriter methodWriter = object.createMethod(w.getModuleWriter(), TVar.EMPTY_ARRAY, Types.PROC, Types.UNIT, new Type[] {Types.CHRContext}); + initializer = methodWriter.getFunction(); + for(IncludeStatement include : includes) { + methodWriter.apply(include.location, + new JavaMethod(true, runtimeRulesetClassName, "register", Types.PROC, Types.UNIT, new Type[] {runtimeRulesetType, Types.CHRContext, include.ruleset.runtimeRulesetType}), + object.getTarget(), methodWriter.getParameters()[0], include.storeVar); + } + methodWriter.return_(NoRepConstant.UNIT); + } + { + CodeWriter methodWriter = object.createMethod(w.getModuleWriter(), TVar.EMPTY_ARRAY, Types.PROC, Types.UNIT, new Type[] {Types.CHRContext}); + deinitializer = methodWriter.getFunction(); + for(IncludeStatement include : includes) { + methodWriter.apply(include.location, + new JavaMethod(true, runtimeRulesetClassName, "unregister", Types.PROC, Types.UNIT, new Type[] {runtimeRulesetType, Types.CHRContext, include.ruleset.runtimeRulesetType}), + object.getTarget(), methodWriter.getParameters()[0], include.storeVar); + } + methodWriter.return_(NoRepConstant.UNIT); + } + } + if(initConstraint != null) { + IVal chrContext = w.apply(location, CREATE_CHR_CONTEXT); + if(initializer != null) { + w.apply(location, + new JavaMethod(true, runtimeRulesetClassName, "initialize", Types.PROC, Types.UNIT, new Type[] {runtimeRulesetType, Types.CHRContext}), + object.getTarget(), chrContext); + } + IVal initFact = w.apply(location, initConstraint.constructor, IntegerConstant.ZERO); + w.apply(location, initConstraint.addProcedure, runtimeRulesetVariable, chrContext, initFact); + w.apply(location, ACTIVATE, chrContext, new IntegerConstant(Integer.MAX_VALUE)); + if(deinitializer != null) { + w.apply(location, + new JavaMethod(true, runtimeRulesetClassName, "deinitialize", Types.PROC, Types.UNIT, new Type[] {runtimeRulesetType, Types.CHRContext}), + object.getTarget(), chrContext); + } + } + return runtimeRulesetVariable; + } + + public void collectEffects(THashSet effects) { + for(CHRRule rule : rules) { + for(CHRLiteral literal : rule.head.literals) + literal.collectQueryEffects(effects); + for(CHRLiteral literal : rule.head.literals) + literal.collectEnforceEffects(effects); + } + } +}