1 package org.simantics.scl.compiler.elaboration.expressions;
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;
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.elaboration.utils.ExpressionDecorator;
24 import org.simantics.scl.compiler.internal.parsing.parser.SCLTerminals;
25 import org.simantics.scl.compiler.types.Type;
26 import org.simantics.scl.compiler.types.Types;
27 import org.simantics.scl.compiler.types.exceptions.MatchException;
28 import org.simantics.scl.compiler.types.kinds.Kinds;
30 import gnu.trove.map.hash.TObjectIntHashMap;
31 import gnu.trove.set.hash.THashSet;
32 import gnu.trove.set.hash.TIntHashSet;
34 public class ESelect extends SimplifiableExpression {
36 private final Type ARRAY_LIST = Types.con("ArrayList", "T");
39 Expression expression;
43 public ESelect(int selectVariant, Expression expression, Query query) {
44 this.selectVariant = selectVariant;
45 this.expression = expression;
50 public void collectRefs(TObjectIntHashMap<Object> allRefs,
52 expression.collectRefs(allRefs, refs);
53 query.collectRefs(allRefs, refs);
57 public void collectVars(TObjectIntHashMap<Variable> allVars,
59 expression.collectVars(allVars, vars);
60 query.collectVars(allVars, vars);
64 public void collectEffects(THashSet<Type> effects) {
65 throw new InternalCompilerError(location, getClass().getSimpleName() + " does not support collectEffects.");
69 protected void updateType() throws MatchException {
70 setType(selectVariant==SCLTerminals.SELECT_FIRST
71 ? Types.apply(Types.MAYBE, expression.getType())
72 : Types.list(expression.getType()));
76 public Expression checkBasicType(TypingContext context, Type requiredType) {
78 switch(selectVariant) {
79 case SCLTerminals.SELECT:
80 case SCLTerminals.SELECT_DISTINCT:
82 componentType = Types.unifyApply(Types.LIST, requiredType);
83 } catch (MatchException e) {
84 context.getErrorLog().log(location, "Select expression produces a list of values.");
85 return new EError(location);
88 case SCLTerminals.SELECT_FIRST:
90 componentType = Types.unifyApply(Types.MAYBE, requiredType);
91 } catch (MatchException e) {
92 context.getErrorLog().log(location, "Select first expression produces an optional value.");
93 return new EError(location);
96 default: throw new InternalCompilerError();
98 for(Variable variable : variables)
99 variable.setType(Types.metaVar(Kinds.STAR));
100 expression.checkType(context, componentType);
101 query.checkType(context);
104 Type elType = expression.getType();
106 if(selectVariant == SCLTerminals.SELECT_FIRST) {
107 QueryCompilationContext queryCompilationContext =
108 new QueryCompilationContext(context, QueryCompilationMode.GET_FIRST,
109 expression.getType(),
112 new QExists(variables, query).generate(queryCompilationContext);
113 } catch (UnsolvableQueryException e) {
114 context.getErrorLog().log(getLocation(), "Failed to compile the query.\n" + e.getMessage());
115 return new EError(getLocation());
117 result = queryCompilationContext.getContinuation();
120 Variable accumulator = newVar("accum", Types.apply(ARRAY_LIST, elType));
122 apply(context.getCompilationContext(), Types.PROC, Names.ArrayList_freeze, elType,
124 Expression innerExpression =
125 apply(context.getCompilationContext(), Types.PROC, Names.ArrayList_add, elType,
126 var(accumulator), expression);
128 QueryCompilationContext queryCompilationContext =
129 new QueryCompilationContext(context, QueryCompilationMode.ITERATE, null, innerExpression);
130 new QExists(variables, query).generate(queryCompilationContext);
131 result = seq(queryCompilationContext.getContinuation(), result);
132 } catch(UnsolvableQueryException e) {
133 context.getErrorLog().log(getLocation(), "Failed to compile the query.\n" + e.getMessage());
134 return new EError(getLocation());
136 result = let(accumulator,
137 apply(context.getCompilationContext(), Types.PROC, Names.ArrayList_new, elType, tuple()),
141 return loc(location, result);
145 public void collectFreeVariables(THashSet<Variable> vars) {
146 expression.collectFreeVariables(vars);
147 query.collectFreeVariables(vars);
148 for(Variable variable : variables)
149 vars.remove(variable);
153 public Expression resolve(TranslationContext context) {
154 context.pushExistentialFrame();
155 expression = expression.resolve(context);
156 query = query.resolve(context);
157 variables = context.popExistentialFrame();
162 public Expression decorate(ExpressionDecorator decorator) {
163 return decorator.decorate(this);
167 public void setLocationDeep(long loc) {
168 if(location == Locations.NO_LOCATION) {
170 expression.setLocationDeep(loc);
171 query.setLocationDeep(loc);
176 public void accept(ExpressionVisitor visitor) {
181 public void forVariables(VariableProcedure procedure) {
182 expression.forVariables(procedure);
183 query.forVariables(procedure);
187 public Expression simplify(SimplificationContext context) {
188 throw new UnsupportedOperationException();
192 public Expression accept(ExpressionTransformer transformer) {
193 return transformer.transform(this);