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