1 package org.simantics.scl.compiler.elaboration.expressions;
3 import java.util.ArrayList;
4 import java.util.Arrays;
6 import org.simantics.scl.compiler.common.names.Name;
7 import org.simantics.scl.compiler.common.names.Names;
8 import org.simantics.scl.compiler.compilation.CompilationContext;
9 import org.simantics.scl.compiler.constants.NoRepConstant;
10 import org.simantics.scl.compiler.elaboration.contexts.ReplaceContext;
11 import org.simantics.scl.compiler.elaboration.contexts.SimplificationContext;
12 import org.simantics.scl.compiler.elaboration.contexts.TranslationContext;
13 import org.simantics.scl.compiler.elaboration.contexts.TypingContext;
14 import org.simantics.scl.compiler.elaboration.errors.NotPatternException;
15 import org.simantics.scl.compiler.elaboration.expressions.lhstype.LhsType;
16 import org.simantics.scl.compiler.elaboration.expressions.lhstype.PatternMatchingLhs;
17 import org.simantics.scl.compiler.elaboration.java.ListConstructor;
18 import org.simantics.scl.compiler.elaboration.macros.MacroRule;
19 import org.simantics.scl.compiler.elaboration.modules.SCLValue;
20 import org.simantics.scl.compiler.errors.Locations;
21 import org.simantics.scl.compiler.internal.codegen.references.IVal;
22 import org.simantics.scl.compiler.internal.codegen.writer.CodeWriter;
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.kinds.Kinds;
33 import org.simantics.scl.compiler.types.util.MultiFunction;
35 public class EApply extends Expression {
36 public Expression function;
37 public Expression[] parameters;
38 public Type effect = Types.NO_EFFECTS;
40 public EApply(Expression function, Expression ... parameters) {
41 this.function = function;
42 this.parameters = parameters;
45 public EApply(Expression function, Expression parameter) {
46 this(function, new Expression[] {parameter});
49 public EApply(long loc, Expression function, Expression ... parameters) {
51 this.function = function;
52 this.parameters = parameters;
55 public EApply(long loc, Type effect, Expression function, Expression ... parameters) {
58 this.function = function;
59 this.parameters = parameters;
62 public void set(Expression function, Expression[] parameters) {
63 this.function = function;
64 this.parameters = parameters;
67 public Expression getFunction() {
71 public Expression[] getParameters() {
76 protected void updateType() throws MatchException {
77 MultiFunction mfun = Types.matchFunction(function.getType(), parameters.length);
78 /*for(int i=0;i<parameters.length;++i)
79 if(!Types.equals(parameters[i].getType(), mfun.parameterTypes[i]))
80 throw new MatchException();*/
82 setType(mfun.returnType);
86 public IVal toVal(CompilationContext context, CodeWriter w) {
87 IVal functionVal = function.toVal(context, w);
88 IVal[] parameterVals = new IVal[parameters.length];
89 for(int i=0;i<parameters.length;++i)
90 parameterVals[i] = parameters[i].toVal(context, w);
91 Type type = getType();
92 effect = Types.simplifyFinalEffect(effect);
93 return w.applyWithEffect(location, effect, type, functionVal, parameterVals);
96 private void combineApplications() {
97 if(function instanceof EApply) {
98 EApply apply = (EApply)function;
99 if(Types.canonical(apply.effect) == Types.NO_EFFECTS) {
100 function = apply.function;
101 parameters = Expression.concat(apply.parameters, parameters);
107 public Expression simplify(SimplificationContext context) {
108 function = function.simplify(context);
109 for(int i=0;i<parameters.length;++i)
110 parameters[i] = parameters[i].simplify(context);
111 combineApplications();
113 // Try to apply macro rule
114 if(function instanceof EConstant) {
115 EConstant constant = (EConstant)function;
116 MacroRule rule = constant.value.getMacroRule();
118 Expression simplified = rule.apply(context, constant.typeParameters, this);
119 if(simplified != null)
120 // There may be more to simplify after macro application
121 // However this may cause performance problems (O(n^2) algorithm in pathologic cases)
122 return simplified.simplify(context);
130 public EVar getPatternHead() throws NotPatternException {
131 return function.getPatternHead();
135 public LhsType getLhsType() throws NotPatternException {
136 LhsType lhsType = function.getLhsType();
137 if(lhsType instanceof PatternMatchingLhs)
138 for(Expression parameter : parameters)
139 parameter.collectVariableNames((PatternMatchingLhs)lhsType);
144 public Expression resolve(TranslationContext context) {
145 function = function.resolve(context);
146 for(int i=0;i<parameters.length;++i)
147 parameters[i] = parameters[i].resolve(context);
148 //combineApplications();
153 public Expression resolveAsPattern(TranslationContext context) {
154 function = function.resolveAsPattern(context);
155 for(int i=0;i<parameters.length;++i)
156 parameters[i] = parameters[i].resolveAsPattern(context);
157 combineApplications();
158 if(!(function instanceof EConstant || function instanceof EError)) {
159 context.getErrorLog().log(location, "Only constants can be applied in patterns.");
166 public void getParameters(TranslationContext context,
167 ArrayList<Expression> parameters) {
168 function.getParameters(context, parameters);
169 for(Expression parameter : this.parameters)
170 parameters.add(parameter);
174 public Expression replace(ReplaceContext context) {
177 effect.replace(context.tvarMap),
178 function.replace(context),
179 replace(context, parameters));
183 public void setLocationDeep(long loc) {
184 if(location == Locations.NO_LOCATION) {
186 function.setLocationDeep(loc);
187 for(Expression parameter : parameters)
188 parameter.setLocationDeep(loc);
193 public int getFunctionDefinitionPatternArity() throws NotPatternException {
194 return function.getFunctionDefinitionPatternArity() + parameters.length;
198 public IExpression toIExpression(ExpressionInterpretationContext target) {
199 IExpression[] parametersI = toIExpressions(target, parameters);
201 Expression function = this.function;
202 while(function instanceof EApplyType)
203 function = ((EApplyType)function).expression;
206 if(function instanceof EConstant) {
207 SCLValue functionValue = ((EConstant)function).value;
208 Name name = functionValue.getName();
209 if(name.module.equals("Builtin")) {
210 IVal val = functionValue.getValue();
211 if(val instanceof ListConstructor) {
212 if(((ListConstructor)val).arity == parametersI.length)
213 return new IListLiteral(parametersI);
217 //System.out.println("--> " + function + " " + function.getClass().getSimpleName());
220 return new IApply(function.toIExpression(target), parametersI);
223 private Expression inferType(TypingContext context, boolean ignoreResult) {
224 function = function.inferType(context);
225 function = context.instantiate(function);
226 Type functionType = function.getType();
228 int arity = Types.getMaxArity(functionType);
229 if(arity < parameters.length) {
231 context.getErrorLog().log(location, "Application of non-function.");
233 context.getErrorLog().log(location, "Function of arity " + arity +
234 " is applied with " + parameters.length + " parameters.");
235 setType(Types.metaVar(Kinds.STAR));
236 for(int i=0;i<parameters.length;++i)
237 parameters[i] = parameters[i].inferType(context);
241 EApply current = this;
243 MultiFunction mfun = Types.unifyFunction2(functionType, current.parameters.length);
244 int marity = mfun.parameterTypes.length;
245 for(int i=0;i<marity;++i)
246 current.parameters[i] = current.parameters[i].checkType(context, mfun.parameterTypes[i]);
247 current.effect = mfun.effect;
248 context.declareEffect(location, mfun.effect);
249 current.setType(mfun.returnType);
251 if(marity < current.parameters.length) {
252 Expression[] missingParameters = Arrays.copyOfRange(current.parameters, marity, current.parameters.length);
253 functionType = mfun.returnType;
254 current.parameters = Arrays.copyOf(current.parameters, marity);
255 current = new EApply(current, missingParameters);
258 if((ignoreResult && mfun.effect == Types.NO_EFFECTS && Skeletons.canonicalSkeleton(mfun.returnType) instanceof TFun) ||
259 (context.isInPattern() && Skeletons.canonicalSkeleton(mfun.returnType) instanceof TFun)) {
260 context.getErrorLog().log(location, "The function is applied with too few parameters.");
268 public Expression inferType(TypingContext context) {
269 if(parameters.length == 2 && function instanceof EConstant && ((EConstant)function).value.getName() == Names.Prelude_dollar)
270 return new EApply(location, parameters[0], parameters[1]).inferType(context);
271 return inferType(context, false);
275 public Expression checkIgnoredType(TypingContext context) {
276 if(parameters.length == 2 && function instanceof EConstant && ((EConstant)function).value.getName() == Names.Prelude_dollar)
277 return new EApply(location, parameters[0], parameters[1]).checkIgnoredType(context);
278 Expression expression = inferType(context, true);
279 if(Types.canonical(getType()) != Types.UNIT)
280 expression = new ESimpleLet(location, null, expression, new ELiteral(NoRepConstant.PUNIT));
284 public Type getLocalEffect() {
288 public Expression toANormalForm(Expression root) {
289 Expression expression = root;
290 for(int i=parameters.length-1;i>=0;--i) {
291 Expression parameter = parameters[i];
292 if(parameter.isEffectful()) {
293 Variable var = new Variable("aNormalTemp" + i, parameter.getType());
294 expression = new ESimpleLet(var, parameter, expression);
295 parameters[i] = new EVariable(var);
298 if(function.isEffectful()) {
299 Variable var = new Variable("aNormalTempF", function.getType());
300 expression = new ESimpleLet(var, function, expression);
301 function = new EVariable(var);
307 public boolean isEffectful() {
308 if(effect != Types.NO_EFFECTS)
310 for(Expression parameter : parameters)
311 if(parameter.isEffectful())
313 if(function.isEffectful())
319 public boolean isFunctionPattern() {
320 return !isConstructorApplication();
324 public boolean isConstructorApplication() {
325 return function.isConstructorApplication();
329 public void accept(ExpressionVisitor visitor) {
334 public boolean isFunctionDefinitionLhs() {
336 EVar patternHead = function.getPatternHead();
337 return !Character.isUpperCase(patternHead.name.charAt(0));
338 } catch(NotPatternException e) {
344 public boolean isPattern(int arity) {
345 if(!function.isPattern(arity+parameters.length))
347 for(Expression parameter : parameters)
348 if(!parameter.isPattern(0))
354 public Expression accept(ExpressionTransformer transformer) {
355 return transformer.transform(this);
359 public boolean equalsExpression(Expression expression) {
360 if(expression.getClass() != getClass())
362 EApply other = (EApply)expression;
363 if(parameters.length != other.parameters.length)
365 if(!function.equalsExpression(other.function))
367 for(int i=0;i<parameters.length;++i)
368 if(!parameters[i].equalsExpression(other.parameters[i]))