--- /dev/null
+package org.simantics.scl.compiler.elaboration.expressions;\r
+\r
+import gnu.trove.map.hash.TObjectIntHashMap;\r
+import gnu.trove.set.hash.THashSet;\r
+import gnu.trove.set.hash.TIntHashSet;\r
+\r
+import java.util.ArrayList;\r
+\r
+import org.simantics.scl.compiler.common.exceptions.InternalCompilerError;\r
+import org.simantics.scl.compiler.common.precedence.Precedence;\r
+import org.simantics.scl.compiler.elaboration.contexts.ReplaceContext;\r
+import org.simantics.scl.compiler.elaboration.contexts.SimplificationContext;\r
+import org.simantics.scl.compiler.elaboration.contexts.TranslationContext;\r
+import org.simantics.scl.compiler.elaboration.contexts.TypingContext;\r
+import org.simantics.scl.compiler.elaboration.errors.NotPatternException;\r
+import org.simantics.scl.compiler.elaboration.expressions.lhstype.LhsType;\r
+import org.simantics.scl.compiler.elaboration.expressions.lhstype.PatternMatchingLhs;\r
+import org.simantics.scl.compiler.elaboration.expressions.printing.ExpressionToStringVisitor;\r
+import org.simantics.scl.compiler.elaboration.query.QAtom;\r
+import org.simantics.scl.compiler.elaboration.relations.SCLRelation;\r
+import org.simantics.scl.compiler.environment.Environment;\r
+import org.simantics.scl.compiler.internal.codegen.references.IVal;\r
+import org.simantics.scl.compiler.internal.codegen.writer.CodeWriter;\r
+import org.simantics.scl.compiler.internal.elaboration.decomposed.DecomposedExpression;\r
+import org.simantics.scl.compiler.internal.elaboration.utils.ExpressionDecorator;\r
+import org.simantics.scl.compiler.internal.interpreted.IExpression;\r
+import org.simantics.scl.compiler.internal.parsing.Symbol;\r
+import org.simantics.scl.compiler.top.ExpressionInterpretationContext;\r
+import org.simantics.scl.compiler.types.TForAll;\r
+import org.simantics.scl.compiler.types.TFun;\r
+import org.simantics.scl.compiler.types.TPred;\r
+import org.simantics.scl.compiler.types.TVar;\r
+import org.simantics.scl.compiler.types.Type;\r
+import org.simantics.scl.compiler.types.Types;\r
+import org.simantics.scl.compiler.types.exceptions.MatchException;\r
+import org.simantics.scl.compiler.types.kinds.Kinds;\r
+import org.simantics.scl.compiler.types.util.Typed;\r
+\r
+public abstract class Expression extends Symbol implements Typed {\r
+ public static final Expression[] EMPTY_ARRAY = new Expression[0];\r
+ \r
+ transient\r
+ private Type type;\r
+ \r
+ public Expression() {\r
+ }\r
+ \r
+ public Expression(long loc) {\r
+ this.location = loc;\r
+ }\r
+ \r
+ @Override\r
+ public Type getType() {\r
+ if(type == null) {\r
+ try {\r
+ updateType();\r
+ } catch (MatchException e) {\r
+ throw new InternalCompilerError(e);\r
+ }\r
+ if(type == null)\r
+ throw new InternalCompilerError(getClass().getSimpleName() + \r
+ ".updateType couldn't compute its type.");\r
+ }\r
+ return type;\r
+ }\r
+\r
+ public void setType(Type type) {\r
+ if(type == null)\r
+ throw new NullPointerException();\r
+ this.type = type;\r
+ }\r
+ \r
+ /**\r
+ * Infers the type of the expression without any context. Adds type\r
+ * applications and lambdas if needed. \r
+ */\r
+ public Expression inferType(TypingContext context) {\r
+ return checkBasicType(context, Types.metaVar(Kinds.STAR));\r
+ }\r
+ \r
+ public Expression checkBasicType(TypingContext context, Type requiredType) {\r
+ return context.subsume(inferType(context), requiredType);\r
+ }\r
+ \r
+ /**\r
+ * Checks the type of the expression against the given type. Adds type\r
+ * applications and lambdas if needed.\r
+ */\r
+ public final Expression checkType(TypingContext context, Type requiredType) {\r
+ //System.out.println("checkType: " + this + " :: " + requiredType);\r
+ if(!context.isInPattern()) {\r
+ requiredType = Types.weakCanonical(requiredType);\r
+ if(requiredType instanceof TForAll) {\r
+ TForAll forAll = (TForAll)requiredType;\r
+ TVar var = forAll.var;\r
+ TVar newVar = Types.var(var.getKind());\r
+ requiredType = Types.canonical(forAll.type).replace(var, newVar);\r
+ return new ELambdaType(new TVar[] {newVar}, checkType(context, requiredType));\r
+ }\r
+ while(requiredType instanceof TFun) {\r
+ TFun fun = (TFun)requiredType;\r
+ if(fun.domain instanceof TPred) { // No need to canonicalize\r
+ ArrayList<Variable> constraints = new ArrayList<Variable>(2);\r
+ while(true) {\r
+ constraints.add(new Variable("constraint", fun.domain));\r
+ requiredType = Types.canonical(fun.range);\r
+ if(!(requiredType instanceof TFun))\r
+ break;\r
+ fun = (TFun)requiredType;\r
+ if(!(fun.domain instanceof TPred))\r
+ break;\r
+ }\r
+ context.pushConstraintFrame(constraints.toArray(new Variable[constraints.size()]));\r
+ Expression expression = checkType(context, requiredType);\r
+ context.popConstraintFrame();\r
+ for(int i=constraints.size()-1;i>=0;--i)\r
+ expression = new ESimpleLambda(constraints.get(i), expression);\r
+ return expression;\r
+ }\r
+ else if(fun.domain == Types.PUNIT) {\r
+ context.pushEffectUpperBound(location, fun.effect);\r
+ Expression expr = checkType(context, fun.range);\r
+ context.popEffectUpperBound(); \r
+ \r
+ // Wrap\r
+ Variable var = new Variable("punit", Types.PUNIT);\r
+ return new ESimpleLambda(location, var, fun.effect, expr);\r
+ }\r
+ else\r
+ break;\r
+ }\r
+ }\r
+ return checkBasicType(context, requiredType); \r
+ }\r
+\r
+ public abstract void collectRefs(TObjectIntHashMap<Object> allRefs, TIntHashSet refs);\r
+ public abstract void collectVars(TObjectIntHashMap<Variable> allVars, TIntHashSet vars);\r
+ public abstract void forVariables(VariableProcedure procedure);\r
+ \r
+ public Expression decomposeMatching() {\r
+ return this;\r
+ }\r
+\r
+ public String toString() {\r
+ StringBuilder b = new StringBuilder();\r
+ ExpressionToStringVisitor visitor = new ExpressionToStringVisitor(b);\r
+ accept(visitor);\r
+ return b.toString();\r
+ }\r
+\r
+ protected abstract void updateType() throws MatchException;\r
+ \r
+ public static class TypeValidationException extends Exception {\r
+ private static final long serialVersionUID = 3181298127162041248L; \r
+ \r
+ long loc;\r
+\r
+ public TypeValidationException(long loc) {\r
+ this.loc = loc;\r
+ }\r
+ \r
+ public long getLoc() {\r
+ return loc;\r
+ }\r
+\r
+ public TypeValidationException(long loc, Throwable cause) {\r
+ super(cause);\r
+ this.loc = loc;\r
+ }\r
+ }\r
+ \r
+ public static void assertEquals(long loc, Type a, Type b) throws TypeValidationException {\r
+ if(!Types.equals(a, b))\r
+ throw new TypeValidationException(loc);\r
+ }\r
+\r
+ public abstract IVal toVal(Environment env, CodeWriter w);\r
+ \r
+ public Expression closure(TVar ... vars) {\r
+ if(vars.length == 0)\r
+ return this;\r
+ return new ELambdaType(vars, this);\r
+ }\r
+ \r
+ public abstract void collectFreeVariables(THashSet<Variable> vars);\r
+ \r
+ public Expression simplify(SimplificationContext context) {\r
+ System.out.println("#############################");\r
+ System.out.println(this);\r
+ throw new InternalCompilerError(location, getClass().getSimpleName() + " does not support simplify method.");\r
+ }\r
+\r
+ public abstract Expression resolve(TranslationContext context);\r
+ \r
+ /**\r
+ * Returns head of the pattern.\r
+ */\r
+ public EVar getPatternHead() throws NotPatternException {\r
+ throw new NotPatternException(this);\r
+ }\r
+ \r
+ public LhsType getLhsType() throws NotPatternException {\r
+ throw new NotPatternException(this);\r
+ }\r
+\r
+ protected void collectVariableNames(PatternMatchingLhs lhsType) throws NotPatternException {\r
+ throw new NotPatternException(this);\r
+ }\r
+\r
+ public void getParameters(TranslationContext translationContext,\r
+ ArrayList<Expression> parameters) {\r
+ throw new InternalCompilerError("Class " + getClass().getSimpleName() + " does not support getParameters."); \r
+ }\r
+\r
+ public Expression resolveAsPattern(TranslationContext context) {\r
+ context.getErrorLog().log(location, "Pattern was expected here.");\r
+ return new EError();\r
+ }\r
+\r
+ public void removeFreeVariables(THashSet<Variable> vars) {\r
+ throw new InternalCompilerError(getClass().getSimpleName() + " is not a pattern.");\r
+ }\r
+ \r
+ public Expression checkTypeAsPattern(TypingContext context, Type requiredType) {\r
+ if(context.isInPattern())\r
+ throw new InternalCompilerError("Already in a pattern.");\r
+ context.setInPattern(true);\r
+ Expression expression = checkType(context, requiredType);\r
+ context.setInPattern(false);\r
+ return expression;\r
+ }\r
+\r
+ public THashSet<Variable> getFreeVariables() {\r
+ THashSet<Variable> result = new THashSet<Variable>();\r
+ collectFreeVariables(result);\r
+ return result;\r
+ } \r
+\r
+ public static Expression[] concat(Expression[] a, Expression[] b) {\r
+ if(a.length == 0)\r
+ return b;\r
+ if(b.length == 0)\r
+ return a;\r
+ Expression[] result = new Expression[a.length + b.length];\r
+ for(int i=0;i<a.length;++i)\r
+ result[i] = a[i];\r
+ for(int i=0;i<b.length;++i)\r
+ result[i+a.length] = b[i];\r
+ return result;\r
+ }\r
+\r
+ public Expression replace(ReplaceContext context) {\r
+ throw new InternalCompilerError(getClass().getSimpleName() + " does not support replace.");\r
+ }\r
+ \r
+ public static Expression[] replace(ReplaceContext context, Expression[] expressions) {\r
+ Expression[] result = new Expression[expressions.length];\r
+ for(int i=0;i<expressions.length;++i)\r
+ result[i] = expressions[i].replace(context);\r
+ return result;\r
+ }\r
+ \r
+ public Expression copy() {\r
+ return replace(new ReplaceContext(null));\r
+ }\r
+ \r
+ public Expression copy(TypingContext typingContext) {\r
+ return replace(new ReplaceContext(typingContext));\r
+ }\r
+\r
+ public abstract void setLocationDeep(long loc);\r
+\r
+ public Expression replaceInPattern(ReplaceContext context) {\r
+ context.inPattern = true;\r
+ Expression result = replace(context);\r
+ context.inPattern = false;\r
+ return result;\r
+ }\r
+\r
+ public int getFunctionDefinitionArity() throws NotPatternException {\r
+ throw new NotPatternException(this);\r
+ }\r
+ \r
+ public IVal lambdaToVal(Environment env, CodeWriter w) {\r
+ DecomposedExpression decomposed = DecomposedExpression.decompose(this);\r
+ CodeWriter newW = w.createFunction(decomposed.typeParameters, decomposed.effect, decomposed.returnType, decomposed.parameterTypes);\r
+ IVal[] parameters = newW.getParameters();\r
+ IVal functionVal = newW.getFunction().getTarget();\r
+ for(int i=0;i<parameters.length;++i)\r
+ decomposed.parameters[i].setVal(parameters[i]);\r
+ newW.return_(decomposed.body.toVal(env, newW));\r
+ return functionVal;\r
+ }\r
+ \r
+ public IExpression toIExpression(ExpressionInterpretationContext context) {\r
+ throw new UnsupportedOperationException();\r
+ }\r
+ \r
+ public static IExpression[] toIExpressions(ExpressionInterpretationContext target, Expression[] expressions) {\r
+ IExpression[] result = new IExpression[expressions.length];\r
+ for(int i=0;i<expressions.length;++i)\r
+ result[i] = expressions[i].toIExpression(target);\r
+ return result;\r
+ }\r
+ \r
+ public Expression applyType(Type type) {\r
+ return new EApplyType(location, this, type);\r
+ }\r
+ \r
+ public abstract Expression decorate(ExpressionDecorator decorator);\r
+\r
+ public boolean isEffectful() {\r
+ return true;\r
+ }\r
+\r
+ public boolean isFunctionPattern() {\r
+ return false;\r
+ }\r
+\r
+ public boolean isConstructorApplication() {\r
+ return false;\r
+ }\r
+ \r
+ public abstract void collectEffects(THashSet<Type> effects);\r
+ \r
+ public Type getEffect() {\r
+ THashSet<Type> effects = new THashSet<Type>();\r
+ collectEffects(effects);\r
+ return Types.union(effects.toArray(new Type[effects.size()]));\r
+ }\r
+ \r
+ public abstract void accept(ExpressionVisitor visitor);\r
+ \r
+ public void collectRelationRefs(\r
+ final TObjectIntHashMap<SCLRelation> allRefs, final TIntHashSet refs) {\r
+ accept(new StandardExpressionVisitor() {\r
+ @Override\r
+ public void visit(QAtom query) {\r
+ int id = allRefs.get(query.relation);\r
+ if(id >= 0)\r
+ refs.add(id);\r
+ }\r
+ });\r
+ }\r
+\r
+ public boolean isFunctionDefinitionLhs() {\r
+ return false;\r
+ }\r
+\r
+ public Precedence getPrecedence() {\r
+ return Precedence.DEFAULT;\r
+ }\r
+\r
+ public boolean isPattern(int arity) {\r
+ return false;\r
+ }\r
+ \r
+ public abstract Expression accept(ExpressionTransformer transformer);\r
+}\r