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