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