1 package org.simantics.scl.compiler.elaboration.expressions;
\r
3 import java.util.ArrayList;
\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
35 import gnu.trove.map.hash.TObjectIntHashMap;
\r
36 import gnu.trove.set.hash.THashSet;
\r
37 import gnu.trove.set.hash.TIntHashSet;
\r
39 public class EApply extends Expression {
\r
40 public Expression function;
\r
41 public Expression[] parameters;
\r
42 Type effect = Types.NO_EFFECTS;
\r
44 public EApply(Expression function, Expression ... parameters) {
\r
45 this.function = function;
\r
46 this.parameters = parameters;
\r
49 public EApply(Expression function, Expression parameter) {
\r
50 this(function, new Expression[] {parameter});
\r
53 public EApply(long loc, Expression function, Expression ... parameters) {
\r
55 this.function = function;
\r
56 this.parameters = parameters;
\r
59 public EApply(long loc, Type effect, Expression function, Expression ... parameters) {
\r
61 this.effect = effect;
\r
62 this.function = function;
\r
63 this.parameters = parameters;
\r
66 public void set(Expression function, Expression[] parameters) {
\r
67 this.function = function;
\r
68 this.parameters = parameters;
\r
71 public Expression getFunction() {
\r
75 public Expression[] getParameters() {
\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
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
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
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
114 public void collectFreeVariables(THashSet<Variable> vars) {
\r
115 function.collectFreeVariables(vars);
\r
116 for(Expression parameter : parameters)
\r
117 parameter.collectFreeVariables(vars);
\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
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
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
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
154 public EVar getPatternHead() throws NotPatternException {
\r
155 return function.getPatternHead();
\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
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
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
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
198 public void removeFreeVariables(THashSet<Variable> vars) {
\r
199 function.removeFreeVariables(vars);
\r
200 for(Expression parameter : parameters)
\r
201 parameter.removeFreeVariables(vars);
\r
205 public Expression replace(ReplaceContext context) {
\r
208 effect.replace(context.tvarMap),
\r
209 function.replace(context),
\r
210 replace(context, parameters));
\r
214 public void setLocationDeep(long loc) {
\r
215 if(location == Locations.NO_LOCATION) {
\r
217 function.setLocationDeep(loc);
\r
218 for(Expression parameter : parameters)
\r
219 parameter.setLocationDeep(loc);
\r
224 public int getFunctionDefinitionArity() throws NotPatternException {
\r
225 return function.getFunctionDefinitionArity() + parameters.length;
\r
229 public IExpression toIExpression(ExpressionInterpretationContext target) {
\r
230 IExpression[] parametersI = toIExpressions(target, parameters);
\r
232 Expression function = this.function;
\r
233 while(function instanceof EApplyType)
\r
234 function = ((EApplyType)function).expression;
\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
248 //System.out.println("--> " + function + " " + function.getClass().getSimpleName());
\r
251 return new IApply(function.toIExpression(target), parametersI);
\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
259 mfun = Types.unifyFunction(function.getType(), parameters.length);
\r
260 } catch (UnificationException e) {
\r
261 int arity = Types.getArity(function.getType());
\r
263 context.getErrorLog().log(location, "Application of non-function.");
\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
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
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
282 effect = mfun.effect;
\r
284 context.declareEffect(location, mfun.effect);
\r
285 setType(mfun.returnType);
\r
289 public Expression inferType(TypingContext context) {
\r
290 inferType(context, false);
\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
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
309 return decorator.decorate(this);
\r
312 public Type getLocalEffect() {
\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
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
335 public boolean isEffectful() {
\r
336 if(effect != Types.NO_EFFECTS)
\r
338 for(Expression parameter : parameters)
\r
339 if(parameter.isEffectful())
\r
341 if(function.isEffectful())
\r
347 public boolean isFunctionPattern() {
\r
348 return !isConstructorApplication();
\r
352 public boolean isConstructorApplication() {
\r
353 return function.isConstructorApplication();
\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
365 public void accept(ExpressionVisitor visitor) {
\r
366 visitor.visit(this);
\r
370 public boolean isFunctionDefinitionLhs() {
\r
372 EVar patternHead = function.getPatternHead();
\r
373 return !Character.isUpperCase(patternHead.name.charAt(0));
\r
374 } catch(NotPatternException e) {
\r
380 public void forVariables(VariableProcedure procedure) {
\r
381 function.forVariables(procedure);
\r
382 for(Expression parameter : parameters)
\r
383 parameter.forVariables(procedure);
\r
387 public boolean isPattern(int arity) {
\r
388 if(!function.isPattern(arity+parameters.length))
\r
390 for(Expression parameter : parameters)
\r
391 if(!parameter.isPattern(0))
\r
397 public Expression accept(ExpressionTransformer transformer) {
\r
398 return transformer.transform(this);
\r
402 public boolean equalsExpression(Expression expression) {
\r
403 if(expression.getClass() != getClass())
\r
405 EApply other = (EApply)expression;
\r
406 if(parameters.length != other.parameters.length)
\r
408 if(!function.equalsExpression(other.function))
\r
410 for(int i=0;i<parameters.length;++i)
\r
411 if(!parameters[i].equalsExpression(other.parameters[i]))
\r