1 package org.simantics.scl.compiler.elaboration.chr;
3 import java.util.ArrayList;
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.NoRepConstant;
13 import org.simantics.scl.compiler.constants.generic.CallJava;
14 import org.simantics.scl.compiler.constants.generic.MethodRef.FieldRef;
15 import org.simantics.scl.compiler.constants.generic.MethodRef.ObjectMethodRef;
16 import org.simantics.scl.compiler.constants.generic.MethodRef.SetFieldRef;
17 import org.simantics.scl.compiler.elaboration.chr.analysis.CHRConstraintGGInfo;
18 import org.simantics.scl.compiler.elaboration.chr.analysis.UsageAnalysis;
19 import org.simantics.scl.compiler.elaboration.chr.plan.CHRSearchPlan;
20 import org.simantics.scl.compiler.elaboration.chr.plan.PlanRealizer;
21 import org.simantics.scl.compiler.elaboration.chr.relations.CHRConstraint;
22 import org.simantics.scl.compiler.elaboration.contexts.SimplificationContext;
23 import org.simantics.scl.compiler.elaboration.contexts.TranslationContext;
24 import org.simantics.scl.compiler.elaboration.contexts.TypingContext;
25 import org.simantics.scl.compiler.elaboration.expressions.Variable;
26 import org.simantics.scl.compiler.elaboration.expressions.block.IncludeStatement;
27 import org.simantics.scl.compiler.environment.AmbiguousNameException;
28 import org.simantics.scl.compiler.errors.Locations;
29 import org.simantics.scl.compiler.internal.codegen.chr.CHRCodeGenerationConstants;
30 import org.simantics.scl.compiler.internal.codegen.chr.CHRRuntimeRulesetCodeGenerator;
31 import org.simantics.scl.compiler.internal.codegen.references.BoundVar;
32 import org.simantics.scl.compiler.internal.codegen.references.IVal;
33 import org.simantics.scl.compiler.internal.codegen.ssa.SSAFunction;
34 import org.simantics.scl.compiler.internal.codegen.types.StandardTypeConstructor;
35 import org.simantics.scl.compiler.internal.codegen.utils.Constants;
36 import org.simantics.scl.compiler.internal.codegen.writer.CodeWriter;
37 import org.simantics.scl.compiler.internal.parsing.Symbol;
38 import org.simantics.scl.compiler.types.TCon;
39 import org.simantics.scl.compiler.types.TVar;
40 import org.simantics.scl.compiler.types.Type;
41 import org.simantics.scl.compiler.types.Types;
43 import gnu.trove.map.hash.THashMap;
44 import gnu.trove.map.hash.TObjectIntHashMap;
45 import gnu.trove.set.hash.THashSet;
46 import gnu.trove.set.hash.TIntHashSet;
48 public class CHRRuleset extends Symbol {
50 public static final String INIT_CONSTRAINT = "__INIT__";
52 public ArrayList<CHRConstraint> constraints = new ArrayList<CHRConstraint>();
53 public ArrayList<CHRRule> rules = new ArrayList<CHRRule>();
54 public ArrayList<IncludeStatement> includes = new ArrayList<IncludeStatement>();
55 public THashMap<CHRConstraint, IncludeStatement> constraintSourceMap = new THashMap<CHRConstraint, IncludeStatement>();
56 public THashMap<CHRConstraint, CHRConstraintGGInfo> activeConstraintGGInfo = new THashMap<CHRConstraint, CHRConstraintGGInfo>(); // contains also imported constraints
57 public THashMap<IncludeStatement, ArrayList<CHRConstraint>> inverseActiveConstraintSourceMap = new THashMap<IncludeStatement, ArrayList<CHRConstraint>>();
59 public boolean extensible;
61 public CHRConstraint initConstraint;
62 public int priorityCount;
64 public int initialPriorityNumber = 0;
66 public String runtimeRulesetClassName;
67 public TCon runtimeRulesetType;
68 public BoundVar runtimeRulesetVariable;
69 public TypeDesc runtimeRulesetTypeDesc;
71 public static final Constant READ_CURRENT_ID = new CallJava(TVar.EMPTY_ARRAY, Types.PROC, Types.INTEGER, new Type[] {Types.CHRContext},
72 null, new FieldRef(CHRCodeGenerationConstants.CHRContext_name, "currentId", CHRRuntimeRulesetCodeGenerator.FACT_ID_TYPE), null);
73 public static final Constant WRITE_CURRENT_ID = new CallJava(TVar.EMPTY_ARRAY, Types.PROC, Types.UNIT, new Type[] {Types.CHRContext, Types.INTEGER},
74 null, new SetFieldRef(CHRCodeGenerationConstants.CHRContext_name, "currentId", CHRRuntimeRulesetCodeGenerator.FACT_ID_TYPE), null);
75 public static final Constant GENERATE_ID = new CallJava(TVar.EMPTY_ARRAY, Types.PROC, Types.INTEGER, new Type[] {Types.CHRContext},
76 null, new ObjectMethodRef(false, CHRCodeGenerationConstants.CHRContext_name, "generateId", CHRRuntimeRulesetCodeGenerator.FACT_ID_TYPE, Constants.EMPTY_TYPEDESC_ARRAY), null);
78 // FIXME remove and change the parameter of Expression.toVal
79 private CompilationContext cachedContext;
81 // For code generation
82 public CHRRulesetObject rulesetObject;
83 public SSAFunction initializer;
84 public SSAFunction deinitializer;
87 initConstraint = new CHRConstraint(Locations.NO_LOCATION, INIT_CONSTRAINT, Type.EMPTY_ARRAY);
88 constraints.add(initConstraint);
91 public void resolve(TranslationContext context) {
92 boolean failedIncludes = false;
93 for(IncludeStatement include : includes) {
95 include.ruleset = context.resolveRuleset(include.name.text);
96 if(include.ruleset == null) {
97 failedIncludes = true;
98 context.getErrorLog().log(include.name.location, "Couldn't resolve ruleset " + include.name + ".");
101 include.value = include.value.resolve(context);
102 for(CHRConstraint constraint : include.ruleset.constraints) {
103 context.newCHRConstraint(constraint.name, constraint);
104 constraintSourceMap.put(constraint, include);
106 } catch (AmbiguousNameException e) {
107 failedIncludes = true;
108 context.getErrorLog().log(include.name.location, e.getMessage());
113 for(CHRConstraint constraint : constraints)
114 context.newCHRConstraint(constraint.name, constraint);
116 for(CHRRule rule : rules) {
117 rule.resolve(context);
118 rule.priority = priorityCount++;
120 /*for(CHRConstraint constraint : constraints) {
121 Variable newVariable = context.newVariable("claim" + constraint.factClassName);
125 public void collectRefs(TObjectIntHashMap<Object> allRefs, TIntHashSet refs) {
126 for(IncludeStatement include : includes)
127 include.value.collectRefs(allRefs, refs);
128 for(CHRRule rule : rules)
129 rule.collectRefs(allRefs, refs);
132 public void checkType(TypingContext context) {
133 for(IncludeStatement include : includes)
134 include.value = include.value.checkType(context, include.ruleset.runtimeRulesetType);
135 for(CHRRule rule : rules)
136 rule.checkType(context);
139 public void collectVars(TObjectIntHashMap<Variable> allVars, TIntHashSet vars) {
140 for(IncludeStatement include : includes)
141 include.value.collectVars(allVars, vars);
142 for(CHRRule rule : rules)
143 rule.collectVars(allVars, vars);
146 public void collectFreeVariables(THashSet<Variable> vars) {
147 for(IncludeStatement include : includes)
148 include.value.collectFreeVariables(vars);
149 for(CHRRule rule : rules)
150 rule.collectFreeVariables(vars);
153 public void setLocationDeep(long loc) {
154 if(location == Locations.NO_LOCATION) {
156 for(CHRRule rule : rules)
157 rule.setLocationDeep(loc);
161 public int getMinimumPriority(CHRConstraint constraint) {
162 CHRConstraintGGInfo info = activeConstraintGGInfo.get(constraint);
164 return Integer.MAX_VALUE;
166 return info.minimumPriority;
169 public int getAndUpdateNextPriority(CHRConstraint constraint, int nextPriority) {
170 CHRConstraintGGInfo info = activeConstraintGGInfo.get(constraint);
172 return Integer.MAX_VALUE;
174 int result = info.nextPriority;
175 info.nextPriority = nextPriority;
180 public void compile(SimplificationContext context) {
181 initializeCodeGeneration(context.getCompilationContext());
183 applyExtensibleDefaults();
184 UsageAnalysis.analyzeUsage(this);
185 for(CHRRule rule : rules) {
186 rule.compile(context.getCompilationContext(), initConstraint);
187 for(CHRSearchPlan plan : rule.plans) {
188 CHRConstraint constraint = plan.constraint;
189 if(!activeConstraintGGInfo.containsKey(constraint)) {
190 activeConstraintGGInfo.put(constraint, new CHRConstraintGGInfo(rule.priority));
191 IncludeStatement include = constraintSourceMap.get(constraint);
192 if(include != null) {
193 ArrayList<CHRConstraint> list = inverseActiveConstraintSourceMap.get(include);
195 list = new ArrayList<CHRConstraint>(4);
196 inverseActiveConstraintSourceMap.put(include, list);
198 list.add(constraint);
203 // remove init constraint if it is not useful
204 if(getMinimumPriority(initConstraint) == Integer.MAX_VALUE) {
205 constraints.remove(0);
206 initConstraint = null;
210 private void applyExtensibleDefaults() {
211 for(CHRConstraint constraint : constraints) {
212 // FIXME Too much indexing!!!
213 int max = 1 << constraint.parameterTypes.length;
214 for(int i=0;i<max;++i)
215 constraint.getOrCreateIndex(cachedContext, i);
216 constraint.setMayBeRemoved();
218 constraint.getOrCreateIndex(cachedContext, 0);
219 if(constraint.parameterTypes.length > 0)
220 constraint.getOrCreateIndex(cachedContext, 1);*/
224 public void simplify(SimplificationContext context) {
225 for(IncludeStatement include : includes)
226 include.value = include.value.simplify(context);
227 for(CHRRule rule : rules)
228 rule.simplify(context);
231 public void setRulesetType(TCon type, String className) {
232 this.runtimeRulesetType = type;
233 this.runtimeRulesetClassName = className;
236 public void initializeCodeGeneration(CompilationContext context) {
237 cachedContext = context; // FIXME remove
239 boolean createTypeDesc = false;
240 if(runtimeRulesetType == null) {
241 String suffix = context.namingPolicy.getFreshClosureClassNameSuffix();
242 setRulesetType(Types.con(context.namingPolicy.getModuleName(), "CHR" + suffix), context.namingPolicy.getModuleClassName() + suffix);
243 createTypeDesc = true;
245 runtimeRulesetTypeDesc = TypeDesc.forClass(runtimeRulesetClassName);
246 runtimeRulesetVariable = new BoundVar(runtimeRulesetType);
247 for(CHRConstraint constraint : constraints)
248 constraint.initializeCodeGeneration(context, this);
249 if(createTypeDesc && context.module != null) // for unit testing
250 context.module.addTypeDescriptor(runtimeRulesetType.name, new StandardTypeConstructor(runtimeRulesetType, TVar.EMPTY_ARRAY, runtimeRulesetTypeDesc));
253 public static final Constant ACTIVATE = new JavaMethod(true, CHRCodeGenerationConstants.CHRContext_name, "activate", Types.PROC, Types.UNIT, Types.CHRContext, Types.INTEGER);
254 private static final Constant CREATE_CHR_CONTEXT = new JavaConstructor("org/simantics/scl/runtime/chr/CHRContext", Types.PROC, Types.CHRContext);
256 public IVal generateCode(CodeWriter w) {
257 for(IncludeStatement include : includes) {
258 include.storeVar = include.value.toVal(cachedContext, w);
259 initialPriorityNumber = Math.max(initialPriorityNumber, include.ruleset.initialPriorityNumber + include.ruleset.priorityCount);
261 CHRRulesetObject object = new CHRRulesetObject(runtimeRulesetVariable, this);
262 w.defineObject(object);
263 for(CHRRule rule : rules) {
264 for(CHRSearchPlan plan : rule.plans) {
265 /*System.out.println(" plan " + plan.priority);
266 for(PlanOp planOp : plan.ops)
267 System.out.println(" " + planOp);*/
268 CodeWriter methodWriter = object.createMethod(w.getModuleWriter(), TVar.EMPTY_ARRAY, Types.PROC, Types.BOOLEAN, new Type[] {Types.CHRContext, plan.constraint.factType});
269 plan.implementation = methodWriter.getFunction();
270 IVal[] implementationParameters = methodWriter.getParameters();
271 plan.activeFact.setVal(implementationParameters[1]);
272 PlanRealizer realizer = new PlanRealizer(cachedContext, this, runtimeRulesetVariable, implementationParameters[0], plan.ops);
273 realizer.nextOp(methodWriter);
274 if(methodWriter.isUnfinished())
275 methodWriter.return_(BooleanConstant.TRUE);
278 if(!includes.isEmpty() || extensible) {
280 CodeWriter methodWriter = object.createMethod(w.getModuleWriter(), TVar.EMPTY_ARRAY, Types.PROC, Types.UNIT, new Type[] {Types.CHRContext});
281 initializer = methodWriter.getFunction();
282 for(IncludeStatement include : includes) {
283 methodWriter.apply(include.location,
284 new JavaMethod(true, runtimeRulesetClassName, "register", Types.PROC, Types.UNIT, new Type[] {runtimeRulesetType, Types.CHRContext, include.ruleset.runtimeRulesetType}),
285 object.getTarget(), methodWriter.getParameters()[0], include.storeVar);
288 methodWriter.apply(Locations.NO_LOCATION,
289 new JavaMethod(true, runtimeRulesetClassName, "register", Types.PROC, Types.UNIT, new Type[] {runtimeRulesetType, Types.CHRContext}),
290 object.getTarget(), methodWriter.getParameters()[0]);
291 methodWriter.return_(NoRepConstant.UNIT);
294 CodeWriter methodWriter = object.createMethod(w.getModuleWriter(), TVar.EMPTY_ARRAY, Types.PROC, Types.UNIT, new Type[] {Types.CHRContext});
295 deinitializer = methodWriter.getFunction();
296 for(IncludeStatement include : includes) {
297 methodWriter.apply(include.location,
298 new JavaMethod(true, runtimeRulesetClassName, "unregister", Types.PROC, Types.UNIT, new Type[] {runtimeRulesetType, Types.CHRContext, include.ruleset.runtimeRulesetType}),
299 object.getTarget(), methodWriter.getParameters()[0], include.storeVar);
302 methodWriter.apply(Locations.NO_LOCATION,
303 new JavaMethod(true, runtimeRulesetClassName, "unregister", Types.PROC, Types.UNIT, new Type[] {runtimeRulesetType, Types.CHRContext}),
304 object.getTarget(), methodWriter.getParameters()[0]);
305 methodWriter.return_(NoRepConstant.UNIT);
308 if(initConstraint != null) {
309 IVal chrContext = w.apply(location, CREATE_CHR_CONTEXT);
310 if(initializer != null) {
312 new JavaMethod(true, runtimeRulesetClassName, "initialize", Types.PROC, Types.UNIT, new Type[] {runtimeRulesetType, Types.CHRContext}),
313 object.getTarget(), chrContext);
315 IVal initFact = w.apply(location, initConstraint.constructor, w.apply(location, GENERATE_ID, chrContext));
316 w.apply(location, initConstraint.addProcedure, runtimeRulesetVariable, chrContext, initFact);
317 w.apply(location, ACTIVATE, chrContext, new IntegerConstant(Integer.MAX_VALUE));
318 if(deinitializer != null) {
320 new JavaMethod(true, runtimeRulesetClassName, "deinitialize", Types.PROC, Types.UNIT, new Type[] {runtimeRulesetType, Types.CHRContext}),
321 object.getTarget(), chrContext);
324 return runtimeRulesetVariable;
327 public void collectEffects(THashSet<Type> effects) {
328 for(CHRRule rule : rules) {
329 for(CHRLiteral literal : rule.head.literals)
330 literal.collectQueryEffects(effects);
331 for(CHRLiteral literal : rule.head.literals)
332 literal.collectEnforceEffects(effects);
336 public void addRule(CHRRule rule) {
338 rule.parentRuleset = this;