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