1 package org.simantics.scl.compiler.elaboration.expressions;
3 import java.util.ArrayList;
5 import org.simantics.scl.compiler.common.names.Name;
6 import org.simantics.scl.compiler.common.names.Names;
7 import org.simantics.scl.compiler.constants.NoRepConstant;
8 import org.simantics.scl.compiler.elaboration.contexts.ReplaceContext;
9 import org.simantics.scl.compiler.elaboration.contexts.SimplificationContext;
10 import org.simantics.scl.compiler.elaboration.contexts.TranslationContext;
11 import org.simantics.scl.compiler.elaboration.contexts.TypingContext;
12 import org.simantics.scl.compiler.elaboration.errors.NotPatternException;
13 import org.simantics.scl.compiler.elaboration.expressions.lhstype.LhsType;
14 import org.simantics.scl.compiler.elaboration.expressions.lhstype.PatternMatchingLhs;
15 import org.simantics.scl.compiler.elaboration.java.ListConstructor;
16 import org.simantics.scl.compiler.elaboration.macros.MacroRule;
17 import org.simantics.scl.compiler.elaboration.modules.SCLValue;
18 import org.simantics.scl.compiler.environment.Environment;
19 import org.simantics.scl.compiler.errors.Locations;
20 import org.simantics.scl.compiler.internal.codegen.references.IVal;
21 import org.simantics.scl.compiler.internal.codegen.writer.CodeWriter;
22 import org.simantics.scl.compiler.internal.elaboration.utils.ExpressionDecorator;
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.exceptions.UnificationException;
33 import org.simantics.scl.compiler.types.kinds.Kinds;
34 import org.simantics.scl.compiler.types.util.MultiFunction;
36 import gnu.trove.map.hash.TObjectIntHashMap;
37 import gnu.trove.set.hash.THashSet;
38 import gnu.trove.set.hash.TIntHashSet;
40 public class EApply extends Expression {
41 public Expression function;
42 public Expression[] parameters;
43 Type effect = Types.NO_EFFECTS;
45 public EApply(Expression function, Expression ... parameters) {
46 this.function = function;
47 this.parameters = parameters;
50 public EApply(Expression function, Expression parameter) {
51 this(function, new Expression[] {parameter});
54 public EApply(long loc, Expression function, Expression ... parameters) {
56 this.function = function;
57 this.parameters = parameters;
60 public EApply(long loc, Type effect, Expression function, Expression ... parameters) {
63 this.function = function;
64 this.parameters = parameters;
67 public void set(Expression function, Expression[] parameters) {
68 this.function = function;
69 this.parameters = parameters;
72 public Expression getFunction() {
76 public Expression[] getParameters() {
81 public void collectRefs(TObjectIntHashMap<Object> allRefs, TIntHashSet refs) {
82 function.collectRefs(allRefs, refs);
83 for(Expression parameter : parameters)
84 parameter.collectRefs(allRefs, refs);
87 public void collectVars(TObjectIntHashMap<Variable> allVars, TIntHashSet vars) {
88 function.collectVars(allVars, vars);
89 for(Expression parameter : parameters)
90 parameter.collectVars(allVars, vars);
94 protected void updateType() throws MatchException {
95 MultiFunction mfun = Types.matchFunction(function.getType(), parameters.length);
96 /*for(int i=0;i<parameters.length;++i)
97 if(!Types.equals(parameters[i].getType(), mfun.parameterTypes[i]))
98 throw new MatchException();*/
100 setType(mfun.returnType);
104 public IVal toVal(Environment env, CodeWriter w) {
105 IVal functionVal = function.toVal(env, w);
106 IVal[] parameterVals = new IVal[parameters.length];
107 for(int i=0;i<parameters.length;++i)
108 parameterVals[i] = parameters[i].toVal(env, w);
109 Type type = getType();
110 effect = Types.simplifyFinalEffect(effect);
111 return w.applyWithEffect(location, effect, type, functionVal, parameterVals);
115 public void collectFreeVariables(THashSet<Variable> vars) {
116 function.collectFreeVariables(vars);
117 for(Expression parameter : parameters)
118 parameter.collectFreeVariables(vars);
121 private void combineApplications() {
122 if(function instanceof EApply) {
123 EApply apply = (EApply)function;
124 if(Types.canonical(apply.effect) == Types.NO_EFFECTS) {
125 function = apply.function;
126 parameters = Expression.concat(apply.parameters, parameters);
132 public Expression simplify(SimplificationContext context) {
133 function = function.simplify(context);
134 for(int i=0;i<parameters.length;++i)
135 parameters[i] = parameters[i].simplify(context);
136 combineApplications();
138 // Try to apply macro rule
139 if(function instanceof EConstant) {
140 EConstant constant = (EConstant)function;
141 MacroRule rule = constant.value.getMacroRule();
143 Expression simplified = rule.apply(context, constant.typeParameters, this);
144 if(simplified != null)
145 // There may be more to simplify after macro application
146 // However this may cause performance problems (O(n^2) algorithm in pathologic cases)
147 return simplified.simplify(context);
155 public EVar getPatternHead() throws NotPatternException {
156 return function.getPatternHead();
160 public LhsType getLhsType() throws NotPatternException {
161 LhsType lhsType = function.getLhsType();
162 if(lhsType instanceof PatternMatchingLhs)
163 for(Expression parameter : parameters)
164 parameter.collectVariableNames((PatternMatchingLhs)lhsType);
169 public Expression resolve(TranslationContext context) {
170 function = function.resolve(context);
171 for(int i=0;i<parameters.length;++i)
172 parameters[i] = parameters[i].resolve(context);
173 //combineApplications();
178 public Expression resolveAsPattern(TranslationContext context) {
179 function = function.resolveAsPattern(context);
180 for(int i=0;i<parameters.length;++i)
181 parameters[i] = parameters[i].resolveAsPattern(context);
182 combineApplications();
183 if(!(function instanceof EConstant || function instanceof EError)) {
184 context.getErrorLog().log(location, "Only constants can be applied in patterns.");
191 public void getParameters(TranslationContext context,
192 ArrayList<Expression> parameters) {
193 function.getParameters(context, parameters);
194 for(Expression parameter : this.parameters)
195 parameters.add(parameter);
199 public void removeFreeVariables(THashSet<Variable> vars) {
200 function.removeFreeVariables(vars);
201 for(Expression parameter : parameters)
202 parameter.removeFreeVariables(vars);
206 public Expression replace(ReplaceContext context) {
209 effect.replace(context.tvarMap),
210 function.replace(context),
211 replace(context, parameters));
215 public void setLocationDeep(long loc) {
216 if(location == Locations.NO_LOCATION) {
218 function.setLocationDeep(loc);
219 for(Expression parameter : parameters)
220 parameter.setLocationDeep(loc);
225 public int getFunctionDefinitionPatternArity() throws NotPatternException {
226 return function.getFunctionDefinitionPatternArity() + parameters.length;
230 public IExpression toIExpression(ExpressionInterpretationContext target) {
231 IExpression[] parametersI = toIExpressions(target, parameters);
233 Expression function = this.function;
234 while(function instanceof EApplyType)
235 function = ((EApplyType)function).expression;
238 if(function instanceof EConstant) {
239 SCLValue functionValue = ((EConstant)function).value;
240 Name name = functionValue.getName();
241 if(name.module.equals("Builtin")) {
242 IVal val = functionValue.getValue();
243 if(val instanceof ListConstructor) {
244 if(((ListConstructor)val).arity == parametersI.length)
245 return new IListLiteral(parametersI);
249 //System.out.println("--> " + function + " " + function.getClass().getSimpleName());
252 return new IApply(function.toIExpression(target), parametersI);
255 private void inferType(TypingContext context, boolean ignoreResult) {
256 function = function.inferType(context);
257 function = context.instantiate(function);
260 mfun = Types.unifyFunction(function.getType(), parameters.length);
261 } catch (UnificationException e) {
262 int arity = Types.getArity(function.getType());
264 context.getErrorLog().log(location, "Application of non-function.");
266 context.getErrorLog().log(location, "Function of arity " + arity +
267 " is applied with " + parameters.length + " parameters.");
268 setType(Types.metaVar(Kinds.STAR));
269 for(int i=0;i<parameters.length;++i)
270 parameters[i] = parameters[i].inferType(context);
273 if((ignoreResult && Skeletons.canonicalSkeleton(mfun.returnType) instanceof TFun &&
274 Types.canonical(mfun.effect) == Types.NO_EFFECTS) ||
275 (context.isInPattern() && Skeletons.canonicalSkeleton(mfun.returnType) instanceof TFun)) {
276 context.getErrorLog().log(location, "The function is applied with too few parameters.");
279 // Check parameter types
280 for(int i=0;i<parameters.length;++i)
281 parameters[i] = parameters[i].checkType(context, mfun.parameterTypes[i]);
283 effect = mfun.effect;
285 context.declareEffect(location, mfun.effect);
286 setType(mfun.returnType);
290 public Expression inferType(TypingContext context) {
291 if(parameters.length == 2 && function instanceof EConstant && ((EConstant)function).value.getName() == Names.Prelude_dollar)
292 return new EApply(location, parameters[0], parameters[1]).inferType(context);
293 inferType(context, false);
298 public Expression checkIgnoredType(TypingContext context) {
299 if(parameters.length == 2 && function instanceof EConstant && ((EConstant)function).value.getName() == Names.Prelude_dollar)
300 return new EApply(location, parameters[0], parameters[1]).inferType(context);
301 inferType(context, true);
302 if(Types.canonical(getType()) != Types.UNIT)
303 return new ESimpleLet(location, null, this, new ELiteral(NoRepConstant.PUNIT));
308 public Expression decorate(ExpressionDecorator decorator) {
309 if(decorator.decorateSubstructure(this)) {
310 function = function.decorate(decorator);
311 for(int i=0;i<parameters.length;++i)
312 parameters[i] = parameters[i].decorate(decorator);
314 return decorator.decorate(this);
317 public Type getLocalEffect() {
321 public Expression toANormalForm(Expression root) {
322 Expression expression = root;
323 for(int i=parameters.length-1;i>=0;--i) {
324 Expression parameter = parameters[i];
325 if(parameter.isEffectful()) {
326 Variable var = new Variable("aNormalTemp" + i, parameter.getType());
327 expression = new ESimpleLet(var, parameter, expression);
328 parameters[i] = new EVariable(var);
331 if(function.isEffectful()) {
332 Variable var = new Variable("aNormalTempF", function.getType());
333 expression = new ESimpleLet(var, function, expression);
334 function = new EVariable(var);
340 public boolean isEffectful() {
341 if(effect != Types.NO_EFFECTS)
343 for(Expression parameter : parameters)
344 if(parameter.isEffectful())
346 if(function.isEffectful())
352 public boolean isFunctionPattern() {
353 return !isConstructorApplication();
357 public boolean isConstructorApplication() {
358 return function.isConstructorApplication();
362 public void collectEffects(THashSet<Type> effects) {
364 function.collectEffects(effects);
365 for(Expression parameter : parameters)
366 parameter.collectEffects(effects);
370 public void accept(ExpressionVisitor visitor) {
375 public boolean isFunctionDefinitionLhs() {
377 EVar patternHead = function.getPatternHead();
378 return !Character.isUpperCase(patternHead.name.charAt(0));
379 } catch(NotPatternException e) {
385 public void forVariables(VariableProcedure procedure) {
386 function.forVariables(procedure);
387 for(Expression parameter : parameters)
388 parameter.forVariables(procedure);
392 public boolean isPattern(int arity) {
393 if(!function.isPattern(arity+parameters.length))
395 for(Expression parameter : parameters)
396 if(!parameter.isPattern(0))
402 public Expression accept(ExpressionTransformer transformer) {
403 return transformer.transform(this);
407 public boolean equalsExpression(Expression expression) {
408 if(expression.getClass() != getClass())
410 EApply other = (EApply)expression;
411 if(parameters.length != other.parameters.length)
413 if(!function.equalsExpression(other.function))
415 for(int i=0;i<parameters.length;++i)
416 if(!parameters[i].equalsExpression(other.parameters[i]))