]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/expressions/Expression.java
da3afdbfa08ea1df7ccef191f859790b1d34f0d9
[simantics/platform.git] / bundles / org.simantics.scl.compiler / src / org / simantics / scl / compiler / elaboration / expressions / Expression.java
1 package org.simantics.scl.compiler.elaboration.expressions;
2
3 import java.util.ArrayList;
4
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.ForVariablesUsesVisitor;
18 import org.simantics.scl.compiler.elaboration.query.QAtom;
19 import org.simantics.scl.compiler.elaboration.relations.SCLRelation;
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.interpreted.IExpression;
24 import org.simantics.scl.compiler.internal.parsing.Symbol;
25 import org.simantics.scl.compiler.top.ExpressionInterpretationContext;
26 import org.simantics.scl.compiler.types.TForAll;
27 import org.simantics.scl.compiler.types.TFun;
28 import org.simantics.scl.compiler.types.TPred;
29 import org.simantics.scl.compiler.types.TVar;
30 import org.simantics.scl.compiler.types.Type;
31 import org.simantics.scl.compiler.types.Types;
32 import org.simantics.scl.compiler.types.exceptions.MatchException;
33 import org.simantics.scl.compiler.types.kinds.Kinds;
34 import org.simantics.scl.compiler.types.util.Typed;
35
36 import gnu.trove.map.hash.TObjectIntHashMap;
37 import gnu.trove.set.hash.THashSet;
38 import gnu.trove.set.hash.TIntHashSet;
39
40 public abstract class Expression extends Symbol implements Typed {
41     public static final Expression[] EMPTY_ARRAY = new Expression[0];
42     
43     transient
44     private Type type;
45     
46     public Expression() {
47     }
48     
49     public Expression(long loc) {
50         this.location = loc;
51     }
52         
53     @Override
54     public Type getType() {
55         if(type == null) {
56             try {
57                 updateType();
58             } catch (MatchException e) {
59                 throw new InternalCompilerError(e);
60             }
61             if(type == null)
62                 throw new InternalCompilerError(getClass().getSimpleName() + 
63                         ".updateType couldn't compute its type.");
64         }
65         return type;
66     }
67
68     public void setType(Type type) {
69         if(type == null)
70             throw new NullPointerException();
71         this.type = type;
72     }
73         
74         /**
75          * Infers the type of the expression without any context. Adds type
76      * applications and lambdas if needed.       
77          */
78     public Expression inferType(TypingContext context) {
79         return checkBasicType(context, Types.metaVar(Kinds.STAR));
80     }
81
82     public Expression checkBasicType(TypingContext context, Type requiredType) {
83         return context.subsume(inferType(context), requiredType);
84     }
85     
86     protected Expression applyPUnit(TypingContext context) {
87         Type type = Types.canonical(getType());
88         if(type instanceof TFun) {
89             TFun fun = (TFun)type;
90             if(fun.getCanonicalDomain() == Types.PUNIT) {
91                 EApply result = new EApply(location, this, new ELiteral(NoRepConstant.PUNIT));
92                 result.effect = fun.getCanonicalEffect();
93                 context.declareEffect(this.location, result.effect);
94                 return result;
95             }
96         }
97         return this;
98     }
99
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));
104         return expression;
105     }
106         
107         /**
108          * Checks the type of the expression against the given type. Adds type
109          * applications and lambdas if needed.
110          */
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));
121             }
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);
126                     while(true) {
127                         constraints.add(new Variable("constraint", fun.domain));
128                         requiredType = Types.canonical(fun.range);
129                         if(!(requiredType instanceof TFun))
130                             break;
131                         fun = (TFun)requiredType;
132                         if(!(fun.domain instanceof TPred))
133                             break;
134                     }
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);
140                     return expression;
141                 }
142                 else if(fun.domain == Types.PUNIT) {
143                     context.pushEffectUpperBound(location, fun.effect);
144                     Expression expr = checkType(context, fun.range);
145                     context.popEffectUpperBound();       
146                     
147                     // Wrap
148                     Variable var = new Variable("punit", Types.PUNIT);
149                     return new ESimpleLambda(location, var, fun.effect, expr);
150                 }
151                 else
152                     break;
153             }
154             }
155             return checkBasicType(context, requiredType); 
156         }
157
158         public abstract void collectRefs(TObjectIntHashMap<Object> allRefs, TIntHashSet refs);
159         public abstract void collectVars(TObjectIntHashMap<Variable> allVars, TIntHashSet vars);
160
161     public void forVariableUses(VariableProcedure procedure) {
162         accept(new ForVariablesUsesVisitor(procedure));
163     }
164
165     public Expression decomposeMatching() {
166         return this;
167     }
168
169         public String toString() {
170             StringBuilder b = new StringBuilder();
171             ExpressionToStringVisitor visitor = new ExpressionToStringVisitor(b);
172             accept(visitor);
173             return b.toString();
174     }
175
176         protected abstract void updateType() throws MatchException;
177         
178         public static class TypeValidationException extends Exception {
179         private static final long serialVersionUID = 3181298127162041248L;  
180         
181         long loc;
182
183         public TypeValidationException(long loc) {
184             this.loc = loc;
185         }
186         
187         public long getLoc() {
188             return loc;
189         }
190
191         public TypeValidationException(long loc, Throwable cause) {
192             super(cause);
193             this.loc = loc;
194         }
195     }
196     
197     public static void assertEquals(long loc, Type a, Type b) throws TypeValidationException {
198         if(!Types.equals(a, b))
199             throw new TypeValidationException(loc);
200     }
201
202         public abstract IVal toVal(CompilationContext context, CodeWriter w);
203                 
204         public Expression closure(TVar ... vars) {
205             if(vars.length == 0)
206             return this;
207         return new ELambdaType(vars, this);
208         }
209     
210     public abstract void collectFreeVariables(THashSet<Variable> vars);
211     
212     public Expression simplify(SimplificationContext context) {
213         System.out.println("#############################");
214         System.out.println(this);
215         throw new InternalCompilerError(location, getClass().getSimpleName() + " does not support simplify method.");
216     }
217
218     public abstract Expression resolve(TranslationContext context);
219     
220     /**
221      * Returns head of the pattern.
222      */
223     public EVar getPatternHead() throws NotPatternException {
224         throw new NotPatternException(this);
225     }
226     
227     public LhsType getLhsType() throws NotPatternException {
228         throw new NotPatternException(this);
229     }
230
231     protected void collectVariableNames(PatternMatchingLhs lhsType) throws NotPatternException {
232         throw new NotPatternException(this);
233     }
234
235     public void getParameters(TranslationContext translationContext,
236             ArrayList<Expression> parameters) {
237         throw new InternalCompilerError("Class " + getClass().getSimpleName() + " does not support getParameters.");        
238     }
239
240     public Expression resolveAsPattern(TranslationContext context) {
241         context.getErrorLog().log(location, "Pattern was expected here.");
242         return new EError();
243     }
244
245     public void removeFreeVariables(THashSet<Variable> vars) {
246         throw new InternalCompilerError(getClass().getSimpleName() + " is not a pattern.");
247     }
248     
249     public Expression checkTypeAsPattern(TypingContext context, Type requiredType) {
250         if(context.isInPattern())
251             throw new InternalCompilerError("Already in a pattern.");
252         context.setInPattern(true);
253         Expression expression = checkType(context, requiredType);
254         context.setInPattern(false);
255         return expression;
256     }
257
258     /**
259      * Used during simplification and in toIExpression
260      */
261     public THashSet<Variable> getFreeVariables() {
262         THashSet<Variable> result = new THashSet<Variable>();
263         collectFreeVariables(result);
264         return result;
265     }
266
267     public static Expression[] concat(Expression[] a, Expression[] b) {
268         if(a.length == 0)
269             return b;
270         if(b.length == 0)
271             return a;
272         Expression[] result = new Expression[a.length + b.length];
273         for(int i=0;i<a.length;++i)
274             result[i] = a[i];
275         for(int i=0;i<b.length;++i)
276             result[i+a.length] = b[i];
277         return result;
278     }
279
280     public Expression replace(ReplaceContext context) {
281         throw new InternalCompilerError(getClass().getSimpleName() + " does not support replace.");
282     }
283     
284     public static Expression[] replace(ReplaceContext context, Expression[] expressions) {
285         Expression[] result = new Expression[expressions.length];
286         for(int i=0;i<expressions.length;++i)
287             result[i] = expressions[i].replace(context);
288         return result;
289     }
290     
291     public Expression copy() {
292         return replace(new ReplaceContext(null));
293     }
294     
295     public Expression copy(TypingContext typingContext) {
296         return replace(new ReplaceContext(typingContext));
297     }
298
299     public abstract void setLocationDeep(long loc);
300
301     public Expression replaceInPattern(ReplaceContext context) {
302         context.inPattern = true;
303         Expression result = replace(context);
304         context.inPattern = false;
305         return result;
306     }
307
308     public int getFunctionDefinitionPatternArity() throws NotPatternException {
309         throw new NotPatternException(this);
310     }
311     
312     public IVal lambdaToVal(CompilationContext context, CodeWriter w) {
313         DecomposedExpression decomposed = DecomposedExpression.decompose(context.errorLog, this);
314         CodeWriter newW = w.createFunction(decomposed.typeParameters, decomposed.effect, decomposed.returnType, decomposed.parameterTypes);
315         IVal[] parameters = newW.getParameters();
316         IVal functionVal = newW.getFunction().getTarget();
317         for(int i=0;i<parameters.length;++i)
318             decomposed.parameters[i].setVal(parameters[i]);
319         newW.return_(decomposed.body.toVal(context, newW));
320         return functionVal;
321     }
322     
323     public IExpression toIExpression(ExpressionInterpretationContext context) {
324         throw new UnsupportedOperationException();
325     }
326     
327     public static IExpression[] toIExpressions(ExpressionInterpretationContext target, Expression[] expressions) {
328         IExpression[] result = new IExpression[expressions.length];
329         for(int i=0;i<expressions.length;++i)
330             result[i] = expressions[i].toIExpression(target);
331         return result;
332     }
333     
334     public Expression applyType(Type type) {
335         return new EApplyType(location, this, type);
336     }
337
338         public boolean isEffectful() {
339                 return true;
340         }
341
342     public boolean isFunctionPattern() {
343         return false;
344     }
345
346     public boolean isConstructorApplication() {
347         return false;
348     }
349     
350     public abstract void collectEffects(THashSet<Type> effects);
351     
352     public Type getEffect() {
353         THashSet<Type> effects = new THashSet<Type>();
354         collectEffects(effects);
355         return Types.union(effects.toArray(new Type[effects.size()]));
356     }
357     
358     public abstract void accept(ExpressionVisitor visitor);
359     
360     public void collectRelationRefs(
361             final TObjectIntHashMap<SCLRelation> allRefs, final TIntHashSet refs) {
362         accept(new StandardExpressionVisitor() {
363             @Override
364             public void visit(QAtom query) {
365                 int id = allRefs.get(query.relation);
366                 if(id >= 0)
367                     refs.add(id);
368             }
369         });
370     }
371
372     public boolean isFunctionDefinitionLhs() {
373         return false;
374     }
375
376     public Precedence getPrecedence() {
377         return Precedence.DEFAULT;
378     }
379
380     public boolean isPattern(int arity) {
381         return false;
382     }
383     
384     public abstract Expression accept(ExpressionTransformer transformer);
385
386     // TODO implement for all expressions
387     public boolean equalsExpression(Expression expression) {
388         return false;
389     }
390
391     /**
392      * This method returns a lower bound for the function arity of the value this expression defines.
393      * The lower bound is calculated purely looking the syntax of the expression, not the
394      * types of the constants and variables the expression refers to.
395      */
396     public int getSyntacticFunctionArity() {
397         return 0;
398     }
399 }