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