(refs #7250) Refactoring CHR implementation
[simantics/platform.git] / bundles / org.simantics.scl.compiler / src / org / simantics / scl / compiler / elaboration / chr / CHRRuleset.java
1 package org.simantics.scl.compiler.elaboration.chr;
2
3 import java.util.ArrayList;
4
5 import org.cojen.classfile.TypeDesc;
6 import org.simantics.scl.compiler.compilation.CompilationContext;
7 import org.simantics.scl.compiler.constants.BooleanConstant;
8 import org.simantics.scl.compiler.constants.Constant;
9 import org.simantics.scl.compiler.constants.IntegerConstant;
10 import org.simantics.scl.compiler.constants.JavaConstructor;
11 import org.simantics.scl.compiler.constants.JavaMethod;
12 import org.simantics.scl.compiler.constants.generic.CallJava;
13 import org.simantics.scl.compiler.constants.generic.MethodRef.FieldRef;
14 import org.simantics.scl.compiler.constants.generic.MethodRef.SetFieldRef;
15 import org.simantics.scl.compiler.elaboration.chr.analysis.UsageAnalysis;
16 import org.simantics.scl.compiler.elaboration.chr.plan.CHRSearchPlan;
17 import org.simantics.scl.compiler.elaboration.chr.plan.PlanRealizer;
18 import org.simantics.scl.compiler.elaboration.chr.relations.CHRConstraint;
19 import org.simantics.scl.compiler.elaboration.contexts.SimplificationContext;
20 import org.simantics.scl.compiler.elaboration.contexts.TranslationContext;
21 import org.simantics.scl.compiler.elaboration.contexts.TypingContext;
22 import org.simantics.scl.compiler.elaboration.expressions.Variable;
23 import org.simantics.scl.compiler.elaboration.expressions.VariableProcedure;
24 import org.simantics.scl.compiler.errors.Locations;
25 import org.simantics.scl.compiler.internal.codegen.chr.CHRCodeGenerationConstants;
26 import org.simantics.scl.compiler.internal.codegen.chr.CHRRuntimeRulesetCodeGenerator;
27 import org.simantics.scl.compiler.internal.codegen.references.BoundVar;
28 import org.simantics.scl.compiler.internal.codegen.references.IVal;
29 import org.simantics.scl.compiler.internal.codegen.types.StandardTypeConstructor;
30 import org.simantics.scl.compiler.internal.codegen.writer.CodeWriter;
31 import org.simantics.scl.compiler.internal.parsing.Symbol;
32 import org.simantics.scl.compiler.types.TCon;
33 import org.simantics.scl.compiler.types.TVar;
34 import org.simantics.scl.compiler.types.Type;
35 import org.simantics.scl.compiler.types.Types;
36
37 import gnu.trove.map.hash.TObjectIntHashMap;
38 import gnu.trove.set.hash.THashSet;
39 import gnu.trove.set.hash.TIntHashSet;
40
41 public class CHRRuleset extends Symbol {
42     
43     public static final String INIT_CONSTRAINT = "__INIT__";
44     
45     public ArrayList<CHRConstraint> constraints = new ArrayList<CHRConstraint>();
46     public ArrayList<CHRRule> rules = new ArrayList<CHRRule>();
47     
48     public CHRConstraint initConstraint;
49     public int priorityCount;
50     
51     public String runtimeRulesetName;
52     public TCon runtimeRulesetType;
53     public BoundVar runtimeRulesetVariable;
54     public TypeDesc runtimeRulesetTypeDesc;
55     public Constant readCurrentId;
56     public Constant writeCurrentId;
57     
58     // FIXME remove and change the parameter of Expression.toVal
59     private CompilationContext cachedContext;
60     
61     // For code generation
62     public BoundVar this_;
63     public BoundVar[] parameters;
64     public TypeDesc[] parameterTypeDescs;
65     
66     public CHRRuleset() {
67         initConstraint = new CHRConstraint(Locations.NO_LOCATION, INIT_CONSTRAINT, Type.EMPTY_ARRAY);
68         constraints.add(initConstraint);
69     }
70     
71     public void resolve(TranslationContext context) {
72         for(CHRConstraint constraint : constraints)
73             context.newCHRConstraint(constraint.name, constraint);
74         priorityCount = 0;
75         for(CHRRule rule : rules) {
76             rule.resolve(context);
77             rule.priority = priorityCount++;
78         }
79         /*for(CHRConstraint constraint : constraints) {
80             Variable newVariable = context.newVariable("claim" + constraint.factClassName);
81         }*/
82     }
83
84     public void collectRefs(TObjectIntHashMap<Object> allRefs, TIntHashSet refs) {
85         for(CHRRule rule : rules)
86             rule.collectRefs(allRefs, refs);
87     }
88
89     public void checkType(TypingContext context) {
90         for(CHRRule rule : rules)
91             rule.checkType(context);
92     }
93
94     public void collectVars(TObjectIntHashMap<Variable> allVars, TIntHashSet vars) {
95         for(CHRRule rule : rules)
96             rule.collectVars(allVars, vars);
97     }
98
99     public void forVariables(VariableProcedure procedure) {
100         for(CHRRule rule : rules)
101             rule.forVariables(procedure);
102     }
103
104     public void collectFreeVariables(THashSet<Variable> vars) {
105         for(CHRRule rule : rules)
106             rule.collectFreeVariables(vars);
107     }
108
109     public void setLocationDeep(long loc) {
110         if(location == Locations.NO_LOCATION) {
111             this.location = loc;
112             for(CHRRule rule : rules)
113                 rule.setLocationDeep(loc);
114         }
115     }
116
117     public void compile(SimplificationContext context) {
118         initializeCodeGeneration(context.getCompilationContext());
119         UsageAnalysis.analyzeUsage(this);
120         for(CHRRule rule : rules)
121             rule.compile(context.getCompilationContext(), initConstraint);
122         // remove init constraint if it is not useful
123         if(initConstraint.minimumPriority == Integer.MAX_VALUE) {
124             constraints.remove(0);
125             initConstraint = null;
126         }
127     }
128
129     public void simplify(SimplificationContext context) {
130         for(CHRRule rule : rules)
131             rule.simplify(context);
132     }
133     
134     public void initializeCodeGeneration(CompilationContext context) {
135         cachedContext = context; // FIXME remove
136         
137         String suffix = context.namingPolicy.getFreshClosureClassNameSuffix();
138         runtimeRulesetType = Types.con(context.namingPolicy.getModuleName(), "CHR" + suffix);
139         runtimeRulesetName = context.namingPolicy.getModuleClassName() + suffix;
140         runtimeRulesetTypeDesc = TypeDesc.forClass(runtimeRulesetName);
141         runtimeRulesetVariable = new BoundVar(runtimeRulesetType);
142         for(CHRConstraint constraint : constraints)
143             constraint.initializeCodeGeneration(context, this);
144         readCurrentId = new CallJava(TVar.EMPTY_ARRAY, Types.PROC, Types.INTEGER, new Type[] {Types.CHRContext},
145                 null, new FieldRef(CHRCodeGenerationConstants.CHRContext_name, "currentId", CHRRuntimeRulesetCodeGenerator.FACT_ID_TYPE), null);
146         writeCurrentId = new CallJava(TVar.EMPTY_ARRAY, Types.PROC, Types.UNIT, new Type[] {Types.CHRContext, Types.INTEGER},
147                 null, new SetFieldRef(CHRCodeGenerationConstants.CHRContext_name, "currentId", CHRRuntimeRulesetCodeGenerator.FACT_ID_TYPE), null);
148         if(context.module != null) // for unit testing
149             context.module.addTypeDescriptor(runtimeRulesetType.name, new StandardTypeConstructor(runtimeRulesetType, TVar.EMPTY_ARRAY, runtimeRulesetTypeDesc));
150     }
151
152     public static final Constant ACTIVATE = new JavaMethod(true, CHRCodeGenerationConstants.CHRContext_name, "activate", Types.PROC, Types.UNIT, Types.CHRContext, Types.INTEGER);
153     private static final Constant CREATE_CHR_CONTEXT = new JavaConstructor("org/simantics/scl/runtime/chr/CHRContext", Types.PROC, Types.CHRContext);
154     
155     public void generateCode(CodeWriter w) {
156         CHRRulesetObject object = new CHRRulesetObject(runtimeRulesetVariable, this);
157         w.defineObject(object);
158         for(CHRRule rule : rules) {
159             for(CHRSearchPlan plan : rule.plans) {
160                 /*System.out.println("    plan " + plan.priority);
161                 for(PlanOp planOp : plan.ops)
162                     System.out.println("        " + planOp);*/
163                 CodeWriter methodWriter = object.createMethod(w.getModuleWriter(), TVar.EMPTY_ARRAY, Types.PROC, Types.BOOLEAN, new Type[] {Types.CHRContext, plan.constraint.factType});
164                 plan.implementation = methodWriter.getFunction();
165                 IVal[] implementationParameters = methodWriter.getParameters();
166                 plan.activeFact.setVal(implementationParameters[1]);
167                 PlanRealizer realizer = new PlanRealizer(cachedContext, this, runtimeRulesetVariable, implementationParameters[0], plan.ops);
168                 realizer.nextOp(methodWriter);
169                 if(methodWriter.isUnfinished())
170                     methodWriter.return_(BooleanConstant.TRUE);
171             }
172         }
173         if(initConstraint != null) {
174             IVal chrContext = w.apply(location, CREATE_CHR_CONTEXT);
175             IVal initFact = w.apply(location, initConstraint.constructor, IntegerConstant.ZERO);
176             w.apply(location, initConstraint.addProcedure, runtimeRulesetVariable, chrContext, initFact);
177             w.apply(location, ACTIVATE, chrContext, new IntegerConstant(Integer.MAX_VALUE));
178         }
179     }
180
181     public void collectEffects(THashSet<Type> effects) {
182         for(CHRRule rule : rules) {
183             for(CHRLiteral literal : rule.head.literals)
184                 literal.collectQueryEffects(effects);
185             for(CHRLiteral literal : rule.head.literals)
186                 literal.collectEnforceEffects(effects);
187         }
188     }
189 }