1 package org.simantics.scl.compiler.elaboration.expressions;
\r
3 import java.util.ArrayList;
\r
5 import org.simantics.scl.compiler.common.exceptions.InternalCompilerError;
\r
6 import org.simantics.scl.compiler.common.precedence.Precedence;
\r
7 import org.simantics.scl.compiler.constants.NoRepConstant;
\r
8 import org.simantics.scl.compiler.elaboration.contexts.EnvironmentalContext;
\r
9 import org.simantics.scl.compiler.elaboration.contexts.ReplaceContext;
\r
10 import org.simantics.scl.compiler.elaboration.contexts.SimplificationContext;
\r
11 import org.simantics.scl.compiler.elaboration.contexts.TranslationContext;
\r
12 import org.simantics.scl.compiler.elaboration.contexts.TypingContext;
\r
13 import org.simantics.scl.compiler.elaboration.errors.NotPatternException;
\r
14 import org.simantics.scl.compiler.elaboration.expressions.lhstype.LhsType;
\r
15 import org.simantics.scl.compiler.elaboration.expressions.lhstype.PatternMatchingLhs;
\r
16 import org.simantics.scl.compiler.elaboration.expressions.printing.ExpressionToStringVisitor;
\r
17 import org.simantics.scl.compiler.elaboration.query.QAtom;
\r
18 import org.simantics.scl.compiler.elaboration.relations.SCLRelation;
\r
19 import org.simantics.scl.compiler.environment.Environment;
\r
20 import org.simantics.scl.compiler.internal.codegen.references.IVal;
\r
21 import org.simantics.scl.compiler.internal.codegen.writer.CodeWriter;
\r
22 import org.simantics.scl.compiler.internal.elaboration.decomposed.DecomposedExpression;
\r
23 import org.simantics.scl.compiler.internal.elaboration.utils.ExpressionDecorator;
\r
24 import org.simantics.scl.compiler.internal.interpreted.IExpression;
\r
25 import org.simantics.scl.compiler.internal.parsing.Symbol;
\r
26 import org.simantics.scl.compiler.top.ExpressionInterpretationContext;
\r
27 import org.simantics.scl.compiler.types.TForAll;
\r
28 import org.simantics.scl.compiler.types.TFun;
\r
29 import org.simantics.scl.compiler.types.TPred;
\r
30 import org.simantics.scl.compiler.types.TVar;
\r
31 import org.simantics.scl.compiler.types.Type;
\r
32 import org.simantics.scl.compiler.types.Types;
\r
33 import org.simantics.scl.compiler.types.exceptions.MatchException;
\r
34 import org.simantics.scl.compiler.types.kinds.Kinds;
\r
35 import org.simantics.scl.compiler.types.util.Typed;
\r
37 import gnu.trove.map.hash.TObjectIntHashMap;
\r
38 import gnu.trove.set.hash.THashSet;
\r
39 import gnu.trove.set.hash.TIntHashSet;
\r
41 public abstract class Expression extends Symbol implements Typed {
\r
42 public static final Expression[] EMPTY_ARRAY = new Expression[0];
\r
47 public Expression() {
\r
50 public Expression(long loc) {
\r
51 this.location = loc;
\r
55 public Type getType() {
\r
59 } catch (MatchException e) {
\r
60 throw new InternalCompilerError(e);
\r
63 throw new InternalCompilerError(getClass().getSimpleName() +
\r
64 ".updateType couldn't compute its type.");
\r
69 public void setType(Type type) {
\r
71 throw new NullPointerException();
\r
76 * Infers the type of the expression without any context. Adds type
\r
77 * applications and lambdas if needed.
\r
79 public Expression inferType(TypingContext context) {
\r
80 return checkBasicType(context, Types.metaVar(Kinds.STAR));
\r
83 public Expression checkBasicType(TypingContext context, Type requiredType) {
\r
84 return context.subsume(inferType(context), requiredType);
\r
87 protected Expression applyPUnit(EnvironmentalContext context) {
\r
88 Type type = Types.canonical(getType());
\r
89 if(type instanceof TFun) {
\r
90 TFun fun = (TFun)type;
\r
91 if(fun.getCanonicalDomain() == Types.PUNIT) {
\r
92 EApply result = new EApply(location, this, new ELiteral(NoRepConstant.PUNIT));
\r
93 result.effect = fun.getCanonicalEffect();
\r
100 public Expression checkIgnoredType(TypingContext context) {
\r
101 Expression expression = inferType(context);
\r
102 if(Types.canonical(expression.getType()) != Types.UNIT)
\r
103 expression = new ESimpleLet(location, null, expression, new ELiteral(NoRepConstant.PUNIT));
\r
108 * Checks the type of the expression against the given type. Adds type
\r
109 * applications and lambdas if needed.
\r
111 public final Expression checkType(TypingContext context, Type requiredType) {
\r
112 //System.out.println("checkType: " + this + " :: " + requiredType);
\r
113 if(!context.isInPattern()) {
\r
114 requiredType = Types.canonical(requiredType);
\r
115 if(requiredType instanceof TForAll) {
\r
116 TForAll forAll = (TForAll)requiredType;
\r
117 TVar var = forAll.var;
\r
118 TVar newVar = Types.var(var.getKind());
\r
119 requiredType = Types.canonical(forAll.type).replace(var, newVar);
\r
120 return new ELambdaType(new TVar[] {newVar}, checkType(context, requiredType));
\r
122 while(requiredType instanceof TFun) {
\r
123 TFun fun = (TFun)requiredType;
\r
124 if(fun.domain instanceof TPred) { // No need to canonicalize
\r
125 ArrayList<Variable> constraints = new ArrayList<Variable>(2);
\r
127 constraints.add(new Variable("constraint", fun.domain));
\r
128 requiredType = Types.canonical(fun.range);
\r
129 if(!(requiredType instanceof TFun))
\r
131 fun = (TFun)requiredType;
\r
132 if(!(fun.domain instanceof TPred))
\r
135 context.pushConstraintFrame(constraints.toArray(new Variable[constraints.size()]));
\r
136 Expression expression = checkType(context, requiredType);
\r
137 context.popConstraintFrame();
\r
138 for(int i=constraints.size()-1;i>=0;--i)
\r
139 expression = new ESimpleLambda(constraints.get(i), expression);
\r
142 else if(fun.domain == Types.PUNIT) {
\r
143 context.pushEffectUpperBound(location, fun.effect);
\r
144 Expression expr = checkType(context, fun.range);
\r
145 context.popEffectUpperBound();
\r
148 Variable var = new Variable("punit", Types.PUNIT);
\r
149 return new ESimpleLambda(location, var, fun.effect, expr);
\r
155 return checkBasicType(context, requiredType);
\r
158 public abstract void collectRefs(TObjectIntHashMap<Object> allRefs, TIntHashSet refs);
\r
159 public abstract void collectVars(TObjectIntHashMap<Variable> allVars, TIntHashSet vars);
\r
160 public abstract void forVariables(VariableProcedure procedure);
\r
162 public Expression decomposeMatching() {
\r
166 public String toString() {
\r
167 StringBuilder b = new StringBuilder();
\r
168 ExpressionToStringVisitor visitor = new ExpressionToStringVisitor(b);
\r
170 return b.toString();
\r
173 protected abstract void updateType() throws MatchException;
\r
175 public static class TypeValidationException extends Exception {
\r
176 private static final long serialVersionUID = 3181298127162041248L;
\r
180 public TypeValidationException(long loc) {
\r
184 public long getLoc() {
\r
188 public TypeValidationException(long loc, Throwable cause) {
\r
194 public static void assertEquals(long loc, Type a, Type b) throws TypeValidationException {
\r
195 if(!Types.equals(a, b))
\r
196 throw new TypeValidationException(loc);
\r
199 public abstract IVal toVal(Environment env, CodeWriter w);
\r
201 public Expression closure(TVar ... vars) {
\r
202 if(vars.length == 0)
\r
204 return new ELambdaType(vars, this);
\r
207 public abstract void collectFreeVariables(THashSet<Variable> vars);
\r
209 public Expression simplify(SimplificationContext context) {
\r
210 throw new InternalCompilerError(location, getClass().getSimpleName() + " does not support simplify method.");
\r
213 public abstract Expression resolve(TranslationContext context);
\r
216 * Returns head of the pattern.
\r
218 public EVar getPatternHead() throws NotPatternException {
\r
219 throw new NotPatternException(this);
\r
222 public LhsType getLhsType() throws NotPatternException {
\r
223 throw new NotPatternException(this);
\r
226 protected void collectVariableNames(PatternMatchingLhs lhsType) throws NotPatternException {
\r
227 throw new NotPatternException(this);
\r
230 public void getParameters(TranslationContext translationContext,
\r
231 ArrayList<Expression> parameters) {
\r
232 throw new InternalCompilerError("Class " + getClass().getSimpleName() + " does not support getParameters.");
\r
235 public Expression resolveAsPattern(TranslationContext context) {
\r
236 context.getErrorLog().log(location, "Pattern was expected here.");
\r
237 return new EError();
\r
240 public void removeFreeVariables(THashSet<Variable> vars) {
\r
241 throw new InternalCompilerError(getClass().getSimpleName() + " is not a pattern.");
\r
244 public Expression checkTypeAsPattern(TypingContext context, Type requiredType) {
\r
245 if(context.isInPattern())
\r
246 throw new InternalCompilerError("Already in a pattern.");
\r
247 context.setInPattern(true);
\r
248 Expression expression = checkType(context, requiredType);
\r
249 context.setInPattern(false);
\r
253 public THashSet<Variable> getFreeVariables() {
\r
254 THashSet<Variable> result = new THashSet<Variable>();
\r
255 collectFreeVariables(result);
\r
259 public static Expression[] concat(Expression[] a, Expression[] b) {
\r
264 Expression[] result = new Expression[a.length + b.length];
\r
265 for(int i=0;i<a.length;++i)
\r
267 for(int i=0;i<b.length;++i)
\r
268 result[i+a.length] = b[i];
\r
272 public Expression replace(ReplaceContext context) {
\r
273 throw new InternalCompilerError(getClass().getSimpleName() + " does not support replace.");
\r
276 public static Expression[] replace(ReplaceContext context, Expression[] expressions) {
\r
277 Expression[] result = new Expression[expressions.length];
\r
278 for(int i=0;i<expressions.length;++i)
\r
279 result[i] = expressions[i].replace(context);
\r
283 public Expression copy() {
\r
284 return replace(new ReplaceContext(null));
\r
287 public Expression copy(TypingContext typingContext) {
\r
288 return replace(new ReplaceContext(typingContext));
\r
291 public abstract void setLocationDeep(long loc);
\r
293 public Expression replaceInPattern(ReplaceContext context) {
\r
294 context.inPattern = true;
\r
295 Expression result = replace(context);
\r
296 context.inPattern = false;
\r
300 public int getFunctionDefinitionArity() throws NotPatternException {
\r
301 throw new NotPatternException(this);
\r
304 public IVal lambdaToVal(Environment env, CodeWriter w) {
\r
305 DecomposedExpression decomposed = DecomposedExpression.decompose(this);
\r
306 CodeWriter newW = w.createFunction(decomposed.typeParameters, decomposed.effect, decomposed.returnType, decomposed.parameterTypes);
\r
307 IVal[] parameters = newW.getParameters();
\r
308 IVal functionVal = newW.getFunction().getTarget();
\r
309 for(int i=0;i<parameters.length;++i)
\r
310 decomposed.parameters[i].setVal(parameters[i]);
\r
311 newW.return_(decomposed.body.toVal(env, newW));
\r
312 return functionVal;
\r
315 public IExpression toIExpression(ExpressionInterpretationContext context) {
\r
316 throw new UnsupportedOperationException();
\r
319 public static IExpression[] toIExpressions(ExpressionInterpretationContext target, Expression[] expressions) {
\r
320 IExpression[] result = new IExpression[expressions.length];
\r
321 for(int i=0;i<expressions.length;++i)
\r
322 result[i] = expressions[i].toIExpression(target);
\r
326 public Expression applyType(Type type) {
\r
327 return new EApplyType(location, this, type);
\r
330 public abstract Expression decorate(ExpressionDecorator decorator);
\r
332 public boolean isEffectful() {
\r
336 public boolean isFunctionPattern() {
\r
340 public boolean isConstructorApplication() {
\r
344 public abstract void collectEffects(THashSet<Type> effects);
\r
346 public Type getEffect() {
\r
347 THashSet<Type> effects = new THashSet<Type>();
\r
348 collectEffects(effects);
\r
349 return Types.union(effects.toArray(new Type[effects.size()]));
\r
352 public abstract void accept(ExpressionVisitor visitor);
\r
354 public void collectRelationRefs(
\r
355 final TObjectIntHashMap<SCLRelation> allRefs, final TIntHashSet refs) {
\r
356 accept(new StandardExpressionVisitor() {
\r
358 public void visit(QAtom query) {
\r
359 int id = allRefs.get(query.relation);
\r
366 public boolean isFunctionDefinitionLhs() {
\r
370 public Precedence getPrecedence() {
\r
371 return Precedence.DEFAULT;
\r
374 public boolean isPattern(int arity) {
\r
378 public abstract Expression accept(ExpressionTransformer transformer);
\r