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