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