1 package org.simantics.scl.compiler.elaboration.expressions;
3 import java.util.ArrayList;
6 import org.simantics.scl.compiler.common.exceptions.InternalCompilerError;
7 import org.simantics.scl.compiler.common.precedence.Precedence;
8 import org.simantics.scl.compiler.compilation.CompilationContext;
9 import org.simantics.scl.compiler.constants.NoRepConstant;
10 import org.simantics.scl.compiler.elaboration.contexts.ReplaceContext;
11 import org.simantics.scl.compiler.elaboration.contexts.SimplificationContext;
12 import org.simantics.scl.compiler.elaboration.contexts.TranslationContext;
13 import org.simantics.scl.compiler.elaboration.contexts.TypingContext;
14 import org.simantics.scl.compiler.elaboration.errors.NotPatternException;
15 import org.simantics.scl.compiler.elaboration.expressions.lhstype.LhsType;
16 import org.simantics.scl.compiler.elaboration.expressions.lhstype.PatternMatchingLhs;
17 import org.simantics.scl.compiler.elaboration.expressions.printing.ExpressionToStringVisitor;
18 import org.simantics.scl.compiler.elaboration.expressions.visitors.CollectEffectsVisitor;
19 import org.simantics.scl.compiler.elaboration.expressions.visitors.CollectFreeVariablesVisitor;
20 import org.simantics.scl.compiler.elaboration.expressions.visitors.CollectRefsVisitor;
21 import org.simantics.scl.compiler.elaboration.expressions.visitors.CollectVarsVisitor;
22 import org.simantics.scl.compiler.elaboration.expressions.visitors.ForVariablesUsesVisitor;
23 import org.simantics.scl.compiler.elaboration.expressions.visitors.StandardExpressionVisitor;
24 import org.simantics.scl.compiler.elaboration.query.QAtom;
25 import org.simantics.scl.compiler.elaboration.relations.SCLRelation;
26 import org.simantics.scl.compiler.internal.codegen.references.IVal;
27 import org.simantics.scl.compiler.internal.codegen.writer.CodeWriter;
28 import org.simantics.scl.compiler.internal.elaboration.decomposed.DecomposedExpression;
29 import org.simantics.scl.compiler.internal.interpreted.IExpression;
30 import org.simantics.scl.compiler.internal.parsing.Symbol;
31 import org.simantics.scl.compiler.top.ExpressionInterpretationContext;
32 import org.simantics.scl.compiler.types.TForAll;
33 import org.simantics.scl.compiler.types.TFun;
34 import org.simantics.scl.compiler.types.TPred;
35 import org.simantics.scl.compiler.types.TVar;
36 import org.simantics.scl.compiler.types.Type;
37 import org.simantics.scl.compiler.types.Types;
38 import org.simantics.scl.compiler.types.exceptions.MatchException;
39 import org.simantics.scl.compiler.types.kinds.Kinds;
40 import org.simantics.scl.compiler.types.util.Typed;
42 import gnu.trove.map.hash.TObjectIntHashMap;
43 import gnu.trove.set.hash.TIntHashSet;
45 public abstract class Expression extends Symbol implements Typed {
46 public static final Expression[] EMPTY_ARRAY = new Expression[0];
54 public Expression(long loc) {
59 public Type getType() {
63 } catch (MatchException e) {
64 throw new InternalCompilerError(location, e);
67 throw new InternalCompilerError(location, getClass().getSimpleName() +
68 ".updateType couldn't compute its type.");
73 public void setType(Type type) {
75 throw new NullPointerException();
80 * Infers the type of the expression without any context. Adds type
81 * applications and lambdas if needed.
83 public Expression inferType(TypingContext context) {
84 return checkBasicType(context, Types.metaVar(Kinds.STAR));
87 public Expression checkBasicType(TypingContext context, Type requiredType) {
88 return context.subsume(inferType(context), requiredType);
91 protected Expression applyPUnit(TypingContext context) {
92 Type type = Types.canonical(getType());
93 if(type instanceof TFun) {
94 TFun fun = (TFun)type;
95 if(fun.getCanonicalDomain() == Types.PUNIT) {
96 EApply result = new EApply(location, this, new ELiteral(NoRepConstant.PUNIT));
97 result.effect = fun.getCanonicalEffect();
98 context.declareEffect(this.location, result.effect);
105 public Expression checkIgnoredType(TypingContext context) {
106 Expression expression = inferType(context);
107 if(Types.canonical(expression.getType()) != Types.UNIT)
108 expression = new ESimpleLet(location, null, expression, new ELiteral(NoRepConstant.PUNIT));
113 * Checks the type of the expression against the given type. Adds type
114 * applications and lambdas if needed.
116 public final Expression checkType(TypingContext context, Type requiredType) {
117 //System.out.println("checkType: " + this + " :: " + requiredType);
118 if(!context.isInPattern()) {
119 requiredType = Types.canonical(requiredType);
120 if(requiredType instanceof TForAll) {
121 TForAll forAll = (TForAll)requiredType;
122 TVar var = forAll.var;
123 TVar newVar = Types.var(var.getKind());
124 requiredType = Types.canonical(forAll.type).replace(var, newVar);
125 return new ELambdaType(new TVar[] {newVar}, checkType(context, requiredType));
127 while(requiredType instanceof TFun) {
128 TFun fun = (TFun)requiredType;
129 if(fun.domain instanceof TPred) { // No need to canonicalize
130 ArrayList<Variable> constraints = new ArrayList<Variable>(2);
132 constraints.add(new Variable("constraint", fun.domain));
133 requiredType = Types.canonical(fun.range);
134 if(!(requiredType instanceof TFun))
136 fun = (TFun)requiredType;
137 if(!(fun.domain instanceof TPred))
140 context.pushConstraintFrame(constraints.toArray(new Variable[constraints.size()]));
141 Expression expression = checkType(context, requiredType);
142 context.popConstraintFrame();
143 for(int i=constraints.size()-1;i>=0;--i)
144 expression = new ESimpleLambda(constraints.get(i), expression);
147 else if(fun.domain == Types.PUNIT) {
148 context.pushEffectUpperBound(location, fun.effect);
149 Expression expr = checkType(context, fun.range);
150 context.popEffectUpperBound();
153 Variable var = new Variable("punit", Types.PUNIT);
154 return new ESimpleLambda(location, var, fun.effect, expr);
160 return checkBasicType(context, requiredType);
163 public final void collectRefs(TObjectIntHashMap<Object> allRefs, TIntHashSet refs) {
164 accept(new CollectRefsVisitor(allRefs, refs));
167 public final void collectVars(TObjectIntHashMap<Variable> allVars, TIntHashSet vars) {
168 accept(new CollectVarsVisitor(allVars, vars));
171 public final void forVariableUses(VariableProcedure procedure) {
172 accept(new ForVariablesUsesVisitor(procedure));
175 public Expression decomposeMatching() {
179 public String toString() {
180 StringBuilder b = new StringBuilder();
181 ExpressionToStringVisitor visitor = new ExpressionToStringVisitor(b);
186 protected abstract void updateType() throws MatchException;
188 public static class TypeValidationException extends Exception {
189 private static final long serialVersionUID = 3181298127162041248L;
193 public TypeValidationException(long loc) {
197 public long getLoc() {
201 public TypeValidationException(long loc, Throwable cause) {
207 public static void assertEquals(long loc, Type a, Type b) throws TypeValidationException {
208 if(!Types.equals(a, b))
209 throw new TypeValidationException(loc);
212 public abstract IVal toVal(CompilationContext context, CodeWriter w);
214 public Expression closure(TVar ... vars) {
217 return new ELambdaType(vars, this);
220 public Expression simplify(SimplificationContext context) {
221 System.out.println("#############################");
222 System.out.println(this);
223 throw new InternalCompilerError(location, getClass().getSimpleName() + " does not support simplify method.");
226 public abstract Expression resolve(TranslationContext context);
229 * Returns head of the pattern.
231 public EVar getPatternHead() throws NotPatternException {
232 throw new NotPatternException(this);
235 public LhsType getLhsType() throws NotPatternException {
236 throw new NotPatternException(this);
239 protected void collectVariableNames(PatternMatchingLhs lhsType) throws NotPatternException {
240 throw new NotPatternException(this);
243 public void getParameters(TranslationContext translationContext,
244 ArrayList<Expression> parameters) {
245 throw new InternalCompilerError(location, "Class " + getClass().getSimpleName() + " does not support getParameters.");
248 public Expression resolveAsPattern(TranslationContext context) {
249 context.getErrorLog().log(location, "Pattern was expected here.");
253 public Expression checkTypeAsPattern(TypingContext context, Type requiredType) {
254 if(context.isInPattern())
255 throw new InternalCompilerError(location, "Already in a pattern.");
256 context.setInPattern(true);
257 Expression expression = checkType(context, requiredType);
258 context.setInPattern(false);
263 * Used during simplification and in toIExpression
265 public Set<Variable> getFreeVariables() {
266 CollectFreeVariablesVisitor visitor = new CollectFreeVariablesVisitor();
268 return visitor.getFreeVariables();
271 public static Expression[] concat(Expression[] a, Expression[] b) {
276 Expression[] result = new Expression[a.length + b.length];
277 for(int i=0;i<a.length;++i)
279 for(int i=0;i<b.length;++i)
280 result[i+a.length] = b[i];
284 public Expression replace(ReplaceContext context) {
285 throw new InternalCompilerError(location, getClass().getSimpleName() + " does not support replace.");
288 public static Expression[] replace(ReplaceContext context, Expression[] expressions) {
289 Expression[] result = new Expression[expressions.length];
290 for(int i=0;i<expressions.length;++i)
291 result[i] = expressions[i].replace(context);
295 public Expression copy() {
296 return replace(new ReplaceContext(null));
299 public Expression copy(TypingContext typingContext) {
300 return replace(new ReplaceContext(typingContext));
303 public abstract void setLocationDeep(long loc);
305 public Expression replaceInPattern(ReplaceContext context) {
306 context.inPattern = true;
307 Expression result = replace(context);
308 context.inPattern = false;
312 public int getFunctionDefinitionPatternArity() throws NotPatternException {
313 throw new NotPatternException(this);
316 public IVal lambdaToVal(CompilationContext context, CodeWriter w) {
317 DecomposedExpression decomposed = DecomposedExpression.decompose(context.errorLog, this);
318 CodeWriter newW = w.createFunction(decomposed.typeParameters, decomposed.effect, decomposed.returnType, decomposed.parameterTypes);
319 IVal[] parameters = newW.getParameters();
320 IVal functionVal = newW.getFunction().getTarget();
321 for(int i=0;i<parameters.length;++i)
322 decomposed.parameters[i].setVal(parameters[i]);
323 newW.return_(decomposed.body.toVal(context, newW));
327 public IExpression toIExpression(ExpressionInterpretationContext context) {
328 throw new UnsupportedOperationException();
331 public static IExpression[] toIExpressions(ExpressionInterpretationContext target, Expression[] expressions) {
332 IExpression[] result = new IExpression[expressions.length];
333 for(int i=0;i<expressions.length;++i)
334 result[i] = expressions[i].toIExpression(target);
338 public Expression applyType(Type type) {
339 return new EApplyType(location, this, type);
342 public boolean isEffectful() {
346 public boolean isFunctionPattern() {
350 public boolean isConstructorApplication() {
354 public Type getEffect() {
355 CollectEffectsVisitor visitor = new CollectEffectsVisitor();
357 return visitor.getCombinedEffect();
360 public abstract void accept(ExpressionVisitor visitor);
362 public void collectRelationRefs(
363 final TObjectIntHashMap<SCLRelation> allRefs, final TIntHashSet refs) {
364 accept(new StandardExpressionVisitor() {
366 public void visit(QAtom query) {
367 int id = allRefs.get(query.relation);
374 public boolean isFunctionDefinitionLhs() {
378 public Precedence getPrecedence() {
379 return Precedence.DEFAULT;
382 public boolean isPattern(int arity) {
386 public abstract Expression accept(ExpressionTransformer transformer);
388 // TODO implement for all expressions
389 public boolean equalsExpression(Expression expression) {
394 * This method returns a lower bound for the function arity of the value this expression defines.
395 * The lower bound is calculated purely looking the syntax of the expression, not the
396 * types of the constants and variables the expression refers to.
398 public int getSyntacticFunctionArity() {