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.constants.NoRepConstant;
7 import org.simantics.scl.compiler.elaboration.contexts.ReplaceContext;
8 import org.simantics.scl.compiler.elaboration.contexts.SimplificationContext;
9 import org.simantics.scl.compiler.elaboration.contexts.TranslationContext;
10 import org.simantics.scl.compiler.elaboration.contexts.TypingContext;
11 import org.simantics.scl.compiler.elaboration.errors.NotPatternException;
12 import org.simantics.scl.compiler.elaboration.expressions.lhstype.LhsType;
13 import org.simantics.scl.compiler.elaboration.expressions.lhstype.PatternMatchingLhs;
14 import org.simantics.scl.compiler.elaboration.java.ListConstructor;
15 import org.simantics.scl.compiler.elaboration.macros.MacroRule;
16 import org.simantics.scl.compiler.elaboration.modules.SCLValue;
17 import org.simantics.scl.compiler.environment.Environment;
18 import org.simantics.scl.compiler.errors.Locations;
19 import org.simantics.scl.compiler.internal.codegen.references.IVal;
20 import org.simantics.scl.compiler.internal.codegen.writer.CodeWriter;
21 import org.simantics.scl.compiler.internal.elaboration.utils.ExpressionDecorator;
22 import org.simantics.scl.compiler.internal.interpreted.IApply;
23 import org.simantics.scl.compiler.internal.interpreted.IExpression;
24 import org.simantics.scl.compiler.internal.interpreted.IListLiteral;
25 import org.simantics.scl.compiler.top.ExpressionInterpretationContext;
26 import org.simantics.scl.compiler.types.Skeletons;
27 import org.simantics.scl.compiler.types.TFun;
28 import org.simantics.scl.compiler.types.Type;
29 import org.simantics.scl.compiler.types.Types;
30 import org.simantics.scl.compiler.types.exceptions.MatchException;
31 import org.simantics.scl.compiler.types.exceptions.UnificationException;
32 import org.simantics.scl.compiler.types.kinds.Kinds;
33 import org.simantics.scl.compiler.types.util.MultiFunction;
35 import gnu.trove.map.hash.TObjectIntHashMap;
36 import gnu.trove.set.hash.THashSet;
37 import gnu.trove.set.hash.TIntHashSet;
39 public class EApply extends Expression {
40 public Expression function;
41 public Expression[] parameters;
42 Type effect = Types.NO_EFFECTS;
44 public EApply(Expression function, Expression ... parameters) {
45 this.function = function;
46 this.parameters = parameters;
49 public EApply(Expression function, Expression parameter) {
50 this(function, new Expression[] {parameter});
53 public EApply(long loc, Expression function, Expression ... parameters) {
55 this.function = function;
56 this.parameters = parameters;
59 public EApply(long loc, Type effect, Expression function, Expression ... parameters) {
62 this.function = function;
63 this.parameters = parameters;
66 public void set(Expression function, Expression[] parameters) {
67 this.function = function;
68 this.parameters = parameters;
71 public Expression getFunction() {
75 public Expression[] getParameters() {
80 public void collectRefs(TObjectIntHashMap<Object> allRefs, TIntHashSet refs) {
81 function.collectRefs(allRefs, refs);
82 for(Expression parameter : parameters)
83 parameter.collectRefs(allRefs, refs);
86 public void collectVars(TObjectIntHashMap<Variable> allVars, TIntHashSet vars) {
87 function.collectVars(allVars, vars);
88 for(Expression parameter : parameters)
89 parameter.collectVars(allVars, vars);
93 protected void updateType() throws MatchException {
94 MultiFunction mfun = Types.matchFunction(function.getType(), parameters.length);
95 /*for(int i=0;i<parameters.length;++i)
96 if(!Types.equals(parameters[i].getType(), mfun.parameterTypes[i]))
97 throw new MatchException();*/
99 setType(mfun.returnType);
103 public IVal toVal(Environment env, CodeWriter w) {
104 IVal functionVal = function.toVal(env, w);
105 IVal[] parameterVals = new IVal[parameters.length];
106 for(int i=0;i<parameters.length;++i)
107 parameterVals[i] = parameters[i].toVal(env, w);
108 Type type = getType();
109 effect = Types.simplifyFinalEffect(effect);
110 return w.applyWithEffect(location, effect, type, functionVal, parameterVals);
114 public void collectFreeVariables(THashSet<Variable> vars) {
115 function.collectFreeVariables(vars);
116 for(Expression parameter : parameters)
117 parameter.collectFreeVariables(vars);
120 private void combineApplications() {
121 if(function instanceof EApply) {
122 EApply apply = (EApply)function;
123 if(Types.canonical(apply.effect) == Types.NO_EFFECTS) {
124 function = apply.function;
125 parameters = Expression.concat(apply.parameters, parameters);
131 public Expression simplify(SimplificationContext context) {
132 function = function.simplify(context);
133 for(int i=0;i<parameters.length;++i)
134 parameters[i] = parameters[i].simplify(context);
135 combineApplications();
137 // Try to apply macro rule
138 if(function instanceof EConstant) {
139 EConstant constant = (EConstant)function;
140 MacroRule rule = constant.value.getMacroRule();
142 Expression simplified = rule.apply(context, constant.typeParameters, this);
143 if(simplified != null)
144 // There may be more to simplify after macro application
145 // However this may cause performance problems (O(n^2) algorithm in pathologic cases)
146 return simplified.simplify(context);
154 public EVar getPatternHead() throws NotPatternException {
155 return function.getPatternHead();
159 public LhsType getLhsType() throws NotPatternException {
160 LhsType lhsType = function.getLhsType();
161 if(lhsType instanceof PatternMatchingLhs)
162 for(Expression parameter : parameters)
163 parameter.collectVariableNames((PatternMatchingLhs)lhsType);
168 public Expression resolve(TranslationContext context) {
169 function = function.resolve(context);
170 for(int i=0;i<parameters.length;++i)
171 parameters[i] = parameters[i].resolve(context);
172 //combineApplications();
177 public Expression resolveAsPattern(TranslationContext context) {
178 function = function.resolveAsPattern(context);
179 for(int i=0;i<parameters.length;++i)
180 parameters[i] = parameters[i].resolveAsPattern(context);
181 combineApplications();
182 if(!(function instanceof EConstant || function instanceof EError)) {
183 context.getErrorLog().log(location, "Only constants can be applied in patterns.");
190 public void getParameters(TranslationContext context,
191 ArrayList<Expression> parameters) {
192 function.getParameters(context, parameters);
193 for(Expression parameter : this.parameters)
194 parameters.add(parameter);
198 public void removeFreeVariables(THashSet<Variable> vars) {
199 function.removeFreeVariables(vars);
200 for(Expression parameter : parameters)
201 parameter.removeFreeVariables(vars);
205 public Expression replace(ReplaceContext context) {
208 effect.replace(context.tvarMap),
209 function.replace(context),
210 replace(context, parameters));
214 public void setLocationDeep(long loc) {
215 if(location == Locations.NO_LOCATION) {
217 function.setLocationDeep(loc);
218 for(Expression parameter : parameters)
219 parameter.setLocationDeep(loc);
224 public int getFunctionDefinitionPatternArity() throws NotPatternException {
225 return function.getFunctionDefinitionPatternArity() + parameters.length;
229 public IExpression toIExpression(ExpressionInterpretationContext target) {
230 IExpression[] parametersI = toIExpressions(target, parameters);
232 Expression function = this.function;
233 while(function instanceof EApplyType)
234 function = ((EApplyType)function).expression;
237 if(function instanceof EConstant) {
238 SCLValue functionValue = ((EConstant)function).value;
239 Name name = functionValue.getName();
240 if(name.module.equals("Builtin")) {
241 IVal val = functionValue.getValue();
242 if(val instanceof ListConstructor) {
243 if(((ListConstructor)val).arity == parametersI.length)
244 return new IListLiteral(parametersI);
248 //System.out.println("--> " + function + " " + function.getClass().getSimpleName());
251 return new IApply(function.toIExpression(target), parametersI);
254 private void inferType(TypingContext context, boolean ignoreResult) {
255 function = function.inferType(context);
256 function = context.instantiate(function);
259 mfun = Types.unifyFunction(function.getType(), parameters.length);
260 } catch (UnificationException e) {
261 int arity = Types.getArity(function.getType());
263 context.getErrorLog().log(location, "Application of non-function.");
265 context.getErrorLog().log(location, "Function of arity " + arity +
266 " is applied with " + parameters.length + " parameters.");
267 setType(Types.metaVar(Kinds.STAR));
268 for(int i=0;i<parameters.length;++i)
269 parameters[i] = parameters[i].inferType(context);
272 if((ignoreResult && Skeletons.canonicalSkeleton(mfun.returnType) instanceof TFun &&
273 Types.canonical(mfun.effect) == Types.NO_EFFECTS) ||
274 (context.isInPattern() && Skeletons.canonicalSkeleton(mfun.returnType) instanceof TFun)) {
275 context.getErrorLog().log(location, "The function is applied with too few parameters.");
278 // Check parameter types
279 for(int i=0;i<parameters.length;++i)
280 parameters[i] = parameters[i].checkType(context, mfun.parameterTypes[i]);
282 effect = mfun.effect;
284 context.declareEffect(location, mfun.effect);
285 setType(mfun.returnType);
289 public Expression inferType(TypingContext context) {
290 inferType(context, false);
295 public Expression checkIgnoredType(TypingContext context) {
296 inferType(context, true);
297 if(Types.canonical(getType()) != Types.UNIT)
298 return new ESimpleLet(location, null, this, new ELiteral(NoRepConstant.PUNIT));
303 public Expression decorate(ExpressionDecorator decorator) {
304 if(decorator.decorateSubstructure(this)) {
305 function = function.decorate(decorator);
306 for(int i=0;i<parameters.length;++i)
307 parameters[i] = parameters[i].decorate(decorator);
309 return decorator.decorate(this);
312 public Type getLocalEffect() {
316 public Expression toANormalForm(Expression root) {
317 Expression expression = root;
318 for(int i=parameters.length-1;i>=0;--i) {
319 Expression parameter = parameters[i];
320 if(parameter.isEffectful()) {
321 Variable var = new Variable("aNormalTemp" + i, parameter.getType());
322 expression = new ESimpleLet(var, parameter, expression);
323 parameters[i] = new EVariable(var);
326 if(function.isEffectful()) {
327 Variable var = new Variable("aNormalTempF", function.getType());
328 expression = new ESimpleLet(var, function, expression);
329 function = new EVariable(var);
335 public boolean isEffectful() {
336 if(effect != Types.NO_EFFECTS)
338 for(Expression parameter : parameters)
339 if(parameter.isEffectful())
341 if(function.isEffectful())
347 public boolean isFunctionPattern() {
348 return !isConstructorApplication();
352 public boolean isConstructorApplication() {
353 return function.isConstructorApplication();
357 public void collectEffects(THashSet<Type> effects) {
359 function.collectEffects(effects);
360 for(Expression parameter : parameters)
361 parameter.collectEffects(effects);
365 public void accept(ExpressionVisitor visitor) {
370 public boolean isFunctionDefinitionLhs() {
372 EVar patternHead = function.getPatternHead();
373 return !Character.isUpperCase(patternHead.name.charAt(0));
374 } catch(NotPatternException e) {
380 public void forVariables(VariableProcedure procedure) {
381 function.forVariables(procedure);
382 for(Expression parameter : parameters)
383 parameter.forVariables(procedure);
387 public boolean isPattern(int arity) {
388 if(!function.isPattern(arity+parameters.length))
390 for(Expression parameter : parameters)
391 if(!parameter.isPattern(0))
397 public Expression accept(ExpressionTransformer transformer) {
398 return transformer.transform(this);
402 public boolean equalsExpression(Expression expression) {
403 if(expression.getClass() != getClass())
405 EApply other = (EApply)expression;
406 if(parameters.length != other.parameters.length)
408 if(!function.equalsExpression(other.function))
410 for(int i=0;i<parameters.length;++i)
411 if(!parameters[i].equalsExpression(other.parameters[i]))