package org.simantics.scl.compiler.elaboration.expressions; import static org.simantics.scl.compiler.elaboration.expressions.Expressions.Just; import static org.simantics.scl.compiler.elaboration.expressions.Expressions.addInteger; import static org.simantics.scl.compiler.elaboration.expressions.Expressions.apply; import static org.simantics.scl.compiler.elaboration.expressions.Expressions.as; import static org.simantics.scl.compiler.elaboration.expressions.Expressions.if_; import static org.simantics.scl.compiler.elaboration.expressions.Expressions.integer; import static org.simantics.scl.compiler.elaboration.expressions.Expressions.isZeroInteger; import static org.simantics.scl.compiler.elaboration.expressions.Expressions.lambda; import static org.simantics.scl.compiler.elaboration.expressions.Expressions.let; import static org.simantics.scl.compiler.elaboration.expressions.Expressions.letRec; import static org.simantics.scl.compiler.elaboration.expressions.Expressions.matchWithDefault; import static org.simantics.scl.compiler.elaboration.expressions.Expressions.newVar; import static org.simantics.scl.compiler.elaboration.expressions.Expressions.seq; import static org.simantics.scl.compiler.elaboration.expressions.Expressions.tuple; import static org.simantics.scl.compiler.elaboration.expressions.Expressions.var; import static org.simantics.scl.compiler.elaboration.expressions.Expressions.vars; import java.util.ArrayList; import java.util.Set; import org.simantics.scl.compiler.common.exceptions.InternalCompilerError; import org.simantics.scl.compiler.common.names.Names; import org.simantics.scl.compiler.elaboration.contexts.TranslationContext; import org.simantics.scl.compiler.elaboration.contexts.TypingContext; import org.simantics.scl.compiler.elaboration.expressions.printing.ExpressionToStringVisitor; import org.simantics.scl.compiler.elaboration.query.Query; import org.simantics.scl.compiler.elaboration.query.Query.Diff; import org.simantics.scl.compiler.elaboration.query.Query.Diffable; import org.simantics.scl.compiler.elaboration.query.compilation.DerivateException; import org.simantics.scl.compiler.elaboration.relations.LocalRelation; import org.simantics.scl.compiler.elaboration.relations.SCLRelation; import org.simantics.scl.compiler.errors.Locations; import org.simantics.scl.compiler.internal.elaboration.utils.ForcedClosure; import org.simantics.scl.compiler.internal.elaboration.utils.StronglyConnectedComponents; import org.simantics.scl.compiler.top.SCLCompilerConfiguration; import org.simantics.scl.compiler.types.Type; import org.simantics.scl.compiler.types.Types; import org.simantics.scl.compiler.types.exceptions.MatchException; import org.simantics.scl.compiler.types.kinds.Kinds; import gnu.trove.impl.Constants; import gnu.trove.map.hash.THashMap; import gnu.trove.map.hash.TObjectIntHashMap; import gnu.trove.set.hash.TIntHashSet; public class ERuleset extends SimplifiableExpression { LocalRelation[] relations; public DatalogRule[] rules; public Expression in; public ERuleset(LocalRelation[] relations, DatalogRule[] rules, Expression in) { this.relations = relations; this.rules = rules; this.in = in; } public static class DatalogRule { public long location; public LocalRelation headRelation; public Expression[] headParameters; public Query body; public Variable[] variables; public DatalogRule(LocalRelation headRelation, Expression[] headParameters, Query body) { this.headRelation = headRelation; this.headParameters = headParameters; this.body = body; } public DatalogRule(long location, LocalRelation headRelation, Expression[] headParameters, Query body, Variable[] variables) { this.location = location; this.headRelation = headRelation; this.headParameters = headParameters; this.body = body; this.variables = variables; } public void setLocationDeep(long loc) { this.location = loc; for(Expression parameter : headParameters) parameter.setLocationDeep(loc); body.setLocationDeep(loc); } @Override public String toString() { StringBuilder b = new StringBuilder(); ExpressionToStringVisitor visitor = new ExpressionToStringVisitor(b); visitor.visit(this); return b.toString(); } } private void checkRuleTypes(TypingContext context) { // Create relation variables for(DatalogRule rule : rules) { Type[] parameterTypes = rule.headRelation.getParameterTypes(); Expression[] parameters = rule.headParameters; for(Variable variable : rule.variables) variable.setType(Types.metaVar(Kinds.STAR)); for(int i=0;i relationsToIds = new TObjectIntHashMap(relations.length, Constants.DEFAULT_LOAD_FACTOR, -1); for(int i=0;i components = new ArrayList(); new StronglyConnectedComponents(relations.length) { @Override protected void reportComponent(int[] component) { components.add(component); } @Override protected int[] findDependencies(int u) { return refs[u]; } }.findComponents(); // If there is just one component, compile it if(components.size() == 1) { return compileStratified(context); } // Inverse of components array int[] strataPerRelation = new int[relations.length]; for(int i=0;i[] rulesPerStrata = new ArrayList[components.size()]; for(int i=0;i(); for(DatalogRule rule : rules) { int stratum = strataPerRelation[relationsToIds.get(rule.headRelation)]; rulesPerStrata[stratum].add(rule); } // Create stratified system Expression cur = this.in; for(int stratum=components.size()-1;stratum >= 0;--stratum) { int[] cs = components.get(stratum); LocalRelation[] curRelations = new LocalRelation[cs.length]; for(int i=0;i curRules = rulesPerStrata[stratum]; cur = new ERuleset(curRelations, curRules.toArray(new DatalogRule[curRules.size()]), cur).compileStratified(context); } return cur; } private Expression compileStratified(TypingContext context) { Expression continuation = Expressions.tuple(); // Create stacks Variable[] stacks = new Variable[relations.length]; for(int i=0;i diffables = new THashMap(relations.length); for(int i=0;i[] updateExpressions = (ArrayList[])new ArrayList[relations.length]; for(int i=0;i(2); ArrayList seedExpressions = new ArrayList(); for(DatalogRule rule : rules) { int id = diffables.get(rule.headRelation).id; Expression appendExp = apply(context.getCompilationContext(), Types.PROC, Names.MList_add, Types.tuple(rule.headRelation.getParameterTypes()), var(stacks[id]), tuple(rule.headParameters) ); Diff[] diffs; try { diffs = rule.body.derivate(diffables); } catch(DerivateException e) { context.getErrorLog().log(e.location, "Recursion must not contain negations or aggragates."); return new EError(); } for(Diff diff : diffs) updateExpressions[diff.id].add(((EWhen)new EWhen(rule.location, diff.query, appendExp, rule.variables).copy(context)).compile(context)); if(diffs.length == 0) seedExpressions.add(((EWhen)new EWhen(rule.location, rule.body, appendExp, rule.variables).copy(context)).compile(context)); else { Query query = rule.body.removeRelations((Set)(Set)diffables.keySet()); if(query != Query.EMPTY_QUERY) seedExpressions.add(((EWhen)new EWhen(location, query, appendExp, rule.variables).copy(context)).compile(context)); } } // Iterative solving of relations Variable[] loops = new Variable[relations.length]; for(int i=0;i