package org.simantics.scl.compiler.elaboration.query; import java.util.ArrayList; import java.util.Set; import org.simantics.scl.compiler.common.exceptions.InternalCompilerError; import org.simantics.scl.compiler.elaboration.contexts.ReplaceContext; import org.simantics.scl.compiler.elaboration.contexts.TranslationContext; import org.simantics.scl.compiler.elaboration.contexts.TypingContext; import org.simantics.scl.compiler.elaboration.expressions.EError; import org.simantics.scl.compiler.elaboration.expressions.Expression; import org.simantics.scl.compiler.elaboration.expressions.QueryTransformer; import org.simantics.scl.compiler.elaboration.expressions.Variable; import org.simantics.scl.compiler.elaboration.expressions.VariableProcedure; import org.simantics.scl.compiler.elaboration.expressions.printing.ExpressionToStringVisitor; import org.simantics.scl.compiler.elaboration.expressions.visitors.CollectRefsVisitor; import org.simantics.scl.compiler.elaboration.expressions.visitors.CollectVarsVisitor; import org.simantics.scl.compiler.elaboration.expressions.visitors.ForVariablesUsesVisitor; import org.simantics.scl.compiler.elaboration.expressions.visitors.StandardExpressionVisitor; import org.simantics.scl.compiler.elaboration.query.compilation.ConstraintCollectionContext; import org.simantics.scl.compiler.elaboration.query.compilation.DerivateException; import org.simantics.scl.compiler.elaboration.query.compilation.DynamicProgrammingOrdering; import org.simantics.scl.compiler.elaboration.query.compilation.EnforcingContext; import org.simantics.scl.compiler.elaboration.query.compilation.QueryCompilationContext; import org.simantics.scl.compiler.elaboration.query.compilation.QueryConstraint; import org.simantics.scl.compiler.elaboration.query.compilation.UnsolvableQueryException; import org.simantics.scl.compiler.elaboration.relations.CompositeRelation; import org.simantics.scl.compiler.elaboration.relations.LocalRelation; import org.simantics.scl.compiler.elaboration.relations.SCLRelation; import org.simantics.scl.compiler.internal.parsing.Symbol; import gnu.trove.map.hash.THashMap; import gnu.trove.map.hash.TIntObjectHashMap; import gnu.trove.map.hash.TObjectIntHashMap; import gnu.trove.set.hash.TIntHashSet; public abstract class Query extends Symbol { public static final Query[] EMPTY_ARRAY = new Query[0]; public abstract void checkType(TypingContext context); public Query resolve(TranslationContext context) { throw new InternalCompilerError(location, getClass().getSimpleName() + " does not support resolve."); } public Expression generateEnforce(EnforcingContext context) { context.getErrorLog().log(location, getClass().getSimpleName() + " does not support enforcing."); return new EError(location); } public abstract void collectConstraints(ConstraintCollectionContext context) throws UnsolvableQueryException; protected QueryConstraint[] getOrderedConstraints(QueryCompilationContext context) throws UnsolvableQueryException { ConstraintCollectionContext collectionContext = new ConstraintCollectionContext(context); collectConstraints(collectionContext); QueryConstraint[] constraints = collectionContext.getConstraints(); DynamicProgrammingOrdering.order(collectionContext, constraints, 0L); return constraints; } protected void applyConstraints(QueryCompilationContext context, QueryConstraint[] constraints) { for(int i=constraints.length-1;i>=0;--i) constraints[i].generateAndUpdateCost(context); } public void generate(QueryCompilationContext context) throws UnsolvableQueryException { applyConstraints(context, getOrderedConstraints(context)); } protected static final TIntObjectHashMap> NO_DERIVATE = new TIntObjectHashMap>(); public static class Diffable { public int id; SCLRelation relation; public Variable[] parameters; public Diffable(int id, SCLRelation relation, Variable[] parameters) { this.id = id; this.relation = relation; this.parameters = parameters; } } public static class Diff { public int id; public Query query; public Diff(int id, Query query) { this.id = id; this.query = query; } } public static final Diff[] NO_DIFF = new Diff[0]; public Diff[] derivate(THashMap diffables) throws DerivateException { throw new DerivateException(location); } public static final QDisjunction EMPTY_QUERY = new QDisjunction(); public Query removeRelations(Set relations) { throw new UnsupportedOperationException(); } public Query copy() { return replace(new ReplaceContext(null)); } public Query copy(TypingContext context) { return replace(new ReplaceContext(context)); } public abstract Query replace(ReplaceContext context); public abstract void setLocationDeep(long loc); public abstract void accept(QueryVisitor visitor); public void collectRelationRefs( final TObjectIntHashMap allRefs, final TIntHashSet refs) { accept(new StandardExpressionVisitor() { @Override public void visit(QAtom query) { visit(query.relation); } private void visit(SCLRelation relation) { int id = allRefs.get(relation); if(id >= 0) refs.add(id); else if(relation instanceof CompositeRelation) for(SCLRelation subrelation : ((CompositeRelation)relation).getSubrelations()) visit(subrelation); } }); } public TIntObjectHashMap> splitToPhases() { TIntObjectHashMap> result = new TIntObjectHashMap>(2); splitToPhases(result); return result; } public void splitToPhases(TIntObjectHashMap> result) { throw new UnsupportedOperationException(getClass().getSimpleName() + " does not support splitToPhases."); } @Override public String toString() { StringBuilder b = new StringBuilder(); ExpressionToStringVisitor visitor = new ExpressionToStringVisitor(b); accept(visitor); return b.toString(); } public abstract Query accept(QueryTransformer transformer); public void forVariables(VariableProcedure procedure) { accept(new ForVariablesUsesVisitor(procedure)); } public void collectRefs(TObjectIntHashMap allRefs, TIntHashSet refs) { accept(new CollectRefsVisitor(allRefs, refs)); } public void collectVars(TObjectIntHashMap allVars, TIntHashSet vars) { accept(new CollectVarsVisitor(allVars, vars)); } }