--- /dev/null
+package org.simantics.scl.compiler.elaboration.expressions;\r
+\r
+import gnu.trove.map.hash.TObjectIntHashMap;\r
+import gnu.trove.set.hash.THashSet;\r
+import gnu.trove.set.hash.TIntHashSet;\r
+\r
+import java.util.ArrayList;\r
+\r
+import org.simantics.scl.compiler.common.names.Name;\r
+import org.simantics.scl.compiler.elaboration.contexts.ReplaceContext;\r
+import org.simantics.scl.compiler.elaboration.contexts.SimplificationContext;\r
+import org.simantics.scl.compiler.elaboration.contexts.TranslationContext;\r
+import org.simantics.scl.compiler.elaboration.contexts.TypingContext;\r
+import org.simantics.scl.compiler.elaboration.errors.NotPatternException;\r
+import org.simantics.scl.compiler.elaboration.expressions.lhstype.LhsType;\r
+import org.simantics.scl.compiler.elaboration.expressions.lhstype.PatternMatchingLhs;\r
+import org.simantics.scl.compiler.elaboration.java.ListConstructor;\r
+import org.simantics.scl.compiler.elaboration.macros.MacroRule;\r
+import org.simantics.scl.compiler.elaboration.modules.SCLValue;\r
+import org.simantics.scl.compiler.environment.Environment;\r
+import org.simantics.scl.compiler.errors.Locations;\r
+import org.simantics.scl.compiler.internal.codegen.references.IVal;\r
+import org.simantics.scl.compiler.internal.codegen.writer.CodeWriter;\r
+import org.simantics.scl.compiler.internal.elaboration.utils.ExpressionDecorator;\r
+import org.simantics.scl.compiler.internal.interpreted.IApply;\r
+import org.simantics.scl.compiler.internal.interpreted.IExpression;\r
+import org.simantics.scl.compiler.internal.interpreted.IListLiteral;\r
+import org.simantics.scl.compiler.top.ExpressionInterpretationContext;\r
+import org.simantics.scl.compiler.types.Type;\r
+import org.simantics.scl.compiler.types.Types;\r
+import org.simantics.scl.compiler.types.exceptions.MatchException;\r
+import org.simantics.scl.compiler.types.exceptions.UnificationException;\r
+import org.simantics.scl.compiler.types.kinds.Kinds;\r
+import org.simantics.scl.compiler.types.util.MultiFunction;\r
+\r
+public class EApply extends Expression {\r
+ Expression function;\r
+ Expression[] parameters;\r
+ Type effect = Types.NO_EFFECTS;\r
+ \r
+ public EApply(Expression function, Expression ... parameters) {\r
+ this.function = function;\r
+ this.parameters = parameters;\r
+ }\r
+ \r
+ public EApply(Expression function, Expression parameter) {\r
+ this(function, new Expression[] {parameter});\r
+ }\r
+\r
+ public EApply(long loc, Expression function, Expression ... parameters) {\r
+ super(loc);\r
+ this.function = function;\r
+ this.parameters = parameters;\r
+ }\r
+ \r
+ public EApply(long loc, Type effect, Expression function, Expression ... parameters) {\r
+ super(loc);\r
+ this.effect = effect;\r
+ this.function = function;\r
+ this.parameters = parameters;\r
+ }\r
+ \r
+ public void set(Expression function, Expression[] parameters) {\r
+ this.function = function;\r
+ this.parameters = parameters;\r
+ }\r
+\r
+ public Expression getFunction() {\r
+ return function;\r
+ }\r
+ \r
+ public Expression[] getParameters() {\r
+ return parameters;\r
+ }\r
+ \r
+\r
+ public void collectRefs(TObjectIntHashMap<Object> allRefs, TIntHashSet refs) {\r
+ function.collectRefs(allRefs, refs);\r
+ for(Expression parameter : parameters)\r
+ parameter.collectRefs(allRefs, refs);\r
+ }\r
+ \r
+ public void collectVars(TObjectIntHashMap<Variable> allVars, TIntHashSet vars) {\r
+ function.collectVars(allVars, vars);\r
+ for(Expression parameter : parameters)\r
+ parameter.collectVars(allVars, vars);\r
+ }\r
+ \r
+ @Override\r
+ protected void updateType() throws MatchException {\r
+ MultiFunction mfun = Types.matchFunction(function.getType(), parameters.length);\r
+ /*for(int i=0;i<parameters.length;++i)\r
+ if(!Types.equals(parameters[i].getType(), mfun.parameterTypes[i]))\r
+ throw new MatchException();*/\r
+ effect = mfun.effect;\r
+ setType(mfun.returnType);\r
+ }\r
+\r
+ @Override\r
+ public IVal toVal(Environment env, CodeWriter w) {\r
+ IVal functionVal = function.toVal(env, w);\r
+ IVal[] parameterVals = new IVal[parameters.length];\r
+ for(int i=0;i<parameters.length;++i)\r
+ parameterVals[i] = parameters[i].toVal(env, w);\r
+ Type type = getType();\r
+ effect = Types.simplifyFinalEffect(effect);\r
+ return w.applyWithEffect(location, effect, type, functionVal, parameterVals);\r
+ }\r
+\r
+ @Override\r
+ public void collectFreeVariables(THashSet<Variable> vars) {\r
+ function.collectFreeVariables(vars);\r
+ for(Expression parameter : parameters)\r
+ parameter.collectFreeVariables(vars);\r
+ }\r
+ \r
+ private void combineApplications() {\r
+ if(function instanceof EApply) {\r
+ EApply apply = (EApply)function;\r
+ if(Types.canonical(apply.effect) == Types.NO_EFFECTS) {\r
+ function = apply.function;\r
+ parameters = Expression.concat(apply.parameters, parameters); \r
+ } \r
+ }\r
+ }\r
+\r
+ @Override\r
+ public Expression simplify(SimplificationContext context) {\r
+ function = function.simplify(context);\r
+ for(int i=0;i<parameters.length;++i)\r
+ parameters[i] = parameters[i].simplify(context);\r
+ combineApplications();\r
+ \r
+ // Try to apply macro rule\r
+ if(function instanceof EConstant) {\r
+ EConstant constant = (EConstant)function;\r
+ MacroRule rule = constant.value.getMacroRule();\r
+ if(rule != null) {\r
+ Expression simplified = rule.apply(context, constant.typeParameters, this);\r
+ if(simplified != null)\r
+ // There may be more to simplify after macro application\r
+ // However this may cause performance problems (O(n^2) algorithm in pathologic cases)\r
+ return simplified.simplify(context);\r
+ }\r
+ }\r
+ \r
+ return this;\r
+ }\r
+ \r
+ @Override\r
+ public EVar getPatternHead() throws NotPatternException {\r
+ return function.getPatternHead();\r
+ }\r
+\r
+ @Override\r
+ public LhsType getLhsType() throws NotPatternException {\r
+ LhsType lhsType = function.getLhsType();\r
+ if(lhsType instanceof PatternMatchingLhs)\r
+ for(Expression parameter : parameters)\r
+ parameter.collectVariableNames((PatternMatchingLhs)lhsType);\r
+ return lhsType;\r
+ }\r
+ \r
+ @Override\r
+ public Expression resolve(TranslationContext context) {\r
+ function = function.resolve(context);\r
+ for(int i=0;i<parameters.length;++i)\r
+ parameters[i] = parameters[i].resolve(context);\r
+ //combineApplications();\r
+ return this;\r
+ }\r
+ \r
+ @Override\r
+ public Expression resolveAsPattern(TranslationContext context) {\r
+ function = function.resolveAsPattern(context);\r
+ for(int i=0;i<parameters.length;++i)\r
+ parameters[i] = parameters[i].resolveAsPattern(context);\r
+ combineApplications();\r
+ if(!(function instanceof EConstant || function instanceof EError)) {\r
+ context.getErrorLog().log(location, "Only constants can be applied in patterns.");\r
+ return new EError();\r
+ }\r
+ return this;\r
+ }\r
+ \r
+ @Override\r
+ public void getParameters(TranslationContext context,\r
+ ArrayList<Expression> parameters) {\r
+ function.getParameters(context, parameters);\r
+ for(Expression parameter : this.parameters)\r
+ parameters.add(parameter);\r
+ }\r
+ \r
+ @Override\r
+ public void removeFreeVariables(THashSet<Variable> vars) {\r
+ function.removeFreeVariables(vars);\r
+ for(Expression parameter : parameters)\r
+ parameter.removeFreeVariables(vars);\r
+ }\r
+\r
+ @Override\r
+ public Expression replace(ReplaceContext context) {\r
+ return new EApply(\r
+ getLocation(), \r
+ effect.replace(context.tvarMap),\r
+ function.replace(context),\r
+ replace(context, parameters));\r
+ }\r
+ \r
+ @Override\r
+ public void setLocationDeep(long loc) {\r
+ if(location == Locations.NO_LOCATION) {\r
+ location = loc;\r
+ function.setLocationDeep(loc);\r
+ for(Expression parameter : parameters)\r
+ parameter.setLocationDeep(loc);\r
+ }\r
+ }\r
+ \r
+ @Override\r
+ public int getFunctionDefinitionArity() throws NotPatternException {\r
+ return function.getFunctionDefinitionArity() + parameters.length;\r
+ }\r
+ \r
+ @Override\r
+ public IExpression toIExpression(ExpressionInterpretationContext target) {\r
+ IExpression[] parametersI = toIExpressions(target, parameters);\r
+ \r
+ Expression function = this.function;\r
+ while(function instanceof EApplyType)\r
+ function = ((EApplyType)function).expression;\r
+ \r
+ // Special cases\r
+ if(function instanceof EConstant) {\r
+ SCLValue functionValue = ((EConstant)function).value;\r
+ Name name = functionValue.getName();\r
+ if(name.module.equals("Builtin")) {\r
+ IVal val = functionValue.getValue();\r
+ if(val instanceof ListConstructor) {\r
+ if(((ListConstructor)val).arity == parametersI.length)\r
+ return new IListLiteral(parametersI);\r
+ }\r
+ }\r
+ }\r
+ //System.out.println("--> " + function + " " + function.getClass().getSimpleName());\r
+ \r
+ // The basic case\r
+ return new IApply(function.toIExpression(target), parametersI);\r
+ }\r
+ \r
+ @Override\r
+ public Expression inferType(TypingContext context) {\r
+ function = function.inferType(context);\r
+ function = context.instantiate(function);\r
+ MultiFunction mfun;\r
+ try {\r
+ mfun = Types.unifyFunction(function.getType(), parameters.length);\r
+ } catch (UnificationException e) {\r
+ int arity = Types.getArity(function.getType());\r
+ if(arity == 0)\r
+ context.getErrorLog().log(location, "Application of non-function.");\r
+ else\r
+ context.getErrorLog().log(location, "Function of arity " + arity + \r
+ " is applied with " + parameters.length + " parameters.");\r
+ setType(Types.metaVar(Kinds.STAR));\r
+ for(int i=0;i<parameters.length;++i)\r
+ parameters[i] = parameters[i].inferType(context);\r
+ return this;\r
+ }\r
+ \r
+ // Check parameter types\r
+ for(int i=0;i<parameters.length;++i)\r
+ parameters[i] = parameters[i].checkType(context, mfun.parameterTypes[i]);\r
+\r
+ effect = mfun.effect;\r
+ \r
+ context.declareEffect(location, mfun.effect);\r
+ setType(mfun.returnType);\r
+\r
+ return this;\r
+ }\r
+\r
+ @Override\r
+ public Expression decorate(ExpressionDecorator decorator) {\r
+ if(decorator.decorateSubstructure(this)) {\r
+ function = function.decorate(decorator);\r
+ for(int i=0;i<parameters.length;++i)\r
+ parameters[i] = parameters[i].decorate(decorator);\r
+ }\r
+ return decorator.decorate(this);\r
+ }\r
+ \r
+ public Type getLocalEffect() {\r
+ return effect;\r
+ }\r
+ \r
+ public Expression toANormalForm(Expression root) {\r
+ Expression expression = root;\r
+ for(int i=parameters.length-1;i>=0;--i) {\r
+ Expression parameter = parameters[i];\r
+ if(parameter.isEffectful()) {\r
+ Variable var = new Variable("aNormalTemp" + i, parameter.getType());\r
+ expression = new ESimpleLet(var, parameter, expression);\r
+ parameters[i] = new EVariable(var);\r
+ }\r
+ }\r
+ if(function.isEffectful()) {\r
+ Variable var = new Variable("aNormalTempF", function.getType());\r
+ expression = new ESimpleLet(var, function, expression);\r
+ function = new EVariable(var);\r
+ }\r
+ return expression;\r
+ }\r
+ \r
+ @Override\r
+ public boolean isEffectful() {\r
+ if(effect != Types.NO_EFFECTS)\r
+ return true; \r
+ for(Expression parameter : parameters)\r
+ if(parameter.isEffectful())\r
+ return true;\r
+ if(function.isEffectful())\r
+ return true;\r
+ return false;\r
+ }\r
+ \r
+ @Override\r
+ public boolean isFunctionPattern() {\r
+ return !isConstructorApplication();\r
+ }\r
+ \r
+ @Override\r
+ public boolean isConstructorApplication() {\r
+ return function.isConstructorApplication();\r
+ }\r
+\r
+ @Override\r
+ public void collectEffects(THashSet<Type> effects) {\r
+ effects.add(effect);\r
+ function.collectEffects(effects);\r
+ for(Expression parameter : parameters)\r
+ parameter.collectEffects(effects);\r
+ }\r
+\r
+ @Override\r
+ public void accept(ExpressionVisitor visitor) {\r
+ visitor.visit(this);\r
+ }\r
+ \r
+ @Override\r
+ public boolean isFunctionDefinitionLhs() {\r
+ try {\r
+ EVar patternHead = function.getPatternHead();\r
+ return !Character.isUpperCase(patternHead.name.charAt(0));\r
+ } catch(NotPatternException e) {\r
+ return false;\r
+ }\r
+ }\r
+\r
+ @Override\r
+ public void forVariables(VariableProcedure procedure) {\r
+ function.forVariables(procedure);\r
+ for(Expression parameter : parameters)\r
+ parameter.forVariables(procedure);\r
+ }\r
+ \r
+ @Override\r
+ public boolean isPattern(int arity) {\r
+ if(!function.isPattern(arity+parameters.length))\r
+ return false;\r
+ for(Expression parameter : parameters)\r
+ if(!parameter.isPattern(0))\r
+ return false;\r
+ return true;\r
+ }\r
+\r
+ @Override\r
+ public Expression accept(ExpressionTransformer transformer) {\r
+ return transformer.transform(this);\r
+ }\r
+}\r