]> gerrit.simantics Code Review - simantics/platform.git/blobdiff - bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/query/QConjunction.java
Migrated source code from Simantics SVN
[simantics/platform.git] / bundles / org.simantics.scl.compiler / src / org / simantics / scl / compiler / elaboration / query / QConjunction.java
diff --git a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/query/QConjunction.java b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/query/QConjunction.java
new file mode 100644 (file)
index 0000000..95bb7b4
--- /dev/null
@@ -0,0 +1,144 @@
+package org.simantics.scl.compiler.elaboration.query;
+
+import gnu.trove.map.hash.THashMap;
+import gnu.trove.map.hash.TIntObjectHashMap;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Set;
+
+import org.simantics.scl.compiler.elaboration.contexts.ReplaceContext;
+import org.simantics.scl.compiler.elaboration.expressions.EConstant;
+import org.simantics.scl.compiler.elaboration.expressions.ESimpleLet;
+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.java.Builtins;
+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.EnforcingContext;
+import org.simantics.scl.compiler.elaboration.query.compilation.UnsolvableQueryException;
+import org.simantics.scl.compiler.elaboration.relations.LocalRelation;
+import org.simantics.scl.compiler.elaboration.relations.SCLRelation;
+import org.simantics.scl.compiler.types.Types;
+
+
+public class QConjunction extends QAbstractCombiner {
+
+    public QConjunction(Query ... queries) {
+        super(queries);
+    }
+
+    public QConjunction(Collection<Query> queries) {
+        this(queries.toArray(new Query[queries.size()]));
+    }
+
+    public Expression generateEnforce(EnforcingContext context) {
+        Expression result = new EConstant(Builtins.TUPLE_CONSTRUCTORS[0]);
+        for(int i=queries.length-1;i>=0;--i)
+            result = new ESimpleLet(
+                    new Variable("_", Types.tupleConstructor(0)),
+                    queries[i].generateEnforce(context),
+                    result
+                    );
+        return result;
+    }
+
+    @Override
+    public void collectConstraints(ConstraintCollectionContext context) throws UnsolvableQueryException {
+        for(Query query : queries)
+            query.collectConstraints(context);
+    }
+
+    private static class DerEntry {
+        Query base;
+        Diff[] diffs;
+        
+        public DerEntry(Query base, Diff[] diffs) {
+            this.base = base;
+            this.diffs = diffs;
+        }
+    }
+    
+    @Override
+    public Diff[] derivate(THashMap<LocalRelation, Diffable> diffables) throws DerivateException {
+        ArrayList<Query> cons = new ArrayList<Query>(queries.length);
+        ArrayList<DerEntry> ders = new ArrayList<DerEntry>(queries.length);
+        for(Query query : queries) {
+            Diff[] diffs = query.derivate(diffables);
+            if(diffs.length == 0)
+                cons.add(query);
+            else
+                ders.add(new DerEntry(query, diffs));
+        }
+        if(ders.isEmpty())
+            return NO_DIFF;
+        
+        Query base = new QConjunction(cons.toArray(new Query[cons.size()]));
+        Diff[] diffs = NO_DIFF;
+        for(DerEntry entry : ders) {
+            ArrayList<Diff> newDiffs = new ArrayList<Diff>();
+            for(Diff diff : diffs)
+                newDiffs.add(new Diff(diff.id, new QConjunction(diff.query, entry.base)));
+            for(Diff newDiff : entry.diffs) {
+                newDiffs.add(new Diff(newDiff.id, new QConjunction(base, newDiff.query)));
+                for(Diff diff : diffs)
+                    if(diff.id == newDiff.id)
+                        newDiffs.add(new Diff(diff.id, new QConjunction(diff.query, newDiff.query)));
+            }
+            base = new QConjunction(base, entry.base);
+            diffs = newDiffs.toArray(new Diff[newDiffs.size()]);
+        }
+        return diffs;
+    }
+    
+    @Override
+    public Query removeRelations(Set<SCLRelation> relations) {
+        for(int i=0;i<queries.length;++i) {
+            Query query = queries[i];
+            Query newQuery = query.removeRelations(relations);
+            if(query != newQuery) {
+                if(newQuery == EMPTY_QUERY)
+                    return EMPTY_QUERY;
+                Query[] newQueries = new Query[queries.length];
+                if(i > 0)
+                    System.arraycopy(queries, 0, newQueries, 0, i-1);
+                newQueries[i] = newQuery;
+                for(++i;i<queries.length;++i) {
+                    query = queries[i];
+                    newQuery = query.removeRelations(relations);
+                    if(newQuery == EMPTY_QUERY)
+                        return EMPTY_QUERY;
+                    newQueries[i] = query;
+                }
+                return new QConjunction(newQueries);
+            }
+        }
+        return this;
+    }
+    
+    @Override
+    public Query replace(ReplaceContext context) {
+        Query[] newQueries = new Query[queries.length];
+        for(int i=0;i<queries.length;++i)
+            newQueries[i] = queries[i].replace(context);
+        return new QConjunction(newQueries);
+    }
+
+    @Override
+    public void accept(QueryVisitor visitor) {
+        visitor.visit(this);
+    }
+
+    @Override
+    public void splitToPhases(TIntObjectHashMap<ArrayList<Query>> result) {
+        for(Query query : queries)
+            query.splitToPhases(result);
+    }
+    
+    @Override
+    public Query accept(QueryTransformer transformer) {
+        return transformer.transform(this);
+    }
+
+}