]> gerrit.simantics Code Review - simantics/platform.git/blobdiff - bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/expressions/EApply.java
Migrated source code from Simantics SVN
[simantics/platform.git] / bundles / org.simantics.scl.compiler / src / org / simantics / scl / compiler / elaboration / expressions / EApply.java
diff --git a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/expressions/EApply.java b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/expressions/EApply.java
new file mode 100755 (executable)
index 0000000..fb27b91
--- /dev/null
@@ -0,0 +1,381 @@
+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