1 package org.simantics.scl.compiler.elaboration.expressions;
3 import java.util.ArrayList;
5 import org.simantics.scl.compiler.common.exceptions.InternalCompilerError;
6 import org.simantics.scl.compiler.common.precedence.Precedence;
7 import org.simantics.scl.compiler.compilation.CompilationContext;
8 import org.simantics.scl.compiler.constants.NoRepConstant;
9 import org.simantics.scl.compiler.elaboration.contexts.ReplaceContext;
10 import org.simantics.scl.compiler.elaboration.contexts.SimplificationContext;
11 import org.simantics.scl.compiler.elaboration.contexts.TranslationContext;
12 import org.simantics.scl.compiler.elaboration.contexts.TypingContext;
13 import org.simantics.scl.compiler.elaboration.errors.NotPatternException;
14 import org.simantics.scl.compiler.elaboration.expressions.lhstype.LhsType;
15 import org.simantics.scl.compiler.elaboration.expressions.lhstype.PatternMatchingLhs;
16 import org.simantics.scl.compiler.elaboration.expressions.printing.ExpressionToStringVisitor;
17 import org.simantics.scl.compiler.elaboration.expressions.visitors.CollectEffectsVisitor;
18 import org.simantics.scl.compiler.elaboration.expressions.visitors.CollectRefsVisitor;
19 import org.simantics.scl.compiler.elaboration.expressions.visitors.ForVariablesUsesVisitor;
20 import org.simantics.scl.compiler.elaboration.query.QAtom;
21 import org.simantics.scl.compiler.elaboration.relations.SCLRelation;
22 import org.simantics.scl.compiler.internal.codegen.references.IVal;
23 import org.simantics.scl.compiler.internal.codegen.writer.CodeWriter;
24 import org.simantics.scl.compiler.internal.elaboration.decomposed.DecomposedExpression;
25 import org.simantics.scl.compiler.internal.interpreted.IExpression;
26 import org.simantics.scl.compiler.internal.parsing.Symbol;
27 import org.simantics.scl.compiler.top.ExpressionInterpretationContext;
28 import org.simantics.scl.compiler.types.TForAll;
29 import org.simantics.scl.compiler.types.TFun;
30 import org.simantics.scl.compiler.types.TPred;
31 import org.simantics.scl.compiler.types.TVar;
32 import org.simantics.scl.compiler.types.Type;
33 import org.simantics.scl.compiler.types.Types;
34 import org.simantics.scl.compiler.types.exceptions.MatchException;
35 import org.simantics.scl.compiler.types.kinds.Kinds;
36 import org.simantics.scl.compiler.types.util.Typed;
38 import gnu.trove.map.hash.TObjectIntHashMap;
39 import gnu.trove.set.hash.THashSet;
40 import gnu.trove.set.hash.TIntHashSet;
42 public abstract class Expression extends Symbol implements Typed {
43 public static final Expression[] EMPTY_ARRAY = new Expression[0];
51 public Expression(long loc) {
56 public Type getType() {
60 } catch (MatchException e) {
61 throw new InternalCompilerError(e);
64 throw new InternalCompilerError(getClass().getSimpleName() +
65 ".updateType couldn't compute its type.");
70 public void setType(Type type) {
72 throw new NullPointerException();
77 * Infers the type of the expression without any context. Adds type
78 * applications and lambdas if needed.
80 public Expression inferType(TypingContext context) {
81 return checkBasicType(context, Types.metaVar(Kinds.STAR));
84 public Expression checkBasicType(TypingContext context, Type requiredType) {
85 return context.subsume(inferType(context), requiredType);
88 protected Expression applyPUnit(TypingContext context) {
89 Type type = Types.canonical(getType());
90 if(type instanceof TFun) {
91 TFun fun = (TFun)type;
92 if(fun.getCanonicalDomain() == Types.PUNIT) {
93 EApply result = new EApply(location, this, new ELiteral(NoRepConstant.PUNIT));
94 result.effect = fun.getCanonicalEffect();
95 context.declareEffect(this.location, result.effect);
102 public Expression checkIgnoredType(TypingContext context) {
103 Expression expression = inferType(context);
104 if(Types.canonical(expression.getType()) != Types.UNIT)
105 expression = new ESimpleLet(location, null, expression, new ELiteral(NoRepConstant.PUNIT));
110 * Checks the type of the expression against the given type. Adds type
111 * applications and lambdas if needed.
113 public final Expression checkType(TypingContext context, Type requiredType) {
114 //System.out.println("checkType: " + this + " :: " + requiredType);
115 if(!context.isInPattern()) {
116 requiredType = Types.canonical(requiredType);
117 if(requiredType instanceof TForAll) {
118 TForAll forAll = (TForAll)requiredType;
119 TVar var = forAll.var;
120 TVar newVar = Types.var(var.getKind());
121 requiredType = Types.canonical(forAll.type).replace(var, newVar);
122 return new ELambdaType(new TVar[] {newVar}, checkType(context, requiredType));
124 while(requiredType instanceof TFun) {
125 TFun fun = (TFun)requiredType;
126 if(fun.domain instanceof TPred) { // No need to canonicalize
127 ArrayList<Variable> constraints = new ArrayList<Variable>(2);
129 constraints.add(new Variable("constraint", fun.domain));
130 requiredType = Types.canonical(fun.range);
131 if(!(requiredType instanceof TFun))
133 fun = (TFun)requiredType;
134 if(!(fun.domain instanceof TPred))
137 context.pushConstraintFrame(constraints.toArray(new Variable[constraints.size()]));
138 Expression expression = checkType(context, requiredType);
139 context.popConstraintFrame();
140 for(int i=constraints.size()-1;i>=0;--i)
141 expression = new ESimpleLambda(constraints.get(i), expression);
144 else if(fun.domain == Types.PUNIT) {
145 context.pushEffectUpperBound(location, fun.effect);
146 Expression expr = checkType(context, fun.range);
147 context.popEffectUpperBound();
150 Variable var = new Variable("punit", Types.PUNIT);
151 return new ESimpleLambda(location, var, fun.effect, expr);
157 return checkBasicType(context, requiredType);
160 public final void collectRefs(TObjectIntHashMap<Object> allRefs, TIntHashSet refs) {
161 accept(new CollectRefsVisitor(allRefs, refs));
164 public abstract void collectVars(TObjectIntHashMap<Variable> allVars, TIntHashSet vars);
166 public final void forVariableUses(VariableProcedure procedure) {
167 accept(new ForVariablesUsesVisitor(procedure));
170 public Expression decomposeMatching() {
174 public String toString() {
175 StringBuilder b = new StringBuilder();
176 ExpressionToStringVisitor visitor = new ExpressionToStringVisitor(b);
181 protected abstract void updateType() throws MatchException;
183 public static class TypeValidationException extends Exception {
184 private static final long serialVersionUID = 3181298127162041248L;
188 public TypeValidationException(long loc) {
192 public long getLoc() {
196 public TypeValidationException(long loc, Throwable cause) {
202 public static void assertEquals(long loc, Type a, Type b) throws TypeValidationException {
203 if(!Types.equals(a, b))
204 throw new TypeValidationException(loc);
207 public abstract IVal toVal(CompilationContext context, CodeWriter w);
209 public Expression closure(TVar ... vars) {
212 return new ELambdaType(vars, this);
215 public abstract void collectFreeVariables(THashSet<Variable> vars);
217 public Expression simplify(SimplificationContext context) {
218 System.out.println("#############################");
219 System.out.println(this);
220 throw new InternalCompilerError(location, getClass().getSimpleName() + " does not support simplify method.");
223 public abstract Expression resolve(TranslationContext context);
226 * Returns head of the pattern.
228 public EVar getPatternHead() throws NotPatternException {
229 throw new NotPatternException(this);
232 public LhsType getLhsType() throws NotPatternException {
233 throw new NotPatternException(this);
236 protected void collectVariableNames(PatternMatchingLhs lhsType) throws NotPatternException {
237 throw new NotPatternException(this);
240 public void getParameters(TranslationContext translationContext,
241 ArrayList<Expression> parameters) {
242 throw new InternalCompilerError("Class " + getClass().getSimpleName() + " does not support getParameters.");
245 public Expression resolveAsPattern(TranslationContext context) {
246 context.getErrorLog().log(location, "Pattern was expected here.");
250 public void removeFreeVariables(THashSet<Variable> vars) {
251 throw new InternalCompilerError(getClass().getSimpleName() + " is not a pattern.");
254 public Expression checkTypeAsPattern(TypingContext context, Type requiredType) {
255 if(context.isInPattern())
256 throw new InternalCompilerError("Already in a pattern.");
257 context.setInPattern(true);
258 Expression expression = checkType(context, requiredType);
259 context.setInPattern(false);
264 * Used during simplification and in toIExpression
266 public THashSet<Variable> getFreeVariables() {
267 THashSet<Variable> result = new THashSet<Variable>();
268 collectFreeVariables(result);
272 public static Expression[] concat(Expression[] a, Expression[] b) {
277 Expression[] result = new Expression[a.length + b.length];
278 for(int i=0;i<a.length;++i)
280 for(int i=0;i<b.length;++i)
281 result[i+a.length] = b[i];
285 public Expression replace(ReplaceContext context) {
286 throw new InternalCompilerError(getClass().getSimpleName() + " does not support replace.");
289 public static Expression[] replace(ReplaceContext context, Expression[] expressions) {
290 Expression[] result = new Expression[expressions.length];
291 for(int i=0;i<expressions.length;++i)
292 result[i] = expressions[i].replace(context);
296 public Expression copy() {
297 return replace(new ReplaceContext(null));
300 public Expression copy(TypingContext typingContext) {
301 return replace(new ReplaceContext(typingContext));
304 public abstract void setLocationDeep(long loc);
306 public Expression replaceInPattern(ReplaceContext context) {
307 context.inPattern = true;
308 Expression result = replace(context);
309 context.inPattern = false;
313 public int getFunctionDefinitionPatternArity() throws NotPatternException {
314 throw new NotPatternException(this);
317 public IVal lambdaToVal(CompilationContext context, CodeWriter w) {
318 DecomposedExpression decomposed = DecomposedExpression.decompose(context.errorLog, this);
319 CodeWriter newW = w.createFunction(decomposed.typeParameters, decomposed.effect, decomposed.returnType, decomposed.parameterTypes);
320 IVal[] parameters = newW.getParameters();
321 IVal functionVal = newW.getFunction().getTarget();
322 for(int i=0;i<parameters.length;++i)
323 decomposed.parameters[i].setVal(parameters[i]);
324 newW.return_(decomposed.body.toVal(context, newW));
328 public IExpression toIExpression(ExpressionInterpretationContext context) {
329 throw new UnsupportedOperationException();
332 public static IExpression[] toIExpressions(ExpressionInterpretationContext target, Expression[] expressions) {
333 IExpression[] result = new IExpression[expressions.length];
334 for(int i=0;i<expressions.length;++i)
335 result[i] = expressions[i].toIExpression(target);
339 public Expression applyType(Type type) {
340 return new EApplyType(location, this, type);
343 public boolean isEffectful() {
347 public boolean isFunctionPattern() {
351 public boolean isConstructorApplication() {
355 public Type getEffect() {
356 CollectEffectsVisitor visitor = new CollectEffectsVisitor();
358 return visitor.getCombinedEffect();
361 public abstract void accept(ExpressionVisitor visitor);
363 public void collectRelationRefs(
364 final TObjectIntHashMap<SCLRelation> allRefs, final TIntHashSet refs) {
365 accept(new StandardExpressionVisitor() {
367 public void visit(QAtom query) {
368 int id = allRefs.get(query.relation);
375 public boolean isFunctionDefinitionLhs() {
379 public Precedence getPrecedence() {
380 return Precedence.DEFAULT;
383 public boolean isPattern(int arity) {
387 public abstract Expression accept(ExpressionTransformer transformer);
389 // TODO implement for all expressions
390 public boolean equalsExpression(Expression expression) {
395 * This method returns a lower bound for the function arity of the value this expression defines.
396 * The lower bound is calculated purely looking the syntax of the expression, not the
397 * types of the constants and variables the expression refers to.
399 public int getSyntacticFunctionArity() {