package org.simantics.scl.compiler.elaboration.chr; import java.util.ArrayList; import java.util.HashMap; import org.simantics.scl.compiler.compilation.CompilationContext; import org.simantics.scl.compiler.elaboration.chr.plan.CHRSearchPlan; import org.simantics.scl.compiler.elaboration.chr.planning.QueryPlanningContext; 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.EAsPattern; import org.simantics.scl.compiler.elaboration.expressions.EVariable; import org.simantics.scl.compiler.elaboration.expressions.Expression; import org.simantics.scl.compiler.elaboration.expressions.ExpressionVisitor; import org.simantics.scl.compiler.elaboration.expressions.Variable; import org.simantics.scl.compiler.elaboration.expressions.printing.ExpressionToStringVisitor; import org.simantics.scl.compiler.elaboration.expressions.visitors.StandardExpressionVisitor; import org.simantics.scl.compiler.errors.Locations; import org.simantics.scl.compiler.internal.parsing.Symbol; import org.simantics.scl.compiler.types.Types; import org.simantics.scl.compiler.types.kinds.Kinds; import gnu.trove.map.hash.TObjectIntHashMap; import gnu.trove.set.hash.TIntHashSet; public class CHRRule extends Symbol { public CHRRuleset parentRuleset; public int priority; public CHRQuery head; public CHRQuery body; public Variable[] existentialVariables; // Analysis //public int firstPriorityExecuted; public int lastPriorityExecuted; // Plans public ArrayList plans = new ArrayList(); // Code generation, move to CHRPriority public String containerClassName; public CHRRule(long location, CHRQuery head, CHRQuery body, Variable[] existentialVariables) { this.location = location; this.head = head; this.body = body; this.existentialVariables = existentialVariables; } public CHRRule(long location, CHRQuery head, CHRQuery body) { this(location, head, body, null); } public void resolve(TranslationContext context) { context.pushExistentialFrame(); head.resolve(context); context.disallowNewExistentials(); body.resolve(context); existentialVariables = context.popExistentialFrame(); warnForExistentialsUsedOnlyOnce(context); } private static final Object NEVER_USED = new Object(); private void warnForExistentialsUsedOnlyOnce(TranslationContext context) { // Initialize the hash map HashMap usageCount = new HashMap<>(existentialVariables.length); for(Variable var : existentialVariables) if(!var.getName().equals("_")) usageCount.put(var, NEVER_USED); // Collect variable uses ExpressionVisitor visitor = new StandardExpressionVisitor() { private void handle(Expression expression, Variable variable) { Object object = usageCount.remove(variable); if(object == NEVER_USED) usageCount.put(variable, expression); } @Override public void visit(EVariable expression) { if(expression.variable != null) handle(expression, expression.variable); } @Override public void visit(EAsPattern expression) { expression.pattern.accept(this); handle(expression, expression.var); } }; head.accept(visitor); body.accept(visitor); // Report as warnings usageCount.forEach((variable, expression_) -> { if(!(expression_ instanceof Expression)) return; // Should never happen Expression expression = (Expression)expression_; if(context.isExpandedFromWildcard(expression)) return; context.getErrorLog().logWarning(expression.location, "Existential variable " + variable.getName() + " is referred only once. Replace by _ if this is a wildcard."); }); } public void checkType(TypingContext context) { for(Variable variable : existentialVariables) variable.setType(Types.metaVar(Kinds.STAR)); head.checkType(context); body.checkType(context); } public void collectVars(TObjectIntHashMap allVars, TIntHashSet vars) { head.collectVars(allVars, vars); body.collectVars(allVars, vars); } public void setLocationDeep(long loc) { if(location == Locations.NO_LOCATION) { this.location = loc; head.setLocationDeep(loc); body.setLocationDeep(loc); } } public void simplify(SimplificationContext context) { head.simplify(context); body.simplify(context); } public void compile(CompilationContext compilationContext, CHRConstraint initConstraint) { boolean hasLocalActiveLiteral = false; for(int i=0;i