]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/expressions/ESelect.java
Merge "LabelDecorator.decorateLabel can return null"
[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 public class ESelect extends SimplifiableExpression {
30
31     private final Type ARRAY_LIST = Types.con("ArrayList", "T"); 
32     
33     int selectVariant;
34     public Expression expression;
35     public Query query;
36     public Variable[] variables;
37     
38     public ESelect(int selectVariant, Expression expression, Query query) {
39         this.selectVariant = selectVariant;
40         this.expression = expression;
41         this.query = query;
42     }
43
44     @Override
45     protected void updateType() throws MatchException {
46         setType(selectVariant==SCLTerminals.SELECT_FIRST 
47                 ? Types.apply(Types.MAYBE, expression.getType()) 
48                 : Types.list(expression.getType()));
49     }
50     
51     @Override
52     public Expression checkBasicType(TypingContext context, Type requiredType) {
53         Type componentType;
54         switch(selectVariant) {
55         case SCLTerminals.SELECT:
56         case SCLTerminals.SELECT_DISTINCT:
57             try {
58                 componentType = Types.unifyApply(Types.LIST, requiredType);
59             } catch (MatchException e) {
60                 context.getErrorLog().log(location, "Select expression produces a list of values.");
61                 return new EError(location);
62             }
63             break;
64         case SCLTerminals.SELECT_FIRST:
65             try {
66                 componentType = Types.unifyApply(Types.MAYBE, requiredType);
67             } catch (MatchException e) {
68                 context.getErrorLog().log(location, "Select first expression produces an optional value.");
69                 return new EError(location);
70             }
71             break;
72         default: throw new InternalCompilerError();
73         }
74         for(Variable variable : variables)
75             variable.setType(Types.metaVar(Kinds.STAR));
76         expression.checkType(context, componentType);
77         query.checkType(context);
78         
79         // Compile query
80         Type elType = expression.getType();
81         Expression result;
82         if(selectVariant == SCLTerminals.SELECT_FIRST) {
83             QueryCompilationContext queryCompilationContext =
84                     new QueryCompilationContext(context, QueryCompilationMode.GET_FIRST,
85                             expression.getType(),
86                             Just(expression));
87             try {
88                 new QExists(variables, query).generate(queryCompilationContext);
89             } catch (UnsolvableQueryException e) {
90                 context.getErrorLog().log(getLocation(), "Failed to compile the query.\n" + e.getMessage());
91                 return new EError(getLocation());
92             }
93             result = queryCompilationContext.getContinuation();
94         }
95         else {
96             Variable accumulator = newVar("accum", Types.apply(ARRAY_LIST, elType));
97             result =
98                     apply(context.getCompilationContext(), Types.PROC, Names.ArrayList_freeze, elType,
99                             var(accumulator));
100             Expression innerExpression = 
101                     apply(context.getCompilationContext(), Types.PROC, Names.ArrayList_add, elType,
102                             var(accumulator), expression);
103             try {
104                 QueryCompilationContext queryCompilationContext =
105                         new QueryCompilationContext(context, QueryCompilationMode.ITERATE, null, innerExpression);
106                 new QExists(variables, query).generate(queryCompilationContext);
107                 result = seq(queryCompilationContext.getContinuation(), result);
108             } catch(UnsolvableQueryException e) {
109                 context.getErrorLog().log(getLocation(), "Failed to compile the query.\n" + e.getMessage());
110                 return new EError(getLocation());
111             }
112             result = let(accumulator,
113                     apply(context.getCompilationContext(), Types.PROC, Names.ArrayList_new, elType, tuple()),
114                     result
115                     );
116         }
117         return loc(location, result);
118     }
119
120     @Override
121     public Expression resolve(TranslationContext context) {
122         context.pushExistentialFrame();
123         expression = expression.resolve(context);
124         query = query.resolve(context);
125         variables = context.popExistentialFrame();
126         return this;
127     }
128     
129     @Override
130     public void setLocationDeep(long loc) {
131         if(location == Locations.NO_LOCATION) {
132             location = loc;
133             expression.setLocationDeep(loc);
134             query.setLocationDeep(loc);
135         }
136     }
137     
138     @Override
139     public void accept(ExpressionVisitor visitor) {
140         visitor.visit(this);
141     }
142     
143     @Override
144     public Expression simplify(SimplificationContext context) {
145         throw new UnsupportedOperationException();
146     }
147     
148     @Override
149     public Expression accept(ExpressionTransformer transformer) {
150         return transformer.transform(this);
151     }
152
153 }