]> gerrit.simantics Code Review - simantics/platform.git/blob
3a2f845fe88191cb594022c5e0c49f60197b1db5
[simantics/platform.git] /
1 package org.simantics.scl.compiler.elaboration.expressions;
2
3 import java.util.ArrayList;
4 import java.util.Set;
5
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;
41
42 import gnu.trove.map.hash.TObjectIntHashMap;
43 import gnu.trove.set.hash.TIntHashSet;
44
45 public abstract class Expression extends Symbol implements Typed {
46     public static final Expression[] EMPTY_ARRAY = new Expression[0];
47     
48     transient
49     private Type type;
50     
51     public Expression() {
52     }
53     
54     public Expression(long loc) {
55         this.location = loc;
56     }
57         
58     @Override
59     public Type getType() {
60         if(type == null) {
61             try {
62                 updateType();
63             } catch (MatchException e) {
64                 throw new InternalCompilerError(location, e);
65             }
66             if(type == null)
67                 throw new InternalCompilerError(location, getClass().getSimpleName() + 
68                         ".updateType couldn't compute its type.");
69         }
70         return type;
71     }
72
73     public void setType(Type type) {
74         if(type == null)
75             throw new NullPointerException();
76         this.type = type;
77     }
78         
79         /**
80          * Infers the type of the expression without any context. Adds type
81      * applications and lambdas if needed.       
82          */
83     public Expression inferType(TypingContext context) {
84         return checkBasicType(context, Types.metaVar(Kinds.STAR));
85     }
86
87     public Expression checkBasicType(TypingContext context, Type requiredType) {
88         return context.subsume(inferType(context), requiredType);
89     }
90     
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);
99                 return result;
100             }
101         }
102         return this;
103     }
104
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));
109         return expression;
110     }
111
112     /**
113      * Checks the type of the expression against the given type. Adds type
114      * applications and lambdas if needed.
115      */
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));
126             }
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);
131                     while(true) {
132                         constraints.add(new Variable("constraint", fun.domain));
133                         requiredType = Types.canonical(fun.range);
134                         if(!(requiredType instanceof TFun))
135                             break;
136                         fun = (TFun)requiredType;
137                         if(!(fun.domain instanceof TPred))
138                             break;
139                     }
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);
145                     return expression;
146                 }
147                 else if(fun.domain == Types.PUNIT) {
148                     context.pushEffectUpperBound(location, fun.effect);
149                     Expression expr = checkType(context, fun.range);
150                     context.popEffectUpperBound();       
151
152                     // Wrap
153                     Variable var = new Variable("punit", Types.PUNIT);
154                     return new ESimpleLambda(location, var, fun.effect, expr);
155                 }
156                 else
157                     break;
158             }
159         }
160         return checkBasicType(context, requiredType); 
161     }
162
163     public final void collectRefs(TObjectIntHashMap<Object> allRefs, TIntHashSet refs) {
164         accept(new CollectRefsVisitor(allRefs, refs));
165     }
166
167     public final void collectVars(TObjectIntHashMap<Variable> allVars, TIntHashSet vars) {
168         accept(new CollectVarsVisitor(allVars, vars));
169     }
170
171     public final void forVariableUses(VariableProcedure procedure) {
172         accept(new ForVariablesUsesVisitor(procedure));
173     }
174
175     public Expression decomposeMatching() {
176         return this;
177     }
178
179         public String toString() {
180             StringBuilder b = new StringBuilder();
181             ExpressionToStringVisitor visitor = new ExpressionToStringVisitor(b);
182             accept(visitor);
183             return b.toString();
184     }
185
186         protected abstract void updateType() throws MatchException;
187         
188         public static class TypeValidationException extends Exception {
189         private static final long serialVersionUID = 3181298127162041248L;  
190         
191         long loc;
192
193         public TypeValidationException(long loc) {
194             this.loc = loc;
195         }
196         
197         public long getLoc() {
198             return loc;
199         }
200
201         public TypeValidationException(long loc, Throwable cause) {
202             super(cause);
203             this.loc = loc;
204         }
205     }
206     
207     public static void assertEquals(long loc, Type a, Type b) throws TypeValidationException {
208         if(!Types.equals(a, b))
209             throw new TypeValidationException(loc);
210     }
211
212         public abstract IVal toVal(CompilationContext context, CodeWriter w);
213                 
214         public Expression closure(TVar ... vars) {
215             if(vars.length == 0)
216             return this;
217         return new ELambdaType(vars, this);
218         }
219     
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.");
224     }
225
226     public abstract Expression resolve(TranslationContext context);
227     
228     /**
229      * Returns head of the pattern.
230      */
231     public EVar getPatternHead() throws NotPatternException {
232         throw new NotPatternException(this);
233     }
234     
235     public LhsType getLhsType() throws NotPatternException {
236         throw new NotPatternException(this);
237     }
238
239     protected void collectVariableNames(PatternMatchingLhs lhsType) throws NotPatternException {
240         throw new NotPatternException(this);
241     }
242
243     public void getParameters(TranslationContext translationContext,
244             ArrayList<Expression> parameters) {
245         throw new InternalCompilerError(location, "Class " + getClass().getSimpleName() + " does not support getParameters.");        
246     }
247
248     public Expression resolveAsPattern(TranslationContext context) {
249         context.getErrorLog().log(location, "Pattern was expected here.");
250         return new EError();
251     }
252     
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);
259         return expression;
260     }
261
262     /**
263      * Used during simplification and in toIExpression
264      */
265     public Set<Variable> getFreeVariables() {
266         CollectFreeVariablesVisitor visitor = new CollectFreeVariablesVisitor(); 
267         accept(visitor);
268         return visitor.getFreeVariables();
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(location, 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 Type getEffect() {
355         CollectEffectsVisitor visitor = new CollectEffectsVisitor();
356         accept(visitor);
357         return visitor.getCombinedEffect();
358     }
359     
360     public abstract void accept(ExpressionVisitor visitor);
361     
362     public void collectRelationRefs(
363             final TObjectIntHashMap<SCLRelation> allRefs, final TIntHashSet refs) {
364         accept(new StandardExpressionVisitor() {
365             @Override
366             public void visit(QAtom query) {
367                 int id = allRefs.get(query.relation);
368                 if(id >= 0)
369                     refs.add(id);
370             }
371         });
372     }
373
374     public boolean isFunctionDefinitionLhs() {
375         return false;
376     }
377
378     public Precedence getPrecedence() {
379         return Precedence.DEFAULT;
380     }
381
382     public boolean isPattern(int arity) {
383         return false;
384     }
385     
386     public abstract Expression accept(ExpressionTransformer transformer);
387
388     // TODO implement for all expressions
389     public boolean equalsExpression(Expression expression) {
390         return false;
391     }
392
393     /**
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.
397      */
398     public int getSyntacticFunctionArity() {
399         return 0;
400     }
401 }