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); } } }