]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/expressions/ESelect.java
7316fe307798a2d1467d013e21d9a7088dc888ac
[simantics/platform.git] / bundles / org.simantics.scl.compiler / src / org / simantics / scl / compiler / elaboration / expressions / ESelect.java
1 package org.simantics.scl.compiler.elaboration.expressions;
2
3 import static org.simantics.scl.compiler.elaboration.expressions.Expressions.Just;
4 import static org.simantics.scl.compiler.elaboration.expressions.Expressions.apply;
5 import static org.simantics.scl.compiler.elaboration.expressions.Expressions.let;
6 import static org.simantics.scl.compiler.elaboration.expressions.Expressions.loc;
7 import static org.simantics.scl.compiler.elaboration.expressions.Expressions.newVar;
8 import static org.simantics.scl.compiler.elaboration.expressions.Expressions.seq;
9 import static org.simantics.scl.compiler.elaboration.expressions.Expressions.tuple;
10 import static org.simantics.scl.compiler.elaboration.expressions.Expressions.var;
11
12 import org.simantics.scl.compiler.common.exceptions.InternalCompilerError;
13 import org.simantics.scl.compiler.common.names.Names;
14 import org.simantics.scl.compiler.elaboration.contexts.SimplificationContext;
15 import org.simantics.scl.compiler.elaboration.contexts.TranslationContext;
16 import org.simantics.scl.compiler.elaboration.contexts.TypingContext;
17 import org.simantics.scl.compiler.elaboration.query.QExists;
18 import org.simantics.scl.compiler.elaboration.query.Query;
19 import org.simantics.scl.compiler.elaboration.query.compilation.QueryCompilationContext;
20 import org.simantics.scl.compiler.elaboration.query.compilation.QueryCompilationMode;
21 import org.simantics.scl.compiler.elaboration.query.compilation.UnsolvableQueryException;
22 import org.simantics.scl.compiler.errors.Locations;
23 import org.simantics.scl.compiler.internal.elaboration.utils.ExpressionDecorator;
24 import org.simantics.scl.compiler.internal.parsing.parser.SCLTerminals;
25 import org.simantics.scl.compiler.types.Type;
26 import org.simantics.scl.compiler.types.Types;
27 import org.simantics.scl.compiler.types.exceptions.MatchException;
28 import org.simantics.scl.compiler.types.kinds.Kinds;
29
30 import gnu.trove.map.hash.TObjectIntHashMap;
31 import gnu.trove.set.hash.THashSet;
32 import gnu.trove.set.hash.TIntHashSet;
33
34 public class ESelect extends SimplifiableExpression {
35
36     private final Type ARRAY_LIST = Types.con("ArrayList", "T"); 
37     
38     int selectVariant;
39     Expression expression;
40     Query query;
41     Variable[] variables;
42     
43     public ESelect(int selectVariant, Expression expression, Query query) {
44         this.selectVariant = selectVariant;
45         this.expression = expression;
46         this.query = query;
47     }
48
49     @Override
50     public void collectRefs(TObjectIntHashMap<Object> allRefs,
51             TIntHashSet refs) {
52         expression.collectRefs(allRefs, refs);
53         query.collectRefs(allRefs, refs);
54     }
55
56     @Override
57     public void collectVars(TObjectIntHashMap<Variable> allVars,
58             TIntHashSet vars) {
59         expression.collectVars(allVars, vars);
60         query.collectVars(allVars, vars);
61     }
62     
63     @Override
64     public void collectEffects(THashSet<Type> effects) {
65         throw new InternalCompilerError(location, getClass().getSimpleName() + " does not support collectEffects.");
66     }
67
68     @Override
69     protected void updateType() throws MatchException {
70         setType(selectVariant==SCLTerminals.SELECT_FIRST 
71                 ? Types.apply(Types.MAYBE, expression.getType()) 
72                 : Types.list(expression.getType()));
73     }
74     
75     @Override
76     public Expression checkBasicType(TypingContext context, Type requiredType) {
77         Type componentType;
78         switch(selectVariant) {
79         case SCLTerminals.SELECT:
80         case SCLTerminals.SELECT_DISTINCT:
81             try {
82                 componentType = Types.unifyApply(Types.LIST, requiredType);
83             } catch (MatchException e) {
84                 context.getErrorLog().log(location, "Select expression produces a list of values.");
85                 return new EError(location);
86             }
87             break;
88         case SCLTerminals.SELECT_FIRST:
89             try {
90                 componentType = Types.unifyApply(Types.MAYBE, requiredType);
91             } catch (MatchException e) {
92                 context.getErrorLog().log(location, "Select first expression produces an optional value.");
93                 return new EError(location);
94             }
95             break;
96         default: throw new InternalCompilerError();
97         }
98         for(Variable variable : variables)
99             variable.setType(Types.metaVar(Kinds.STAR));
100         expression.checkType(context, componentType);
101         query.checkType(context);
102         
103         // Compile query
104         Type elType = expression.getType();
105         Expression result;
106         if(selectVariant == SCLTerminals.SELECT_FIRST) {
107             QueryCompilationContext queryCompilationContext =
108                     new QueryCompilationContext(context, QueryCompilationMode.GET_FIRST,
109                             expression.getType(),
110                             Just(expression));
111             try {
112                 new QExists(variables, query).generate(queryCompilationContext);
113             } catch (UnsolvableQueryException e) {
114                 context.getErrorLog().log(getLocation(), "Failed to compile the query.\n" + e.getMessage());
115                 return new EError(getLocation());
116             }
117             result = queryCompilationContext.getContinuation();
118         }
119         else {
120             Variable accumulator = newVar("accum", Types.apply(ARRAY_LIST, elType));
121             result =
122                     apply(context.getCompilationContext(), Types.PROC, Names.ArrayList_freeze, elType,
123                             var(accumulator));
124             Expression innerExpression = 
125                     apply(context.getCompilationContext(), Types.PROC, Names.ArrayList_add, elType,
126                             var(accumulator), expression);
127             try {
128                 QueryCompilationContext queryCompilationContext =
129                         new QueryCompilationContext(context, QueryCompilationMode.ITERATE, null, innerExpression);
130                 new QExists(variables, query).generate(queryCompilationContext);
131                 result = seq(queryCompilationContext.getContinuation(), result);
132             } catch(UnsolvableQueryException e) {
133                 context.getErrorLog().log(getLocation(), "Failed to compile the query.\n" + e.getMessage());
134                 return new EError(getLocation());
135             }
136             result = let(accumulator,
137                     apply(context.getCompilationContext(), Types.PROC, Names.ArrayList_new, elType, tuple()),
138                     result
139                     );
140         }
141         return loc(location, result);
142     }
143
144     @Override
145     public void collectFreeVariables(THashSet<Variable> vars) {
146         expression.collectFreeVariables(vars);
147         query.collectFreeVariables(vars);
148         for(Variable variable : variables)
149             vars.remove(variable);
150     }
151
152     @Override
153     public Expression resolve(TranslationContext context) {
154         context.pushExistentialFrame();
155         expression = expression.resolve(context);
156         query = query.resolve(context);
157         variables = context.popExistentialFrame();
158         return this;
159     }
160
161     @Override
162     public Expression decorate(ExpressionDecorator decorator) {
163         return decorator.decorate(this);
164     }
165     
166     @Override
167     public void setLocationDeep(long loc) {
168         if(location == Locations.NO_LOCATION) {
169             location = loc;
170             expression.setLocationDeep(loc);
171             query.setLocationDeep(loc);
172         }
173     }
174     
175     @Override
176     public void accept(ExpressionVisitor visitor) {
177         visitor.visit(this);
178     }
179
180     @Override
181     public void forVariables(VariableProcedure procedure) {
182         expression.forVariables(procedure);
183         query.forVariables(procedure);
184     }
185     
186     @Override
187     public Expression simplify(SimplificationContext context) {
188         throw new UnsupportedOperationException();
189     }
190     
191     @Override
192     public Expression accept(ExpressionTransformer transformer) {
193         return transformer.transform(this);
194     }
195
196 }