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.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;
29 public class ESelect extends SimplifiableExpression {
31 private final Type ARRAY_LIST = Types.con("ArrayList", "T");
34 public Expression expression;
36 public Variable[] variables;
38 public ESelect(int selectVariant, Expression expression, Query query) {
39 this.selectVariant = selectVariant;
40 this.expression = expression;
45 protected void updateType() throws MatchException {
46 setType(selectVariant==SCLTerminals.SELECT_FIRST
47 ? Types.apply(Types.MAYBE, expression.getType())
48 : Types.list(expression.getType()));
52 public Expression checkBasicType(TypingContext context, Type requiredType) {
54 switch(selectVariant) {
55 case SCLTerminals.SELECT:
56 case SCLTerminals.SELECT_DISTINCT:
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);
64 case SCLTerminals.SELECT_FIRST:
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);
72 default: throw new InternalCompilerError();
74 for(Variable variable : variables)
75 variable.setType(Types.metaVar(Kinds.STAR));
76 expression.checkType(context, componentType);
77 query.checkType(context);
80 Type elType = expression.getType();
82 if(selectVariant == SCLTerminals.SELECT_FIRST) {
83 QueryCompilationContext queryCompilationContext =
84 new QueryCompilationContext(context, QueryCompilationMode.GET_FIRST,
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());
93 result = queryCompilationContext.getContinuation();
96 Variable accumulator = newVar("accum", Types.apply(ARRAY_LIST, elType));
98 apply(context.getCompilationContext(), Types.PROC, Names.ArrayList_freeze, elType,
100 Expression innerExpression =
101 apply(context.getCompilationContext(), Types.PROC, Names.ArrayList_add, elType,
102 var(accumulator), expression);
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());
112 result = let(accumulator,
113 apply(context.getCompilationContext(), Types.PROC, Names.ArrayList_new, elType, tuple()),
117 return loc(location, result);
121 public Expression resolve(TranslationContext context) {
122 context.pushExistentialFrame();
123 expression = expression.resolve(context);
124 query = query.resolve(context);
125 variables = context.popExistentialFrame();
130 public void setLocationDeep(long loc) {
131 if(location == Locations.NO_LOCATION) {
133 expression.setLocationDeep(loc);
134 query.setLocationDeep(loc);
139 public void accept(ExpressionVisitor visitor) {
144 public Expression simplify(SimplificationContext context) {
145 throw new UnsupportedOperationException();
149 public Expression accept(ExpressionTransformer transformer) {
150 return transformer.transform(this);