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