1 package org.simantics.scl.compiler.elaboration.expressions;
\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
7 import java.util.ArrayList;
\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
36 public class EApply extends Expression {
\r
37 Expression function;
\r
38 Expression[] parameters;
\r
39 Type effect = Types.NO_EFFECTS;
\r
41 public EApply(Expression function, Expression ... parameters) {
\r
42 this.function = function;
\r
43 this.parameters = parameters;
\r
46 public EApply(Expression function, Expression parameter) {
\r
47 this(function, new Expression[] {parameter});
\r
50 public EApply(long loc, Expression function, Expression ... parameters) {
\r
52 this.function = function;
\r
53 this.parameters = parameters;
\r
56 public EApply(long loc, Type effect, Expression function, Expression ... parameters) {
\r
58 this.effect = effect;
\r
59 this.function = function;
\r
60 this.parameters = parameters;
\r
63 public void set(Expression function, Expression[] parameters) {
\r
64 this.function = function;
\r
65 this.parameters = parameters;
\r
68 public Expression getFunction() {
\r
72 public Expression[] getParameters() {
\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
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
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
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
111 public void collectFreeVariables(THashSet<Variable> vars) {
\r
112 function.collectFreeVariables(vars);
\r
113 for(Expression parameter : parameters)
\r
114 parameter.collectFreeVariables(vars);
\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
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
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
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
151 public EVar getPatternHead() throws NotPatternException {
\r
152 return function.getPatternHead();
\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
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
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
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
195 public void removeFreeVariables(THashSet<Variable> vars) {
\r
196 function.removeFreeVariables(vars);
\r
197 for(Expression parameter : parameters)
\r
198 parameter.removeFreeVariables(vars);
\r
202 public Expression replace(ReplaceContext context) {
\r
205 effect.replace(context.tvarMap),
\r
206 function.replace(context),
\r
207 replace(context, parameters));
\r
211 public void setLocationDeep(long loc) {
\r
212 if(location == Locations.NO_LOCATION) {
\r
214 function.setLocationDeep(loc);
\r
215 for(Expression parameter : parameters)
\r
216 parameter.setLocationDeep(loc);
\r
221 public int getFunctionDefinitionArity() throws NotPatternException {
\r
222 return function.getFunctionDefinitionArity() + parameters.length;
\r
226 public IExpression toIExpression(ExpressionInterpretationContext target) {
\r
227 IExpression[] parametersI = toIExpressions(target, parameters);
\r
229 Expression function = this.function;
\r
230 while(function instanceof EApplyType)
\r
231 function = ((EApplyType)function).expression;
\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
245 //System.out.println("--> " + function + " " + function.getClass().getSimpleName());
\r
248 return new IApply(function.toIExpression(target), parametersI);
\r
252 public Expression inferType(TypingContext context) {
\r
253 function = function.inferType(context);
\r
254 function = context.instantiate(function);
\r
255 MultiFunction mfun;
\r
257 mfun = Types.unifyFunction(function.getType(), parameters.length);
\r
258 } catch (UnificationException e) {
\r
259 int arity = Types.getArity(function.getType());
\r
261 context.getErrorLog().log(location, "Application of non-function.");
\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
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
275 effect = mfun.effect;
\r
277 context.declareEffect(location, mfun.effect);
\r
278 setType(mfun.returnType);
\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
290 return decorator.decorate(this);
\r
293 public Type getLocalEffect() {
\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
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
316 public boolean isEffectful() {
\r
317 if(effect != Types.NO_EFFECTS)
\r
319 for(Expression parameter : parameters)
\r
320 if(parameter.isEffectful())
\r
322 if(function.isEffectful())
\r
328 public boolean isFunctionPattern() {
\r
329 return !isConstructorApplication();
\r
333 public boolean isConstructorApplication() {
\r
334 return function.isConstructorApplication();
\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
346 public void accept(ExpressionVisitor visitor) {
\r
347 visitor.visit(this);
\r
351 public boolean isFunctionDefinitionLhs() {
\r
353 EVar patternHead = function.getPatternHead();
\r
354 return !Character.isUpperCase(patternHead.name.charAt(0));
\r
355 } catch(NotPatternException e) {
\r
361 public void forVariables(VariableProcedure procedure) {
\r
362 function.forVariables(procedure);
\r
363 for(Expression parameter : parameters)
\r
364 parameter.forVariables(procedure);
\r
368 public boolean isPattern(int arity) {
\r
369 if(!function.isPattern(arity+parameters.length))
\r
371 for(Expression parameter : parameters)
\r
372 if(!parameter.isPattern(0))
\r
378 public Expression accept(ExpressionTransformer transformer) {
\r
379 return transformer.transform(this);
\r