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