]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/expressions/EApply.java
Fixed multiple issues causing dangling references to discarded queries
[simantics/platform.git] / bundles / org.simantics.scl.compiler / src / org / simantics / scl / compiler / elaboration / expressions / EApply.java
1 package org.simantics.scl.compiler.elaboration.expressions;
2
3 import java.util.ArrayList;
4 import java.util.Arrays;
5
6 import org.simantics.scl.compiler.common.names.Name;
7 import org.simantics.scl.compiler.common.names.Names;
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.java.ListConstructor;
18 import org.simantics.scl.compiler.elaboration.macros.MacroRule;
19 import org.simantics.scl.compiler.elaboration.modules.SCLValue;
20 import org.simantics.scl.compiler.errors.Locations;
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.interpreted.IApply;
24 import org.simantics.scl.compiler.internal.interpreted.IExpression;
25 import org.simantics.scl.compiler.internal.interpreted.IListLiteral;
26 import org.simantics.scl.compiler.top.ExpressionInterpretationContext;
27 import org.simantics.scl.compiler.types.Skeletons;
28 import org.simantics.scl.compiler.types.TFun;
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.MultiFunction;
34
35 public class EApply extends Expression {
36     public Expression function;
37     public Expression[] parameters;
38     public Type effect = Types.NO_EFFECTS;
39     
40     public EApply(Expression function, Expression ... parameters) {
41         this.function = function;
42         this.parameters = parameters;
43     }
44     
45     public EApply(Expression function, Expression parameter) {
46         this(function, new Expression[] {parameter});
47     }
48
49     public EApply(long loc, Expression function, Expression ... parameters) {
50         super(loc);
51         this.function = function;
52         this.parameters = parameters;
53     }
54     
55     public EApply(long loc, Type effect, Expression function, Expression ... parameters) {
56         super(loc);
57         this.effect = effect;
58         this.function = function;
59         this.parameters = parameters;
60     }
61     
62     public void set(Expression function, Expression[] parameters) {
63         this.function = function;
64         this.parameters = parameters;
65     }
66
67     public Expression getFunction() {
68         return function;
69     }
70     
71     public Expression[] getParameters() {
72         return parameters;
73     }
74
75     @Override
76     protected void updateType() throws MatchException {
77         MultiFunction mfun = Types.matchFunction(function.getType(), parameters.length);
78         /*for(int i=0;i<parameters.length;++i)
79             if(!Types.equals(parameters[i].getType(), mfun.parameterTypes[i]))
80                 throw new MatchException();*/
81         effect = mfun.effect;
82         setType(mfun.returnType);
83         }
84
85         @Override
86         public IVal toVal(CompilationContext context, CodeWriter w) {
87         IVal functionVal = function.toVal(context, w);
88         IVal[] parameterVals = new IVal[parameters.length];
89         for(int i=0;i<parameters.length;++i)
90             parameterVals[i] = parameters[i].toVal(context, w);
91         Type type = getType();
92         effect = Types.simplifyFinalEffect(effect);
93         return w.applyWithEffect(location, effect, type, functionVal, parameterVals);
94     }
95     
96     private void combineApplications() {
97         if(function instanceof EApply) {
98             EApply apply = (EApply)function;
99             if(Types.canonical(apply.effect) == Types.NO_EFFECTS) {
100                 function = apply.function;
101                 parameters = Expression.concat(apply.parameters, parameters); 
102             } 
103         }
104     }
105
106     @Override
107     public Expression simplify(SimplificationContext context) {
108         function = function.simplify(context);
109         for(int i=0;i<parameters.length;++i)
110             parameters[i] = parameters[i].simplify(context);
111         combineApplications();
112         
113         // Try to apply macro rule
114         if(function instanceof EConstant) {
115             EConstant constant = (EConstant)function;
116             MacroRule rule = constant.value.getMacroRule();
117             if(rule != null) {
118                 Expression simplified = rule.apply(context, constant.typeParameters, this);
119                 if(simplified != null)
120                     // There may be more to simplify after macro application
121                     // However this may cause performance problems (O(n^2) algorithm in pathologic cases)
122                     return simplified.simplify(context);
123             }
124         }
125         
126         return this;
127     }
128     
129     @Override
130     public EVar getPatternHead() throws NotPatternException {
131         return function.getPatternHead();
132     }
133
134     @Override
135     public LhsType getLhsType() throws NotPatternException {
136         LhsType lhsType = function.getLhsType();
137         if(lhsType instanceof PatternMatchingLhs)
138             for(Expression parameter : parameters)
139                 parameter.collectVariableNames((PatternMatchingLhs)lhsType);
140         return lhsType;
141     }
142     
143     @Override
144     public Expression resolve(TranslationContext context) {
145         function = function.resolve(context);
146         for(int i=0;i<parameters.length;++i)
147             parameters[i] = parameters[i].resolve(context);
148         //combineApplications();
149         return this;
150     }
151     
152     @Override
153     public Expression resolveAsPattern(TranslationContext context) {
154         function = function.resolveAsPattern(context);
155         for(int i=0;i<parameters.length;++i)
156             parameters[i] = parameters[i].resolveAsPattern(context);
157         combineApplications();
158         if(!(function instanceof EConstant || function instanceof EError)) {
159             context.getErrorLog().log(location, "Only constants can be applied in patterns.");
160             return new EError();
161         }
162         return this;
163     }
164     
165     @Override
166     public void getParameters(TranslationContext context,
167             ArrayList<Expression> parameters) {
168         function.getParameters(context, parameters);
169         for(Expression parameter : this.parameters)
170             parameters.add(parameter);
171     }
172
173     @Override
174     public Expression replace(ReplaceContext context) {
175         return new EApply(
176                 getLocation(),                
177                 effect.replace(context.tvarMap),
178                 function.replace(context),
179                 replace(context, parameters));
180     }
181     
182     @Override
183     public void setLocationDeep(long loc) {
184         if(location == Locations.NO_LOCATION) {
185             location = loc;
186             function.setLocationDeep(loc);
187             for(Expression parameter : parameters)
188                 parameter.setLocationDeep(loc);
189         }
190     }
191     
192     @Override
193     public int getFunctionDefinitionPatternArity() throws NotPatternException {
194         return function.getFunctionDefinitionPatternArity() + parameters.length;
195     }
196     
197     @Override
198     public IExpression toIExpression(ExpressionInterpretationContext target) {
199         IExpression[] parametersI = toIExpressions(target, parameters);
200         
201         Expression function = this.function;
202         while(function instanceof EApplyType)
203             function = ((EApplyType)function).expression;
204         
205         // Special cases
206         if(function instanceof EConstant) {
207             SCLValue functionValue = ((EConstant)function).value;
208             Name name = functionValue.getName();
209             if(name.module.equals("Builtin")) {
210                 IVal val = functionValue.getValue();
211                 if(val instanceof ListConstructor) {
212                     if(((ListConstructor)val).arity == parametersI.length)
213                         return new IListLiteral(parametersI);
214                 }
215             }
216         }
217         //System.out.println("--> " + function + " " + function.getClass().getSimpleName());
218         
219         // The basic case
220         return new IApply(function.toIExpression(target), parametersI);
221     }
222     
223     private Expression inferType(TypingContext context, boolean ignoreResult) {
224         function = function.inferType(context);
225         function = context.instantiate(function);
226         Type functionType = function.getType();
227         
228         int arity = Types.getMaxArity(functionType);
229         if(arity < parameters.length) {
230             if(arity == 0)
231                 context.getErrorLog().log(location, "Application of non-function.");
232             else
233                 context.getErrorLog().log(location, "Function of arity " + arity + 
234                         " is applied with " + parameters.length + " parameters.");
235             setType(Types.metaVar(Kinds.STAR));
236             for(int i=0;i<parameters.length;++i)
237                 parameters[i] = parameters[i].inferType(context);
238             return this;
239         }
240         
241         EApply current = this;
242         while(true) {
243             MultiFunction mfun = Types.unifyFunction2(functionType, current.parameters.length);
244             int marity = mfun.parameterTypes.length;
245             for(int i=0;i<marity;++i)
246                 current.parameters[i] = current.parameters[i].checkType(context, mfun.parameterTypes[i]);
247             current.effect = mfun.effect;
248             context.declareEffect(location, mfun.effect);
249             current.setType(mfun.returnType);
250
251             if(marity < current.parameters.length) {
252                 if (marity == 0) {
253                     // Cannot eat away any more parameters
254                     context.getErrorLog().log(location, "Application of non-function");
255                     return current;
256                 }
257                 
258                 Expression[] missingParameters = Arrays.copyOfRange(current.parameters, marity, current.parameters.length);
259                 functionType = mfun.returnType;
260                 current.parameters = Arrays.copyOf(current.parameters, marity);
261                 current = new EApply(current, missingParameters);
262             }
263             else {
264                 if((ignoreResult && mfun.effect == Types.NO_EFFECTS && Skeletons.canonicalSkeleton(mfun.returnType) instanceof TFun) ||
265                         (context.isInPattern() && Skeletons.canonicalSkeleton(mfun.returnType) instanceof TFun)) {
266                     context.getErrorLog().log(location, "The function is applied with too few parameters.");
267                 }
268                 return current;
269             }
270         }
271     }
272     
273     @Override
274     public Expression inferType(TypingContext context) {
275         if(parameters.length == 2 && function instanceof EConstant && ((EConstant)function).value.getName() == Names.Prelude_dollar)
276             return new EApply(location, parameters[0], parameters[1]).inferType(context);
277         return inferType(context, false);
278     }
279     
280     @Override
281     public Expression checkIgnoredType(TypingContext context) {
282         if(parameters.length == 2 && function instanceof EConstant && ((EConstant)function).value.getName() == Names.Prelude_dollar)
283             return new EApply(location, parameters[0], parameters[1]).checkIgnoredType(context);
284         Expression expression = inferType(context, true);
285         if(Types.canonical(getType()) != Types.UNIT)
286             expression = new ESimpleLet(location, null, expression, new ELiteral(NoRepConstant.PUNIT));
287         return expression;
288     }
289     
290     public Type getLocalEffect() {
291         return effect;
292     }
293     
294     public Expression toANormalForm(Expression root) {
295         Expression expression = root;
296         for(int i=parameters.length-1;i>=0;--i) {
297                 Expression parameter = parameters[i];
298                 if(parameter.isEffectful()) {
299                         Variable var = new Variable("aNormalTemp" + i, parameter.getType());
300                         expression = new ESimpleLet(var, parameter, expression);
301                         parameters[i] = new EVariable(var);
302                 }
303         }
304         if(function.isEffectful()) {
305                 Variable var = new Variable("aNormalTempF", function.getType());
306                 expression = new ESimpleLet(var, function, expression);
307                 function = new EVariable(var);
308         }
309         return expression;
310     }
311     
312     @Override
313     public boolean isEffectful() {
314         if(effect != Types.NO_EFFECTS)
315                 return true;            
316         for(Expression parameter : parameters)
317                 if(parameter.isEffectful())
318                         return true;
319         if(function.isEffectful())
320                 return true;
321         return false;
322     }
323     
324     @Override
325     public boolean isFunctionPattern() {
326         return !isConstructorApplication();
327     }
328     
329     @Override
330     public boolean isConstructorApplication() {
331         return function.isConstructorApplication();
332     }
333
334     @Override
335     public void accept(ExpressionVisitor visitor) {
336         visitor.visit(this);
337     }
338     
339     @Override
340     public boolean isFunctionDefinitionLhs() {
341         try {
342             EVar patternHead = function.getPatternHead();
343             return !Character.isUpperCase(patternHead.name.charAt(0));
344         } catch(NotPatternException e) {
345             return false;
346         }
347     }
348     
349     @Override
350     public boolean isPattern(int arity) {
351         if(!function.isPattern(arity+parameters.length))
352             return false;
353         for(Expression parameter : parameters)
354             if(!parameter.isPattern(0))
355                 return false;
356         return true;
357     }
358
359     @Override
360     public Expression accept(ExpressionTransformer transformer) {
361         return transformer.transform(this);
362     }
363     
364     @Override
365     public boolean equalsExpression(Expression expression) {
366         if(expression.getClass() != getClass())
367             return false;
368         EApply other = (EApply)expression;
369         if(parameters.length != other.parameters.length)
370             return false;
371         if(!function.equalsExpression(other.function))
372             return false;
373         for(int i=0;i<parameters.length;++i)
374             if(!parameters[i].equalsExpression(other.parameters[i]))
375                 return false;
376         return true;
377     }
378 }