]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/query/QConjunction.java
95bb7b454145638403eb824fe2d59505467947b1
[simantics/platform.git] / bundles / org.simantics.scl.compiler / src / org / simantics / scl / compiler / elaboration / query / QConjunction.java
1 package org.simantics.scl.compiler.elaboration.query;
2
3 import gnu.trove.map.hash.THashMap;
4 import gnu.trove.map.hash.TIntObjectHashMap;
5
6 import java.util.ArrayList;
7 import java.util.Collection;
8 import java.util.Set;
9
10 import org.simantics.scl.compiler.elaboration.contexts.ReplaceContext;
11 import org.simantics.scl.compiler.elaboration.expressions.EConstant;
12 import org.simantics.scl.compiler.elaboration.expressions.ESimpleLet;
13 import org.simantics.scl.compiler.elaboration.expressions.Expression;
14 import org.simantics.scl.compiler.elaboration.expressions.QueryTransformer;
15 import org.simantics.scl.compiler.elaboration.expressions.Variable;
16 import org.simantics.scl.compiler.elaboration.java.Builtins;
17 import org.simantics.scl.compiler.elaboration.query.compilation.ConstraintCollectionContext;
18 import org.simantics.scl.compiler.elaboration.query.compilation.DerivateException;
19 import org.simantics.scl.compiler.elaboration.query.compilation.EnforcingContext;
20 import org.simantics.scl.compiler.elaboration.query.compilation.UnsolvableQueryException;
21 import org.simantics.scl.compiler.elaboration.relations.LocalRelation;
22 import org.simantics.scl.compiler.elaboration.relations.SCLRelation;
23 import org.simantics.scl.compiler.types.Types;
24
25
26 public class QConjunction extends QAbstractCombiner {
27
28     public QConjunction(Query ... queries) {
29         super(queries);
30     }
31
32     public QConjunction(Collection<Query> queries) {
33         this(queries.toArray(new Query[queries.size()]));
34     }
35
36     public Expression generateEnforce(EnforcingContext context) {
37         Expression result = new EConstant(Builtins.TUPLE_CONSTRUCTORS[0]);
38         for(int i=queries.length-1;i>=0;--i)
39             result = new ESimpleLet(
40                     new Variable("_", Types.tupleConstructor(0)),
41                     queries[i].generateEnforce(context),
42                     result
43                     );
44         return result;
45     }
46
47     @Override
48     public void collectConstraints(ConstraintCollectionContext context) throws UnsolvableQueryException {
49         for(Query query : queries)
50             query.collectConstraints(context);
51     }
52
53     private static class DerEntry {
54         Query base;
55         Diff[] diffs;
56         
57         public DerEntry(Query base, Diff[] diffs) {
58             this.base = base;
59             this.diffs = diffs;
60         }
61     }
62     
63     @Override
64     public Diff[] derivate(THashMap<LocalRelation, Diffable> diffables) throws DerivateException {
65         ArrayList<Query> cons = new ArrayList<Query>(queries.length);
66         ArrayList<DerEntry> ders = new ArrayList<DerEntry>(queries.length);
67         for(Query query : queries) {
68             Diff[] diffs = query.derivate(diffables);
69             if(diffs.length == 0)
70                 cons.add(query);
71             else
72                 ders.add(new DerEntry(query, diffs));
73         }
74         if(ders.isEmpty())
75             return NO_DIFF;
76         
77         Query base = new QConjunction(cons.toArray(new Query[cons.size()]));
78         Diff[] diffs = NO_DIFF;
79         for(DerEntry entry : ders) {
80             ArrayList<Diff> newDiffs = new ArrayList<Diff>();
81             for(Diff diff : diffs)
82                 newDiffs.add(new Diff(diff.id, new QConjunction(diff.query, entry.base)));
83             for(Diff newDiff : entry.diffs) {
84                 newDiffs.add(new Diff(newDiff.id, new QConjunction(base, newDiff.query)));
85                 for(Diff diff : diffs)
86                     if(diff.id == newDiff.id)
87                         newDiffs.add(new Diff(diff.id, new QConjunction(diff.query, newDiff.query)));
88             }
89             base = new QConjunction(base, entry.base);
90             diffs = newDiffs.toArray(new Diff[newDiffs.size()]);
91         }
92         return diffs;
93     }
94     
95     @Override
96     public Query removeRelations(Set<SCLRelation> relations) {
97         for(int i=0;i<queries.length;++i) {
98             Query query = queries[i];
99             Query newQuery = query.removeRelations(relations);
100             if(query != newQuery) {
101                 if(newQuery == EMPTY_QUERY)
102                     return EMPTY_QUERY;
103                 Query[] newQueries = new Query[queries.length];
104                 if(i > 0)
105                     System.arraycopy(queries, 0, newQueries, 0, i-1);
106                 newQueries[i] = newQuery;
107                 for(++i;i<queries.length;++i) {
108                     query = queries[i];
109                     newQuery = query.removeRelations(relations);
110                     if(newQuery == EMPTY_QUERY)
111                         return EMPTY_QUERY;
112                     newQueries[i] = query;
113                 }
114                 return new QConjunction(newQueries);
115             }
116         }
117         return this;
118     }
119     
120     @Override
121     public Query replace(ReplaceContext context) {
122         Query[] newQueries = new Query[queries.length];
123         for(int i=0;i<queries.length;++i)
124             newQueries[i] = queries[i].replace(context);
125         return new QConjunction(newQueries);
126     }
127
128     @Override
129     public void accept(QueryVisitor visitor) {
130         visitor.visit(this);
131     }
132
133     @Override
134     public void splitToPhases(TIntObjectHashMap<ArrayList<Query>> result) {
135         for(Query query : queries)
136             query.splitToPhases(result);
137     }
138     
139     @Override
140     public Query accept(QueryTransformer transformer) {
141         return transformer.transform(this);
142     }
143
144 }