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