1 package org.simantics.scl.compiler.elaboration.chr;
3 import java.util.ArrayList;
4 import java.util.HashMap;
6 import org.simantics.scl.compiler.compilation.CompilationContext;
7 import org.simantics.scl.compiler.elaboration.chr.plan.CHRSearchPlan;
8 import org.simantics.scl.compiler.elaboration.chr.planning.QueryPlanningContext;
9 import org.simantics.scl.compiler.elaboration.chr.relations.CHRConstraint;
10 import org.simantics.scl.compiler.elaboration.contexts.SimplificationContext;
11 import org.simantics.scl.compiler.elaboration.contexts.TranslationContext;
12 import org.simantics.scl.compiler.elaboration.contexts.TypingContext;
13 import org.simantics.scl.compiler.elaboration.expressions.EAsPattern;
14 import org.simantics.scl.compiler.elaboration.expressions.EVariable;
15 import org.simantics.scl.compiler.elaboration.expressions.Expression;
16 import org.simantics.scl.compiler.elaboration.expressions.ExpressionVisitor;
17 import org.simantics.scl.compiler.elaboration.expressions.Variable;
18 import org.simantics.scl.compiler.elaboration.expressions.printing.ExpressionToStringVisitor;
19 import org.simantics.scl.compiler.elaboration.expressions.visitors.StandardExpressionVisitor;
20 import org.simantics.scl.compiler.errors.Locations;
21 import org.simantics.scl.compiler.internal.parsing.Symbol;
22 import org.simantics.scl.compiler.types.Types;
23 import org.simantics.scl.compiler.types.kinds.Kinds;
25 import gnu.trove.map.hash.TObjectIntHashMap;
26 import gnu.trove.set.hash.TIntHashSet;
28 public class CHRRule extends Symbol {
29 public CHRRuleset parentRuleset;
33 public Variable[] existentialVariables;
36 //public int firstPriorityExecuted;
37 public int lastPriorityExecuted;
40 public ArrayList<CHRSearchPlan> plans = new ArrayList<CHRSearchPlan>();
42 // Code generation, move to CHRPriority
43 public String containerClassName;
45 public CHRRule(long location, CHRQuery head, CHRQuery body, Variable[] existentialVariables) {
46 this.location = location;
49 this.existentialVariables = existentialVariables;
52 public CHRRule(long location, CHRQuery head, CHRQuery body) {
53 this(location, head, body, null);
56 public void resolve(TranslationContext context) {
57 context.pushExistentialFrame();
58 head.resolve(context);
59 context.disallowNewExistentials();
60 body.resolve(context);
61 existentialVariables = context.popExistentialFrame();
63 warnForExistentialsUsedOnlyOnce(context);
66 private static final Object NEVER_USED = new Object();
68 private void warnForExistentialsUsedOnlyOnce(TranslationContext context) {
69 // Initialize the hash map
70 HashMap<Variable, Object> usageCount = new HashMap<>(existentialVariables.length);
71 for(Variable var : existentialVariables)
72 if(!var.getName().equals("_"))
73 usageCount.put(var, NEVER_USED);
75 // Collect variable uses
76 ExpressionVisitor visitor = new StandardExpressionVisitor() {
77 private void handle(Expression expression, Variable variable) {
78 Object object = usageCount.remove(variable);
79 if(object == NEVER_USED)
80 usageCount.put(variable, expression);
83 public void visit(EVariable expression) {
84 if(expression.variable != null)
85 handle(expression, expression.variable);
88 public void visit(EAsPattern expression) {
89 expression.pattern.accept(this);
90 handle(expression, expression.var);
97 usageCount.forEach((variable, expression_) -> {
98 if(!(expression_ instanceof Expression))
99 return; // Should never happen
100 Expression expression = (Expression)expression_;
101 if(context.isExpandedFromWildcard(expression))
104 context.getErrorLog().logWarning(expression.location,
105 "Existential variable " + variable.getName() + " is referred only once. Replace by _ if this is a wildcard.");
110 public void checkType(TypingContext context) {
111 for(Variable variable : existentialVariables)
112 variable.setType(Types.metaVar(Kinds.STAR));
113 head.checkType(context);
114 body.checkType(context);
117 public void collectVars(TObjectIntHashMap<Variable> allVars, TIntHashSet vars) {
118 head.collectVars(allVars, vars);
119 body.collectVars(allVars, vars);
122 public void setLocationDeep(long loc) {
123 if(location == Locations.NO_LOCATION) {
125 head.setLocationDeep(loc);
126 body.setLocationDeep(loc);
130 public void simplify(SimplificationContext context) {
131 head.simplify(context);
132 body.simplify(context);
135 public void compile(CompilationContext compilationContext, CHRConstraint initConstraint) {
136 boolean hasLocalActiveLiteral = false;
137 for(int i=0;i<head.literals.length;++i) {
138 CHRLiteral literal = head.literals[i];
141 CHRConstraint constraint = (CHRConstraint)literal.relation;
143 Variable activeFact = new Variable("activeFact", constraint.factType);
144 QueryPlanningContext context = new QueryPlanningContext(compilationContext, existentialVariables);
145 if(!head.createQueryPlan(context, new EVariable(activeFact), i, initConstraint))
147 body.createEnforcePlan(context, priority);
148 addPlan(new CHRSearchPlan(constraint, activeFact, context.getPlanOps()));
150 if(constraint.parentRuleset == parentRuleset)
151 hasLocalActiveLiteral = true;
153 if(!hasLocalActiveLiteral) {
154 Variable activeFact = new Variable("activeFact", initConstraint.factType);
155 QueryPlanningContext context = new QueryPlanningContext(compilationContext, existentialVariables);
156 if(!head.createQueryPlan(context, new EVariable(activeFact), -1, initConstraint))
158 body.createEnforcePlan(context, priority);
159 /*System.out.println(this);
160 for(PlanOp planOp : context.getPlanOps())
161 System.out.println(" " + planOp);*/
162 addPlan(new CHRSearchPlan(initConstraint, activeFact, context.getPlanOps()));
166 private void addPlan(CHRSearchPlan plan) {
170 public String toString() {
171 StringBuilder b = new StringBuilder();
172 ExpressionToStringVisitor visitor = new ExpressionToStringVisitor(b);