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.constants.NoRepConstant;
8 import org.simantics.scl.compiler.elaboration.contexts.EnvironmentalContext;
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.query.QAtom;
18 import org.simantics.scl.compiler.elaboration.relations.SCLRelation;
19 import org.simantics.scl.compiler.environment.Environment;
20 import org.simantics.scl.compiler.internal.codegen.references.IVal;
21 import org.simantics.scl.compiler.internal.codegen.writer.CodeWriter;
22 import org.simantics.scl.compiler.internal.elaboration.decomposed.DecomposedExpression;
23 import org.simantics.scl.compiler.internal.elaboration.utils.ExpressionDecorator;
24 import org.simantics.scl.compiler.internal.interpreted.IExpression;
25 import org.simantics.scl.compiler.internal.parsing.Symbol;
26 import org.simantics.scl.compiler.top.ExpressionInterpretationContext;
27 import org.simantics.scl.compiler.types.TForAll;
28 import org.simantics.scl.compiler.types.TFun;
29 import org.simantics.scl.compiler.types.TPred;
30 import org.simantics.scl.compiler.types.TVar;
31 import org.simantics.scl.compiler.types.Type;
32 import org.simantics.scl.compiler.types.Types;
33 import org.simantics.scl.compiler.types.exceptions.MatchException;
34 import org.simantics.scl.compiler.types.kinds.Kinds;
35 import org.simantics.scl.compiler.types.util.Typed;
37 import gnu.trove.map.hash.TObjectIntHashMap;
38 import gnu.trove.set.hash.THashSet;
39 import gnu.trove.set.hash.TIntHashSet;
41 public abstract class Expression extends Symbol implements Typed {
42 public static final Expression[] EMPTY_ARRAY = new Expression[0];
50 public Expression(long loc) {
55 public Type getType() {
59 } catch (MatchException e) {
60 throw new InternalCompilerError(e);
63 throw new InternalCompilerError(getClass().getSimpleName() +
64 ".updateType couldn't compute its type.");
69 public void setType(Type type) {
71 throw new NullPointerException();
76 * Infers the type of the expression without any context. Adds type
77 * applications and lambdas if needed.
79 public Expression inferType(TypingContext context) {
80 return checkBasicType(context, Types.metaVar(Kinds.STAR));
83 public Expression checkBasicType(TypingContext context, Type requiredType) {
84 return context.subsume(inferType(context), requiredType);
87 protected Expression applyPUnit(EnvironmentalContext context) {
88 Type type = Types.canonical(getType());
89 if(type instanceof TFun) {
90 TFun fun = (TFun)type;
91 if(fun.getCanonicalDomain() == Types.PUNIT) {
92 EApply result = new EApply(location, this, new ELiteral(NoRepConstant.PUNIT));
93 result.effect = fun.getCanonicalEffect();
100 public Expression checkIgnoredType(TypingContext context) {
101 Expression expression = inferType(context);
102 if(Types.canonical(expression.getType()) != Types.UNIT)
103 expression = new ESimpleLet(location, null, expression, new ELiteral(NoRepConstant.PUNIT));
108 * Checks the type of the expression against the given type. Adds type
109 * applications and lambdas if needed.
111 public final Expression checkType(TypingContext context, Type requiredType) {
112 //System.out.println("checkType: " + this + " :: " + requiredType);
113 if(!context.isInPattern()) {
114 requiredType = Types.canonical(requiredType);
115 if(requiredType instanceof TForAll) {
116 TForAll forAll = (TForAll)requiredType;
117 TVar var = forAll.var;
118 TVar newVar = Types.var(var.getKind());
119 requiredType = Types.canonical(forAll.type).replace(var, newVar);
120 return new ELambdaType(new TVar[] {newVar}, checkType(context, requiredType));
122 while(requiredType instanceof TFun) {
123 TFun fun = (TFun)requiredType;
124 if(fun.domain instanceof TPred) { // No need to canonicalize
125 ArrayList<Variable> constraints = new ArrayList<Variable>(2);
127 constraints.add(new Variable("constraint", fun.domain));
128 requiredType = Types.canonical(fun.range);
129 if(!(requiredType instanceof TFun))
131 fun = (TFun)requiredType;
132 if(!(fun.domain instanceof TPred))
135 context.pushConstraintFrame(constraints.toArray(new Variable[constraints.size()]));
136 Expression expression = checkType(context, requiredType);
137 context.popConstraintFrame();
138 for(int i=constraints.size()-1;i>=0;--i)
139 expression = new ESimpleLambda(constraints.get(i), expression);
142 else if(fun.domain == Types.PUNIT) {
143 context.pushEffectUpperBound(location, fun.effect);
144 Expression expr = checkType(context, fun.range);
145 context.popEffectUpperBound();
148 Variable var = new Variable("punit", Types.PUNIT);
149 return new ESimpleLambda(location, var, fun.effect, expr);
155 return checkBasicType(context, requiredType);
158 public abstract void collectRefs(TObjectIntHashMap<Object> allRefs, TIntHashSet refs);
159 public abstract void collectVars(TObjectIntHashMap<Variable> allVars, TIntHashSet vars);
160 public abstract void forVariables(VariableProcedure procedure);
162 public Expression decomposeMatching() {
166 public String toString() {
167 StringBuilder b = new StringBuilder();
168 ExpressionToStringVisitor visitor = new ExpressionToStringVisitor(b);
173 protected abstract void updateType() throws MatchException;
175 public static class TypeValidationException extends Exception {
176 private static final long serialVersionUID = 3181298127162041248L;
180 public TypeValidationException(long loc) {
184 public long getLoc() {
188 public TypeValidationException(long loc, Throwable cause) {
194 public static void assertEquals(long loc, Type a, Type b) throws TypeValidationException {
195 if(!Types.equals(a, b))
196 throw new TypeValidationException(loc);
199 public abstract IVal toVal(Environment env, CodeWriter w);
201 public Expression closure(TVar ... vars) {
204 return new ELambdaType(vars, this);
207 public abstract void collectFreeVariables(THashSet<Variable> vars);
209 public Expression simplify(SimplificationContext context) {
210 System.out.println("#############################");
211 System.out.println(this);
212 throw new InternalCompilerError(location, getClass().getSimpleName() + " does not support simplify method.");
215 public abstract Expression resolve(TranslationContext context);
218 * Returns head of the pattern.
220 public EVar getPatternHead() throws NotPatternException {
221 throw new NotPatternException(this);
224 public LhsType getLhsType() throws NotPatternException {
225 throw new NotPatternException(this);
228 protected void collectVariableNames(PatternMatchingLhs lhsType) throws NotPatternException {
229 throw new NotPatternException(this);
232 public void getParameters(TranslationContext translationContext,
233 ArrayList<Expression> parameters) {
234 throw new InternalCompilerError("Class " + getClass().getSimpleName() + " does not support getParameters.");
237 public Expression resolveAsPattern(TranslationContext context) {
238 context.getErrorLog().log(location, "Pattern was expected here.");
242 public void removeFreeVariables(THashSet<Variable> vars) {
243 throw new InternalCompilerError(getClass().getSimpleName() + " is not a pattern.");
246 public Expression checkTypeAsPattern(TypingContext context, Type requiredType) {
247 if(context.isInPattern())
248 throw new InternalCompilerError("Already in a pattern.");
249 context.setInPattern(true);
250 Expression expression = checkType(context, requiredType);
251 context.setInPattern(false);
255 public THashSet<Variable> getFreeVariables() {
256 THashSet<Variable> result = new THashSet<Variable>();
257 collectFreeVariables(result);
261 public static Expression[] concat(Expression[] a, Expression[] b) {
266 Expression[] result = new Expression[a.length + b.length];
267 for(int i=0;i<a.length;++i)
269 for(int i=0;i<b.length;++i)
270 result[i+a.length] = b[i];
274 public Expression replace(ReplaceContext context) {
275 throw new InternalCompilerError(getClass().getSimpleName() + " does not support replace.");
278 public static Expression[] replace(ReplaceContext context, Expression[] expressions) {
279 Expression[] result = new Expression[expressions.length];
280 for(int i=0;i<expressions.length;++i)
281 result[i] = expressions[i].replace(context);
285 public Expression copy() {
286 return replace(new ReplaceContext(null));
289 public Expression copy(TypingContext typingContext) {
290 return replace(new ReplaceContext(typingContext));
293 public abstract void setLocationDeep(long loc);
295 public Expression replaceInPattern(ReplaceContext context) {
296 context.inPattern = true;
297 Expression result = replace(context);
298 context.inPattern = false;
302 public int getFunctionDefinitionPatternArity() throws NotPatternException {
303 throw new NotPatternException(this);
306 public IVal lambdaToVal(Environment env, CodeWriter w) {
307 DecomposedExpression decomposed = DecomposedExpression.decompose(this);
308 CodeWriter newW = w.createFunction(decomposed.typeParameters, decomposed.effect, decomposed.returnType, decomposed.parameterTypes);
309 IVal[] parameters = newW.getParameters();
310 IVal functionVal = newW.getFunction().getTarget();
311 for(int i=0;i<parameters.length;++i)
312 decomposed.parameters[i].setVal(parameters[i]);
313 newW.return_(decomposed.body.toVal(env, newW));
317 public IExpression toIExpression(ExpressionInterpretationContext context) {
318 throw new UnsupportedOperationException();
321 public static IExpression[] toIExpressions(ExpressionInterpretationContext target, Expression[] expressions) {
322 IExpression[] result = new IExpression[expressions.length];
323 for(int i=0;i<expressions.length;++i)
324 result[i] = expressions[i].toIExpression(target);
328 public Expression applyType(Type type) {
329 return new EApplyType(location, this, type);
332 public abstract Expression decorate(ExpressionDecorator decorator);
334 public boolean isEffectful() {
338 public boolean isFunctionPattern() {
342 public boolean isConstructorApplication() {
346 public abstract void collectEffects(THashSet<Type> effects);
348 public Type getEffect() {
349 THashSet<Type> effects = new THashSet<Type>();
350 collectEffects(effects);
351 return Types.union(effects.toArray(new Type[effects.size()]));
354 public abstract void accept(ExpressionVisitor visitor);
356 public void collectRelationRefs(
357 final TObjectIntHashMap<SCLRelation> allRefs, final TIntHashSet refs) {
358 accept(new StandardExpressionVisitor() {
360 public void visit(QAtom query) {
361 int id = allRefs.get(query.relation);
368 public boolean isFunctionDefinitionLhs() {
372 public Precedence getPrecedence() {
373 return Precedence.DEFAULT;
376 public boolean isPattern(int arity) {
380 public abstract Expression accept(ExpressionTransformer transformer);
382 // TODO implement for all expressions
383 public boolean equalsExpression(Expression expression) {
388 * This method returns a lower bound for the function arity of the value this expression defines.
389 * The lower bound is calculated purely looking the syntax of the expression, not the
390 * types of the constants and variables the expression refers to.
392 public int getSyntacticFunctionArity() {