1 package org.simantics.scl.compiler.elaboration.expressions;
\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
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
33 public class ESelect extends SimplifiableExpression {
\r
35 private final Type ARRAY_LIST = Types.con("ArrayList", "T");
\r
38 Expression expression;
\r
40 Variable[] variables;
\r
42 public ESelect(int selectVariant, Expression expression, Query query) {
\r
43 this.selectVariant = selectVariant;
\r
44 this.expression = expression;
\r
49 public void collectRefs(TObjectIntHashMap<Object> allRefs,
\r
51 expression.collectRefs(allRefs, refs);
\r
52 query.collectRefs(allRefs, refs);
\r
56 public void collectVars(TObjectIntHashMap<Variable> allVars,
\r
58 expression.collectVars(allVars, vars);
\r
59 query.collectVars(allVars, vars);
\r
63 public void collectEffects(THashSet<Type> effects) {
\r
64 throw new InternalCompilerError(location, getClass().getSimpleName() + " does not support collectEffects.");
\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
75 public Expression checkBasicType(TypingContext context, Type requiredType) {
\r
77 switch(selectVariant) {
\r
78 case SCLTerminals.SELECT:
\r
79 case SCLTerminals.SELECT_DISTINCT:
\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
87 case SCLTerminals.SELECT_FIRST:
\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
95 default: throw new InternalCompilerError();
\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
103 Type elType = expression.getType();
\r
105 if(selectVariant == SCLTerminals.SELECT_FIRST) {
\r
106 QueryCompilationContext queryCompilationContext =
\r
107 new QueryCompilationContext(context, QueryCompilationMode.GET_FIRST,
\r
108 expression.getType(),
\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
116 result = queryCompilationContext.getContinuation();
\r
119 Variable accumulator = newVar("accum", Types.apply(ARRAY_LIST, elType));
\r
121 apply(context, Types.PROC, Name.create("ArrayList", "freeze"), elType,
\r
123 Expression innerExpression =
\r
124 apply(context, Types.PROC, Name.create("ArrayList", "add"), elType,
\r
125 var(accumulator), expression);
\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
135 result = let(accumulator,
\r
136 apply(context, Types.PROC, Name.create("ArrayList", "new"), elType, tuple()),
\r
140 return loc(location, result);
\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
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
161 public Expression decorate(ExpressionDecorator decorator) {
\r
162 return decorator.decorate(this);
\r
166 public void setLocationDeep(long loc) {
\r
167 if(location == Locations.NO_LOCATION) {
\r
169 expression.setLocationDeep(loc);
\r
170 query.setLocationDeep(loc);
\r
175 public void accept(ExpressionVisitor visitor) {
\r
176 visitor.visit(this);
\r
180 public void forVariables(VariableProcedure procedure) {
\r
181 expression.forVariables(procedure);
\r
182 query.forVariables(procedure);
\r
186 public Expression simplify(SimplificationContext context) {
\r
187 throw new UnsupportedOperationException();
\r
191 public Expression accept(ExpressionTransformer transformer) {
\r
192 return transformer.transform(this);
\r