From e73c1660b2f4d2a03784451e9e6afe1552b00877 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Hannu=20Niemist=C3=B6?= Date: Wed, 28 Dec 2016 12:46:48 +0200 Subject: [PATCH] Improvements to SCL compiler error messages Better error message if type annotation has different number of parameters than the function definition. Refactored method names, we have now getSyntacticFunctionArity for estimating function arity without type information and getFunctionDefinitionPatternArity for arity calculations of patterns. refs #6897 Change-Id: I032ee0e5da416f232517d1e03c7a7cb0208c4d45 --- .../scl/compiler/compilation/Elaboration.java | 2 +- .../compiler/compilation/TypeChecking.java | 10 + .../elaboration/expressions/Case.java | 246 +++--- .../expressions/DecoratingExpression.java | 9 +- .../elaboration/expressions/EApply.java | 830 +++++++++--------- .../elaboration/expressions/EBinary.java | 476 +++++----- .../elaboration/expressions/EBlock.java | 9 + .../compiler/elaboration/expressions/EIf.java | 394 +++++---- .../elaboration/expressions/ELambda.java | 438 ++++----- .../elaboration/expressions/ELambdaType.java | 263 +++--- .../elaboration/expressions/ELet.java | 519 +++++------ .../elaboration/expressions/EMatch.java | 433 ++++----- .../elaboration/expressions/EPreLet.java | 199 +++-- .../elaboration/expressions/EPreRuleset.java | 171 ++-- .../expressions/ESimpleLambda.java | 503 +++++------ .../elaboration/expressions/ESimpleLet.java | 444 +++++----- .../elaboration/expressions/EVar.java | 164 ++-- .../elaboration/expressions/Expression.java | 781 ++++++++-------- .../expressions/GuardedExpressionGroup.java | 367 ++++---- .../scl/compiler/errors/ErrorLog.java | 4 + .../scl/compiler/tests/scl/Arity1.scl | 31 +- 21 files changed, 3198 insertions(+), 3095 deletions(-) diff --git a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/compilation/Elaboration.java b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/compilation/Elaboration.java index d89c00c82..f5834aef1 100644 --- a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/compilation/Elaboration.java +++ b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/compilation/Elaboration.java @@ -1198,7 +1198,7 @@ public class Elaboration { } else if(annotation.id.text.equals("@inline")) { try { - int arity = defs.get(0).lhs.getFunctionDefinitionArity(); + int arity = defs.get(0).lhs.getFunctionDefinitionPatternArity(); int phaseMask = 0xffffffff; if(annotation.parameters.length > 0) { phaseMask = Integer.parseInt(((EIntegerLiteral)annotation.parameters[0]).getValue()); diff --git a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/compilation/TypeChecking.java b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/compilation/TypeChecking.java index 667c089c3..3118142df 100644 --- a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/compilation/TypeChecking.java +++ b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/compilation/TypeChecking.java @@ -204,6 +204,9 @@ public class TypeChecking { Expression expression = value.getExpression(); + int errorCountBeforeTypeChecking = compilationContext.errorLog.getErrorCount(); + int functionArity = expression.getSyntacticFunctionArity(); + try { ArrayList vars = new ArrayList(); type = Types.removeForAll(type, vars); @@ -218,6 +221,13 @@ public class TypeChecking { overloaded.assertResolved(compilationContext.errorLog); expression.getType().addPolarity(Polarity.POSITIVE); context.solveSubsumptions(expression.getLocation()); + + if(compilationContext.errorLog.getErrorCount() != errorCountBeforeTypeChecking) { + int typeArity = Types.getArity(type); + if(typeArity != functionArity) + compilationContext.errorLog.log(value.definitionLocation, "Possible problem: type declaration has " + typeArity + " parameter types, but function definition has " + functionArity + " parameters."); + } + ArrayList demands = context.getConstraintDemand(); if(!demands.isEmpty() || !givenConstraints.isEmpty()) { ReducedConstraints red = diff --git a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/expressions/Case.java b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/expressions/Case.java index 50eda1c13..4a34cebcf 100755 --- a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/expressions/Case.java +++ b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/expressions/Case.java @@ -1,123 +1,123 @@ -package org.simantics.scl.compiler.elaboration.expressions; - -import org.simantics.scl.compiler.elaboration.contexts.ReplaceContext; -import org.simantics.scl.compiler.elaboration.contexts.SimplificationContext; -import org.simantics.scl.compiler.elaboration.contexts.TranslationContext; -import org.simantics.scl.compiler.elaboration.contexts.TypingContext; -import org.simantics.scl.compiler.errors.Locations; -import org.simantics.scl.compiler.internal.elaboration.utils.ExpressionDecorator; -import org.simantics.scl.compiler.internal.parsing.Symbol; -import org.simantics.scl.compiler.types.Type; - -import gnu.trove.map.hash.TObjectIntHashMap; -import gnu.trove.set.hash.THashSet; -import gnu.trove.set.hash.TIntHashSet; - -public class Case extends Symbol { - public Expression[] patterns; - public Expression value; - - long lhs; - - public Case(Expression[] patterns, Expression value) { - this.patterns = patterns; - this.value = value; - } - - public Case(Expression pattern, Expression value) { - this(new Expression[] {pattern}, value); - } - - public void setLhs(long lhs) { - this.lhs = lhs; - } - - public long getLhs() { - return lhs; - } - - public void collectRefs(TObjectIntHashMap allRefs, TIntHashSet refs) { - value.collectRefs(allRefs, refs); - } - - public void collectVars(TObjectIntHashMap allVars, - TIntHashSet vars) { - value.collectVars(allVars, vars); - } - - public void collectFreeVariables(THashSet vars) { - value.collectFreeVariables(vars); - for(int i=patterns.length-1;i>=0;--i) - patterns[i].removeFreeVariables(vars); - } - - public void resolve(TranslationContext context) { - context.pushFrame(); - for(int i=0;i allRefs, TIntHashSet refs) { + value.collectRefs(allRefs, refs); + } + + public void collectVars(TObjectIntHashMap allVars, + TIntHashSet vars) { + value.collectVars(allVars, vars); + } + + public void collectFreeVariables(THashSet vars) { + value.collectFreeVariables(vars); + for(int i=patterns.length-1;i>=0;--i) + patterns[i].removeFreeVariables(vars); + } + + public void resolve(TranslationContext context) { + context.pushFrame(); + for(int i=0;i allRefs, TIntHashSet refs) { - function.collectRefs(allRefs, refs); - for(Expression parameter : parameters) - parameter.collectRefs(allRefs, refs); - } - - public void collectVars(TObjectIntHashMap allVars, TIntHashSet vars) { - function.collectVars(allVars, vars); - for(Expression parameter : parameters) - parameter.collectVars(allVars, vars); - } - - @Override - protected void updateType() throws MatchException { - MultiFunction mfun = Types.matchFunction(function.getType(), parameters.length); - /*for(int i=0;i vars) { - function.collectFreeVariables(vars); - for(Expression parameter : parameters) - parameter.collectFreeVariables(vars); - } - - private void combineApplications() { - if(function instanceof EApply) { - EApply apply = (EApply)function; - if(Types.canonical(apply.effect) == Types.NO_EFFECTS) { - function = apply.function; - parameters = Expression.concat(apply.parameters, parameters); - } - } - } - - @Override - public Expression simplify(SimplificationContext context) { - function = function.simplify(context); - for(int i=0;i parameters) { - function.getParameters(context, parameters); - for(Expression parameter : this.parameters) - parameters.add(parameter); - } - - @Override - public void removeFreeVariables(THashSet vars) { - function.removeFreeVariables(vars); - for(Expression parameter : parameters) - parameter.removeFreeVariables(vars); - } - - @Override - public Expression replace(ReplaceContext context) { - return new EApply( - getLocation(), - effect.replace(context.tvarMap), - function.replace(context), - replace(context, parameters)); - } - - @Override - public void setLocationDeep(long loc) { - if(location == Locations.NO_LOCATION) { - location = loc; - function.setLocationDeep(loc); - for(Expression parameter : parameters) - parameter.setLocationDeep(loc); - } - } - - @Override - public int getFunctionDefinitionArity() throws NotPatternException { - return function.getFunctionDefinitionArity() + parameters.length; - } - - @Override - public IExpression toIExpression(ExpressionInterpretationContext target) { - IExpression[] parametersI = toIExpressions(target, parameters); - - Expression function = this.function; - while(function instanceof EApplyType) - function = ((EApplyType)function).expression; - - // Special cases - if(function instanceof EConstant) { - SCLValue functionValue = ((EConstant)function).value; - Name name = functionValue.getName(); - if(name.module.equals("Builtin")) { - IVal val = functionValue.getValue(); - if(val instanceof ListConstructor) { - if(((ListConstructor)val).arity == parametersI.length) - return new IListLiteral(parametersI); - } - } - } - //System.out.println("--> " + function + " " + function.getClass().getSimpleName()); - - // The basic case - return new IApply(function.toIExpression(target), parametersI); - } - - private void inferType(TypingContext context, boolean ignoreResult) { - function = function.inferType(context); - function = context.instantiate(function); - MultiFunction mfun; - try { - mfun = Types.unifyFunction(function.getType(), parameters.length); - } catch (UnificationException e) { - int arity = Types.getArity(function.getType()); - if(arity == 0) - context.getErrorLog().log(location, "Application of non-function."); - else - context.getErrorLog().log(location, "Function of arity " + arity + - " is applied with " + parameters.length + " parameters."); - setType(Types.metaVar(Kinds.STAR)); - for(int i=0;i=0;--i) { - Expression parameter = parameters[i]; - if(parameter.isEffectful()) { - Variable var = new Variable("aNormalTemp" + i, parameter.getType()); - expression = new ESimpleLet(var, parameter, expression); - parameters[i] = new EVariable(var); - } - } - if(function.isEffectful()) { - Variable var = new Variable("aNormalTempF", function.getType()); - expression = new ESimpleLet(var, function, expression); - function = new EVariable(var); - } - return expression; - } - - @Override - public boolean isEffectful() { - if(effect != Types.NO_EFFECTS) - return true; - for(Expression parameter : parameters) - if(parameter.isEffectful()) - return true; - if(function.isEffectful()) - return true; - return false; - } - - @Override - public boolean isFunctionPattern() { - return !isConstructorApplication(); - } - - @Override - public boolean isConstructorApplication() { - return function.isConstructorApplication(); - } - - @Override - public void collectEffects(THashSet effects) { - effects.add(effect); - function.collectEffects(effects); - for(Expression parameter : parameters) - parameter.collectEffects(effects); - } - - @Override - public void accept(ExpressionVisitor visitor) { - visitor.visit(this); - } - - @Override - public boolean isFunctionDefinitionLhs() { - try { - EVar patternHead = function.getPatternHead(); - return !Character.isUpperCase(patternHead.name.charAt(0)); - } catch(NotPatternException e) { - return false; - } - } - - @Override - public void forVariables(VariableProcedure procedure) { - function.forVariables(procedure); - for(Expression parameter : parameters) - parameter.forVariables(procedure); - } - - @Override - public boolean isPattern(int arity) { - if(!function.isPattern(arity+parameters.length)) - return false; - for(Expression parameter : parameters) - if(!parameter.isPattern(0)) - return false; - return true; - } - - @Override - public Expression accept(ExpressionTransformer transformer) { - return transformer.transform(this); - } - - @Override - public boolean equalsExpression(Expression expression) { - if(expression.getClass() != getClass()) - return false; - EApply other = (EApply)expression; - if(parameters.length != other.parameters.length) - return false; - if(!function.equalsExpression(other.function)) - return false; - for(int i=0;i allRefs, TIntHashSet refs) { + function.collectRefs(allRefs, refs); + for(Expression parameter : parameters) + parameter.collectRefs(allRefs, refs); + } + + public void collectVars(TObjectIntHashMap allVars, TIntHashSet vars) { + function.collectVars(allVars, vars); + for(Expression parameter : parameters) + parameter.collectVars(allVars, vars); + } + + @Override + protected void updateType() throws MatchException { + MultiFunction mfun = Types.matchFunction(function.getType(), parameters.length); + /*for(int i=0;i vars) { + function.collectFreeVariables(vars); + for(Expression parameter : parameters) + parameter.collectFreeVariables(vars); + } + + private void combineApplications() { + if(function instanceof EApply) { + EApply apply = (EApply)function; + if(Types.canonical(apply.effect) == Types.NO_EFFECTS) { + function = apply.function; + parameters = Expression.concat(apply.parameters, parameters); + } + } + } + + @Override + public Expression simplify(SimplificationContext context) { + function = function.simplify(context); + for(int i=0;i parameters) { + function.getParameters(context, parameters); + for(Expression parameter : this.parameters) + parameters.add(parameter); + } + + @Override + public void removeFreeVariables(THashSet vars) { + function.removeFreeVariables(vars); + for(Expression parameter : parameters) + parameter.removeFreeVariables(vars); + } + + @Override + public Expression replace(ReplaceContext context) { + return new EApply( + getLocation(), + effect.replace(context.tvarMap), + function.replace(context), + replace(context, parameters)); + } + + @Override + public void setLocationDeep(long loc) { + if(location == Locations.NO_LOCATION) { + location = loc; + function.setLocationDeep(loc); + for(Expression parameter : parameters) + parameter.setLocationDeep(loc); + } + } + + @Override + public int getFunctionDefinitionPatternArity() throws NotPatternException { + return function.getFunctionDefinitionPatternArity() + parameters.length; + } + + @Override + public IExpression toIExpression(ExpressionInterpretationContext target) { + IExpression[] parametersI = toIExpressions(target, parameters); + + Expression function = this.function; + while(function instanceof EApplyType) + function = ((EApplyType)function).expression; + + // Special cases + if(function instanceof EConstant) { + SCLValue functionValue = ((EConstant)function).value; + Name name = functionValue.getName(); + if(name.module.equals("Builtin")) { + IVal val = functionValue.getValue(); + if(val instanceof ListConstructor) { + if(((ListConstructor)val).arity == parametersI.length) + return new IListLiteral(parametersI); + } + } + } + //System.out.println("--> " + function + " " + function.getClass().getSimpleName()); + + // The basic case + return new IApply(function.toIExpression(target), parametersI); + } + + private void inferType(TypingContext context, boolean ignoreResult) { + function = function.inferType(context); + function = context.instantiate(function); + MultiFunction mfun; + try { + mfun = Types.unifyFunction(function.getType(), parameters.length); + } catch (UnificationException e) { + int arity = Types.getArity(function.getType()); + if(arity == 0) + context.getErrorLog().log(location, "Application of non-function."); + else + context.getErrorLog().log(location, "Function of arity " + arity + + " is applied with " + parameters.length + " parameters."); + setType(Types.metaVar(Kinds.STAR)); + for(int i=0;i=0;--i) { + Expression parameter = parameters[i]; + if(parameter.isEffectful()) { + Variable var = new Variable("aNormalTemp" + i, parameter.getType()); + expression = new ESimpleLet(var, parameter, expression); + parameters[i] = new EVariable(var); + } + } + if(function.isEffectful()) { + Variable var = new Variable("aNormalTempF", function.getType()); + expression = new ESimpleLet(var, function, expression); + function = new EVariable(var); + } + return expression; + } + + @Override + public boolean isEffectful() { + if(effect != Types.NO_EFFECTS) + return true; + for(Expression parameter : parameters) + if(parameter.isEffectful()) + return true; + if(function.isEffectful()) + return true; + return false; + } + + @Override + public boolean isFunctionPattern() { + return !isConstructorApplication(); + } + + @Override + public boolean isConstructorApplication() { + return function.isConstructorApplication(); + } + + @Override + public void collectEffects(THashSet effects) { + effects.add(effect); + function.collectEffects(effects); + for(Expression parameter : parameters) + parameter.collectEffects(effects); + } + + @Override + public void accept(ExpressionVisitor visitor) { + visitor.visit(this); + } + + @Override + public boolean isFunctionDefinitionLhs() { + try { + EVar patternHead = function.getPatternHead(); + return !Character.isUpperCase(patternHead.name.charAt(0)); + } catch(NotPatternException e) { + return false; + } + } + + @Override + public void forVariables(VariableProcedure procedure) { + function.forVariables(procedure); + for(Expression parameter : parameters) + parameter.forVariables(procedure); + } + + @Override + public boolean isPattern(int arity) { + if(!function.isPattern(arity+parameters.length)) + return false; + for(Expression parameter : parameters) + if(!parameter.isPattern(0)) + return false; + return true; + } + + @Override + public Expression accept(ExpressionTransformer transformer) { + return transformer.transform(this); + } + + @Override + public boolean equalsExpression(Expression expression) { + if(expression.getClass() != getClass()) + return false; + EApply other = (EApply)expression; + if(parameters.length != other.parameters.length) + return false; + if(!function.equalsExpression(other.function)) + return false; + for(int i=0;i rights = new ArrayList(); - public EVar negation; - - public EBinary(Expression left, EVar negation) { - this.left = left; - this.negation = negation; - } - - private EBinary(Expression left, EVar operator, Expression right) { - this.left = left; - rights.add(new EBinaryRightSide(operator, right)); - } - - public static EBinary create(Expression left, EVar operator, Expression right) { - if(left instanceof EBinary) { - EBinary left_ = (EBinary)left; - left_.rights.add(new EBinaryRightSide(operator, right)); - return left_; - } - else - return new EBinary(left, operator, right); - } - - @Override - public Expression resolve(TranslationContext context) { - return parseOperators(context).resolve(context); - } - - public Expression parseOperators(TranslationContext context) { - ArrayList output = new ArrayList(); - ArrayList ops = new ArrayList(); - ArrayList opAsts = new ArrayList(); - - EVar negation = this.negation; - - output.add(left); - for(EBinaryRightSide right : rights) { - // Read op - Expression op = context.resolveExpression(right.operator.location, right.operator.name); - if(op == null) - return new EError(location); - Precedence opPrec = op.getPrecedence(); - while(!ops.isEmpty()) { - Expression oldOp = ops.get(ops.size()-1); - Precedence oldOpPrecedence = oldOp.getPrecedence(); - - if(oldOpPrecedence.level < opPrec.level) - break; - if(oldOpPrecedence.level == opPrec.level) { - if(opPrec.associativity == Associativity.RIGHT) - break; - if(opPrec.associativity == Associativity.NONASSOC) { - context.getErrorLog().log(right.operator.location, - "Operator " + right.operator.name + " is not associative."); - return new EError(location); - } - } - - // Pop op - ops.remove(ops.size()-1); - Expression r = output.remove(output.size()-1); - Expression l = output.remove(output.size()-1); - output.add(binary(l, oldOp, opAsts.remove(opAsts.size()-1), r)); - } - if(negation != null && ops.isEmpty()) { - if(opPrec.level <= NEGATION_LEVEL) { - SCLValue neg = context.getEnvironment().getValue(Names.Prelude_neg); - if(neg == null) { - context.getErrorLog().log(location, - "Couldn't resolve variable neg."); - return new EError(location); - } - output.set(0, unary(neg, negation, output.get(0))); - negation = null; - } - } - ops.add(op); - opAsts.add(right.operator); - - // Read value - output.add(right.right); - } - - // Pop rest - while(!ops.isEmpty()) { - Expression oldOp = ops.remove(ops.size()-1); - Expression r = output.remove(output.size()-1); - Expression l = output.remove(output.size()-1); - output.add(binary(l, oldOp, opAsts.remove(opAsts.size()-1), r)); - } - if(negation != null) { - SCLValue neg = context.getEnvironment().getValue(Names.Prelude_neg); - if(neg == null) { - context.getErrorLog().log(location, - "Couldn't resolve variable neg."); - return new EError(location); - } - output.set(0, unary(neg, negation, output.get(0))); - } - - return output.get(0); - - //System.out.println("parseOperators: " + this); - //return parse(context, left, rights.listIterator(), new Precedence(-1, Associativity.NONASSOC)); - } - - /* - private Expression parse(TranslationContext context, - Expression lhs, ListIterator it, Precedence minPrec) { - while(it.hasNext()) { - EBinaryRightSide right = it.next(); - SCLValue op = context.resolveValue(right.operator.name); - if(op == null) { - context.getErrorLog().log(right.operator, - "Couldn't resolve variable " + right.operator.name + "."); - return lhs; - } - Precedence opPrec = op.getPrecedence(); - if(minPrec.level > opPrec.level) - break; - Expression rhs = right.right; - while(it.hasNext()) { - EVar var = it.next().operator; - SCLValue nextOp = context.resolveValue(var.name); - if(nextOp == null) { - context.getErrorLog().log(var, - "Couldn't resolve variable " + var.name + "."); - return lhs; - } - it.previous(); - Precedence nextPrec = nextOp.getPrecedence(); - int precDiff = opPrec.level - nextPrec.level; - if(precDiff == 0) { - if(opPrec.associativity == Associativity.LEFT) - break; - else if(opPrec.associativity == Associativity.NONASSOC) { - context.getErrorLog().log(it.next().operator, "Nonassociative operator."); - return lhs; - } - } - else if(precDiff > 0) - break; - rhs = parse(context, rhs, it, nextPrec); - } - lhs = binary(lhs, op, right.operator, rhs); - } - return lhs; - } - */ - private Expression binary(Expression lhs, Expression op, EVar opAst, Expression rhs) { - return new EApply(Locations.combine(lhs.location, rhs.location), op, lhs, rhs); - } - - private Expression unary(SCLValue operator, EVar opAst, Expression expression) { - EConstant op = new EConstant(opAst.location, operator); - return new EApply(expression.location /*wrong*/, op, expression); - } - - @Override - public EVar getPatternHead() throws NotPatternException { - if(rights.size() == 1) - return rights.get(0).operator; - else - throw new NotPatternException(this); - } - - @Override - public LhsType getLhsType() throws NotPatternException { - if(rights.size() == 1) - return new FunctionDefinitionLhs(rights.get(0).operator.name); - else - throw new InternalCompilerError(); - } - - @Override - public void getParameters(TranslationContext context, - ArrayList parameters) { - parseOperators(context).getParameters(context, parameters); - } - - public static Expression negate(EVar op, Expression expression) { - if(expression instanceof EBinary) { - ((EBinary)expression).negation = op; - return expression; - } - /*else if(expression instanceof EIntegerLiteral) { - EIntegerLiteral literal = (EIntegerLiteral)expression; - literal.value = -literal.value; - return expression; - }*/ - else - return new EBinary(expression, op); - } - - @Override - public int getFunctionDefinitionArity() throws NotPatternException { - return 2; - } - - @Override - public void setLocationDeep(long loc) { - if(location == Locations.NO_LOCATION) { - location = loc; - left.setLocationDeep(loc); - if(negation != null) - negation.setLocationDeep(loc); - for(EBinaryRightSide right : rights) - right.setLocationDeep(loc); - } - } - - @Override - public Expression accept(ExpressionTransformer transformer) { - return transformer.transform(this); - } - -} +package org.simantics.scl.compiler.elaboration.expressions; + +import java.util.ArrayList; + +import org.simantics.scl.compiler.common.exceptions.InternalCompilerError; +import org.simantics.scl.compiler.common.names.Names; +import org.simantics.scl.compiler.common.precedence.Associativity; +import org.simantics.scl.compiler.common.precedence.Precedence; +import org.simantics.scl.compiler.elaboration.contexts.TranslationContext; +import org.simantics.scl.compiler.elaboration.errors.NotPatternException; +import org.simantics.scl.compiler.elaboration.expressions.lhstype.FunctionDefinitionLhs; +import org.simantics.scl.compiler.elaboration.expressions.lhstype.LhsType; +import org.simantics.scl.compiler.elaboration.modules.SCLValue; +import org.simantics.scl.compiler.errors.Locations; + + + +public class EBinary extends ASTExpression { + public static final int NEGATION_LEVEL = 6; + + public Expression left; + public ArrayList rights = new ArrayList(); + public EVar negation; + + public EBinary(Expression left, EVar negation) { + this.left = left; + this.negation = negation; + } + + private EBinary(Expression left, EVar operator, Expression right) { + this.left = left; + rights.add(new EBinaryRightSide(operator, right)); + } + + public static EBinary create(Expression left, EVar operator, Expression right) { + if(left instanceof EBinary) { + EBinary left_ = (EBinary)left; + left_.rights.add(new EBinaryRightSide(operator, right)); + return left_; + } + else + return new EBinary(left, operator, right); + } + + @Override + public Expression resolve(TranslationContext context) { + return parseOperators(context).resolve(context); + } + + public Expression parseOperators(TranslationContext context) { + ArrayList output = new ArrayList(); + ArrayList ops = new ArrayList(); + ArrayList opAsts = new ArrayList(); + + EVar negation = this.negation; + + output.add(left); + for(EBinaryRightSide right : rights) { + // Read op + Expression op = context.resolveExpression(right.operator.location, right.operator.name); + if(op == null) + return new EError(location); + Precedence opPrec = op.getPrecedence(); + while(!ops.isEmpty()) { + Expression oldOp = ops.get(ops.size()-1); + Precedence oldOpPrecedence = oldOp.getPrecedence(); + + if(oldOpPrecedence.level < opPrec.level) + break; + if(oldOpPrecedence.level == opPrec.level) { + if(opPrec.associativity == Associativity.RIGHT) + break; + if(opPrec.associativity == Associativity.NONASSOC) { + context.getErrorLog().log(right.operator.location, + "Operator " + right.operator.name + " is not associative."); + return new EError(location); + } + } + + // Pop op + ops.remove(ops.size()-1); + Expression r = output.remove(output.size()-1); + Expression l = output.remove(output.size()-1); + output.add(binary(l, oldOp, opAsts.remove(opAsts.size()-1), r)); + } + if(negation != null && ops.isEmpty()) { + if(opPrec.level <= NEGATION_LEVEL) { + SCLValue neg = context.getEnvironment().getValue(Names.Prelude_neg); + if(neg == null) { + context.getErrorLog().log(location, + "Couldn't resolve variable neg."); + return new EError(location); + } + output.set(0, unary(neg, negation, output.get(0))); + negation = null; + } + } + ops.add(op); + opAsts.add(right.operator); + + // Read value + output.add(right.right); + } + + // Pop rest + while(!ops.isEmpty()) { + Expression oldOp = ops.remove(ops.size()-1); + Expression r = output.remove(output.size()-1); + Expression l = output.remove(output.size()-1); + output.add(binary(l, oldOp, opAsts.remove(opAsts.size()-1), r)); + } + if(negation != null) { + SCLValue neg = context.getEnvironment().getValue(Names.Prelude_neg); + if(neg == null) { + context.getErrorLog().log(location, + "Couldn't resolve variable neg."); + return new EError(location); + } + output.set(0, unary(neg, negation, output.get(0))); + } + + return output.get(0); + + //System.out.println("parseOperators: " + this); + //return parse(context, left, rights.listIterator(), new Precedence(-1, Associativity.NONASSOC)); + } + + /* + private Expression parse(TranslationContext context, + Expression lhs, ListIterator it, Precedence minPrec) { + while(it.hasNext()) { + EBinaryRightSide right = it.next(); + SCLValue op = context.resolveValue(right.operator.name); + if(op == null) { + context.getErrorLog().log(right.operator, + "Couldn't resolve variable " + right.operator.name + "."); + return lhs; + } + Precedence opPrec = op.getPrecedence(); + if(minPrec.level > opPrec.level) + break; + Expression rhs = right.right; + while(it.hasNext()) { + EVar var = it.next().operator; + SCLValue nextOp = context.resolveValue(var.name); + if(nextOp == null) { + context.getErrorLog().log(var, + "Couldn't resolve variable " + var.name + "."); + return lhs; + } + it.previous(); + Precedence nextPrec = nextOp.getPrecedence(); + int precDiff = opPrec.level - nextPrec.level; + if(precDiff == 0) { + if(opPrec.associativity == Associativity.LEFT) + break; + else if(opPrec.associativity == Associativity.NONASSOC) { + context.getErrorLog().log(it.next().operator, "Nonassociative operator."); + return lhs; + } + } + else if(precDiff > 0) + break; + rhs = parse(context, rhs, it, nextPrec); + } + lhs = binary(lhs, op, right.operator, rhs); + } + return lhs; + } + */ + private Expression binary(Expression lhs, Expression op, EVar opAst, Expression rhs) { + return new EApply(Locations.combine(lhs.location, rhs.location), op, lhs, rhs); + } + + private Expression unary(SCLValue operator, EVar opAst, Expression expression) { + EConstant op = new EConstant(opAst.location, operator); + return new EApply(expression.location /*wrong*/, op, expression); + } + + @Override + public EVar getPatternHead() throws NotPatternException { + if(rights.size() == 1) + return rights.get(0).operator; + else + throw new NotPatternException(this); + } + + @Override + public LhsType getLhsType() throws NotPatternException { + if(rights.size() == 1) + return new FunctionDefinitionLhs(rights.get(0).operator.name); + else + throw new InternalCompilerError(); + } + + @Override + public void getParameters(TranslationContext context, + ArrayList parameters) { + parseOperators(context).getParameters(context, parameters); + } + + public static Expression negate(EVar op, Expression expression) { + if(expression instanceof EBinary) { + ((EBinary)expression).negation = op; + return expression; + } + /*else if(expression instanceof EIntegerLiteral) { + EIntegerLiteral literal = (EIntegerLiteral)expression; + literal.value = -literal.value; + return expression; + }*/ + else + return new EBinary(expression, op); + } + + @Override + public int getFunctionDefinitionPatternArity() throws NotPatternException { + return 2; + } + + @Override + public void setLocationDeep(long loc) { + if(location == Locations.NO_LOCATION) { + location = loc; + left.setLocationDeep(loc); + if(negation != null) + negation.setLocationDeep(loc); + for(EBinaryRightSide right : rights) + right.setLocationDeep(loc); + } + } + + @Override + public Expression accept(ExpressionTransformer transformer) { + return transformer.transform(this); + } + +} diff --git a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/expressions/EBlock.java b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/expressions/EBlock.java index fb5c2bdfa..ebe88b499 100755 --- a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/expressions/EBlock.java +++ b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/expressions/EBlock.java @@ -119,4 +119,13 @@ public class EBlock extends ASTExpression { return transformer.transform(this); } + @Override + public int getSyntacticFunctionArity() { + if(monadic) + return 0; + Statement lastStatement = statements.getLast(); + if(!(lastStatement instanceof GuardStatement)) + return 0; + return ((GuardStatement)lastStatement).value.getSyntacticFunctionArity(); + } } diff --git a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/expressions/EIf.java b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/expressions/EIf.java index b714d7678..e3bb2fe0a 100755 --- a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/expressions/EIf.java +++ b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/expressions/EIf.java @@ -1,195 +1,199 @@ -package org.simantics.scl.compiler.elaboration.expressions; - -import org.simantics.scl.compiler.elaboration.contexts.ReplaceContext; -import org.simantics.scl.compiler.elaboration.contexts.SimplificationContext; -import org.simantics.scl.compiler.elaboration.contexts.TranslationContext; -import org.simantics.scl.compiler.elaboration.contexts.TypingContext; -import org.simantics.scl.compiler.environment.Environment; -import org.simantics.scl.compiler.errors.Locations; -import org.simantics.scl.compiler.internal.codegen.references.IVal; -import org.simantics.scl.compiler.internal.codegen.writer.CodeWriter; -import org.simantics.scl.compiler.internal.elaboration.utils.ExpressionDecorator; -import org.simantics.scl.compiler.internal.interpreted.IConstant; -import org.simantics.scl.compiler.internal.interpreted.IExpression; -import org.simantics.scl.compiler.internal.interpreted.IIf; -import org.simantics.scl.compiler.top.ExpressionInterpretationContext; -import org.simantics.scl.compiler.types.Type; -import org.simantics.scl.compiler.types.Types; -import org.simantics.scl.compiler.types.exceptions.MatchException; -import org.simantics.scl.runtime.tuple.Tuple0; - -import gnu.trove.map.hash.TObjectIntHashMap; -import gnu.trove.set.hash.THashSet; -import gnu.trove.set.hash.TIntHashSet; - -public class EIf extends Expression { - public Expression condition; - public Expression then_; - public Expression else_; // may be null - - public EIf(Expression condition, Expression then_, Expression else_) { - this.condition = condition; - this.then_ = then_; - this.else_ = else_; - } - - public EIf(long loc, Expression condition, Expression then_, Expression else_) { - super(loc); - this.condition = condition; - this.then_ = then_; - this.else_ = else_; - } - - public void collectRefs(TObjectIntHashMap allRefs, TIntHashSet refs) { - condition.collectRefs(allRefs, refs); - then_.collectRefs(allRefs, refs); - if(else_ != null) - else_.collectRefs(allRefs, refs); - } - - @Override - public void collectVars(TObjectIntHashMap allVars, - TIntHashSet vars) { - condition.collectVars(allVars, vars); - then_.collectVars(allVars, vars); - if(else_ != null) - else_.collectVars(allVars, vars); - } - - @Override - protected void updateType() throws MatchException { - setType(then_.getType()); - } - - @Override - public IVal toVal(Environment env, CodeWriter w) { - IVal conditionVal = condition.toVal(env, w); - CodeWriter joinPoint = w.createBlock(getType()); - CodeWriter thenBlock = w.createBlock(); - if(else_ != null) { - CodeWriter elseBlock = w.createBlock(); - w.if_(conditionVal, thenBlock.getContinuation(), elseBlock.getContinuation()); - - IVal elseVal = else_.toVal(env, elseBlock); - elseBlock.jump(joinPoint.getContinuation(), elseVal); - } - else { - w.if_(conditionVal, thenBlock.getContinuation(), joinPoint.getContinuation()); - } - IVal thenVal = then_.toVal(env, thenBlock); - thenBlock.jump(joinPoint.getContinuation(), thenVal); - w.continueAs(joinPoint); - - return w.getParameters()[0]; - } - - @Override - public void collectFreeVariables(THashSet vars) { - condition.collectFreeVariables(vars); - then_.collectFreeVariables(vars); - if(else_ != null) - else_.collectFreeVariables(vars); - } - - @Override - public Expression simplify(SimplificationContext context) { - condition = condition.simplify(context); - then_ = then_.simplify(context); - if(else_ != null) - else_ = else_.simplify(context); - return this; - } - - @Override - public Expression resolve(TranslationContext context) { - condition = condition.resolve(context); - then_ = then_.resolve(context); - if(else_ != null) - else_ = else_.resolve(context); - return this; - } - - @Override - public Expression replace(ReplaceContext context) { - return new EIf(condition.replace(context), - then_.replace(context), - else_ == null ? null : else_.replace(context)); - } - - @Override - public Expression checkBasicType(TypingContext context, Type requiredType) { - condition = condition.checkType(context, Types.BOOLEAN); - then_ = then_.checkType(context, requiredType); - if(else_ != null) - else_ = else_.checkType(context, requiredType); - else - context.getErrorLog().log(location, "Else branch is required because the return value of the if expression is used."); - return this; - } - - @Override - public Expression checkIgnoredType(TypingContext context) { - condition = condition.checkType(context, Types.BOOLEAN); - then_ = then_.checkIgnoredType(context); - if(else_ != null) - else_ = else_.checkIgnoredType(context); - return this; - } - - @Override - public Expression decorate(ExpressionDecorator decorator) { - condition = condition.decorate(decorator); - then_ = then_.decorate(decorator); - if(else_ != null) - else_ = else_.decorate(decorator); - return decorator.decorate(this); - } - - @Override - public boolean isEffectful() { - return condition.isEffectful() || then_.isEffectful() || (else_ != null && else_.isEffectful()); - } - - @Override - public void collectEffects(THashSet effects) { - condition.collectEffects(effects); - then_.collectEffects(effects); - if(else_ != null) - else_.collectEffects(effects); - } - - @Override - public void setLocationDeep(long loc) { - if(location == Locations.NO_LOCATION) { - location = loc; - condition.setLocationDeep(loc); - then_.setLocationDeep(loc); - if(else_ != null) - else_.setLocationDeep(loc); - } - } - - @Override - public void accept(ExpressionVisitor visitor) { - visitor.visit(this); - } - - @Override - public IExpression toIExpression(ExpressionInterpretationContext target) { - return new IIf(condition.toIExpression(target), then_.toIExpression(target), - else_ != null ? else_.toIExpression(target) : new IConstant(Tuple0.INSTANCE)); - } - - @Override - public void forVariables(VariableProcedure procedure) { - condition.forVariables(procedure); - then_.forVariables(procedure); - if(else_ != null) - else_.forVariables(procedure); - } - @Override - public Expression accept(ExpressionTransformer transformer) { - return transformer.transform(this); - } - -} +package org.simantics.scl.compiler.elaboration.expressions; + +import org.simantics.scl.compiler.elaboration.contexts.ReplaceContext; +import org.simantics.scl.compiler.elaboration.contexts.SimplificationContext; +import org.simantics.scl.compiler.elaboration.contexts.TranslationContext; +import org.simantics.scl.compiler.elaboration.contexts.TypingContext; +import org.simantics.scl.compiler.environment.Environment; +import org.simantics.scl.compiler.errors.Locations; +import org.simantics.scl.compiler.internal.codegen.references.IVal; +import org.simantics.scl.compiler.internal.codegen.writer.CodeWriter; +import org.simantics.scl.compiler.internal.elaboration.utils.ExpressionDecorator; +import org.simantics.scl.compiler.internal.interpreted.IConstant; +import org.simantics.scl.compiler.internal.interpreted.IExpression; +import org.simantics.scl.compiler.internal.interpreted.IIf; +import org.simantics.scl.compiler.top.ExpressionInterpretationContext; +import org.simantics.scl.compiler.types.Type; +import org.simantics.scl.compiler.types.Types; +import org.simantics.scl.compiler.types.exceptions.MatchException; +import org.simantics.scl.runtime.tuple.Tuple0; + +import gnu.trove.map.hash.TObjectIntHashMap; +import gnu.trove.set.hash.THashSet; +import gnu.trove.set.hash.TIntHashSet; + +public class EIf extends Expression { + public Expression condition; + public Expression then_; + public Expression else_; // may be null + + public EIf(Expression condition, Expression then_, Expression else_) { + this.condition = condition; + this.then_ = then_; + this.else_ = else_; + } + + public EIf(long loc, Expression condition, Expression then_, Expression else_) { + super(loc); + this.condition = condition; + this.then_ = then_; + this.else_ = else_; + } + + public void collectRefs(TObjectIntHashMap allRefs, TIntHashSet refs) { + condition.collectRefs(allRefs, refs); + then_.collectRefs(allRefs, refs); + if(else_ != null) + else_.collectRefs(allRefs, refs); + } + + @Override + public void collectVars(TObjectIntHashMap allVars, + TIntHashSet vars) { + condition.collectVars(allVars, vars); + then_.collectVars(allVars, vars); + if(else_ != null) + else_.collectVars(allVars, vars); + } + + @Override + protected void updateType() throws MatchException { + setType(then_.getType()); + } + + @Override + public IVal toVal(Environment env, CodeWriter w) { + IVal conditionVal = condition.toVal(env, w); + CodeWriter joinPoint = w.createBlock(getType()); + CodeWriter thenBlock = w.createBlock(); + if(else_ != null) { + CodeWriter elseBlock = w.createBlock(); + w.if_(conditionVal, thenBlock.getContinuation(), elseBlock.getContinuation()); + + IVal elseVal = else_.toVal(env, elseBlock); + elseBlock.jump(joinPoint.getContinuation(), elseVal); + } + else { + w.if_(conditionVal, thenBlock.getContinuation(), joinPoint.getContinuation()); + } + IVal thenVal = then_.toVal(env, thenBlock); + thenBlock.jump(joinPoint.getContinuation(), thenVal); + w.continueAs(joinPoint); + + return w.getParameters()[0]; + } + + @Override + public void collectFreeVariables(THashSet vars) { + condition.collectFreeVariables(vars); + then_.collectFreeVariables(vars); + if(else_ != null) + else_.collectFreeVariables(vars); + } + + @Override + public Expression simplify(SimplificationContext context) { + condition = condition.simplify(context); + then_ = then_.simplify(context); + if(else_ != null) + else_ = else_.simplify(context); + return this; + } + + @Override + public Expression resolve(TranslationContext context) { + condition = condition.resolve(context); + then_ = then_.resolve(context); + if(else_ != null) + else_ = else_.resolve(context); + return this; + } + + @Override + public Expression replace(ReplaceContext context) { + return new EIf(condition.replace(context), + then_.replace(context), + else_ == null ? null : else_.replace(context)); + } + + @Override + public Expression checkBasicType(TypingContext context, Type requiredType) { + condition = condition.checkType(context, Types.BOOLEAN); + then_ = then_.checkType(context, requiredType); + if(else_ != null) + else_ = else_.checkType(context, requiredType); + else + context.getErrorLog().log(location, "Else branch is required because the return value of the if expression is used."); + return this; + } + + @Override + public Expression checkIgnoredType(TypingContext context) { + condition = condition.checkType(context, Types.BOOLEAN); + then_ = then_.checkIgnoredType(context); + if(else_ != null) + else_ = else_.checkIgnoredType(context); + return this; + } + + @Override + public Expression decorate(ExpressionDecorator decorator) { + condition = condition.decorate(decorator); + then_ = then_.decorate(decorator); + if(else_ != null) + else_ = else_.decorate(decorator); + return decorator.decorate(this); + } + + @Override + public boolean isEffectful() { + return condition.isEffectful() || then_.isEffectful() || (else_ != null && else_.isEffectful()); + } + + @Override + public void collectEffects(THashSet effects) { + condition.collectEffects(effects); + then_.collectEffects(effects); + if(else_ != null) + else_.collectEffects(effects); + } + + @Override + public void setLocationDeep(long loc) { + if(location == Locations.NO_LOCATION) { + location = loc; + condition.setLocationDeep(loc); + then_.setLocationDeep(loc); + if(else_ != null) + else_.setLocationDeep(loc); + } + } + + @Override + public void accept(ExpressionVisitor visitor) { + visitor.visit(this); + } + + @Override + public IExpression toIExpression(ExpressionInterpretationContext target) { + return new IIf(condition.toIExpression(target), then_.toIExpression(target), + else_ != null ? else_.toIExpression(target) : new IConstant(Tuple0.INSTANCE)); + } + + @Override + public void forVariables(VariableProcedure procedure) { + condition.forVariables(procedure); + then_.forVariables(procedure); + if(else_ != null) + else_.forVariables(procedure); + } + @Override + public Expression accept(ExpressionTransformer transformer) { + return transformer.transform(this); + } + + @Override + public int getSyntacticFunctionArity() { + return Math.max(then_.getSyntacticFunctionArity(), else_.getSyntacticFunctionArity()); + } +} diff --git a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/expressions/ELambda.java b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/expressions/ELambda.java index abf4c89da..67a7e1476 100755 --- a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/expressions/ELambda.java +++ b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/expressions/ELambda.java @@ -1,215 +1,223 @@ -package org.simantics.scl.compiler.elaboration.expressions; - -import org.simantics.scl.compiler.elaboration.contexts.ReplaceContext; -import org.simantics.scl.compiler.elaboration.contexts.SimplificationContext; -import org.simantics.scl.compiler.elaboration.contexts.TranslationContext; -import org.simantics.scl.compiler.elaboration.contexts.TypingContext; -import org.simantics.scl.compiler.errors.Locations; -import org.simantics.scl.compiler.internal.elaboration.utils.ExpressionDecorator; -import org.simantics.scl.compiler.types.Type; -import org.simantics.scl.compiler.types.Types; -import org.simantics.scl.compiler.types.exceptions.MatchException; -import org.simantics.scl.compiler.types.exceptions.UnificationException; -import org.simantics.scl.compiler.types.kinds.Kinds; -import org.simantics.scl.compiler.types.util.MultiFunction; - -import gnu.trove.map.hash.TObjectIntHashMap; -import gnu.trove.set.hash.THashSet; -import gnu.trove.set.hash.TIntHashSet; - -public class ELambda extends SimplifiableExpression { - public Case[] cases; - Type effect = Types.NO_EFFECTS; - - public ELambda(Case[] cases) { - this.cases = cases; - } - - public ELambda(Case case_) { - this(new Case[] {case_}); - } - - public ELambda(long loc, Case ... cases) { - super(loc); - this.cases = cases; - } - - public ELambda(long loc, Expression pat, Expression exp) { - this(loc, new Case(new Expression[] {pat}, exp)); - } - - public void collectRefs(TObjectIntHashMap allRefs, TIntHashSet refs) { - for(Case case_ : cases) - case_.collectRefs(allRefs, refs); - } - - @Override - public void collectVars(TObjectIntHashMap allVars, - TIntHashSet vars) { - for(Case case_ : cases) - case_.collectVars(allVars, vars); - } - - public Expression decomposeMatching() { - Expression[] patterns = cases[0].patterns; - int arity = patterns.length; - - // Simple cases - if(cases.length == 1 && - !(cases[0].value instanceof GuardedExpressionGroup)) { - boolean noMatchingNeeded = true; - for(int i=0;i=0;--i) { - Variable var = ((EVariable)patterns[i]).getVariable(); - decomposed = new ESimpleLambda(getLocation(), var, effect, decomposed); - effect = Types.NO_EFFECTS; - } - return decomposed; - } - } - - // Complex case - Variable[] vars = new Variable[arity]; - Expression[] scrutinee = new Expression[arity]; - for(int i=0;i=0;--i) { - decomposed = new ESimpleLambda(getLocation(), vars[i], curEffect, decomposed); - curEffect = Types.NO_EFFECTS; - } - return decomposed; - } - - @Override - protected void updateType() throws MatchException { - setType(Types.functionE(Types.getTypes(cases[0].patterns), effect, cases[0].value.getType())); - } - - @Override - public Expression simplify(SimplificationContext context) { - return decomposeMatching().simplify(context); - } - - @Override - public void collectFreeVariables(THashSet vars) { - for(Case case_ : cases) - case_.collectFreeVariables(vars); - } - - @Override - public Expression resolve(TranslationContext context) { - for(Case case_ : cases) - case_.resolve(context); - return this; - } - - @Override - public void setLocationDeep(long loc) { - if(location == Locations.NO_LOCATION) { - location = loc; - for(Case case_ : cases) - case_.setLocationDeep(loc); - } - } - - @Override - public Expression replace(ReplaceContext context) { - Case[] newCases = new Case[cases.length]; - for(int i=0;i effects) { - for(Case case_ : cases) { - for(Expression pattern : case_.patterns) - pattern.collectEffects(effects); - case_.value.collectEffects(effects); - } - } - - @Override - public void accept(ExpressionVisitor visitor) { - visitor.visit(this); - } - - @Override - public void forVariables(VariableProcedure procedure) { - for(Case case_ : cases) - case_.forVariables(procedure); - } - - @Override - public Expression accept(ExpressionTransformer transformer) { - return transformer.transform(this); - } - -} +package org.simantics.scl.compiler.elaboration.expressions; + +import org.simantics.scl.compiler.elaboration.contexts.ReplaceContext; +import org.simantics.scl.compiler.elaboration.contexts.SimplificationContext; +import org.simantics.scl.compiler.elaboration.contexts.TranslationContext; +import org.simantics.scl.compiler.elaboration.contexts.TypingContext; +import org.simantics.scl.compiler.errors.Locations; +import org.simantics.scl.compiler.internal.elaboration.utils.ExpressionDecorator; +import org.simantics.scl.compiler.types.Type; +import org.simantics.scl.compiler.types.Types; +import org.simantics.scl.compiler.types.exceptions.MatchException; +import org.simantics.scl.compiler.types.exceptions.UnificationException; +import org.simantics.scl.compiler.types.kinds.Kinds; +import org.simantics.scl.compiler.types.util.MultiFunction; + +import gnu.trove.map.hash.TObjectIntHashMap; +import gnu.trove.set.hash.THashSet; +import gnu.trove.set.hash.TIntHashSet; + +public class ELambda extends SimplifiableExpression { + public Case[] cases; + Type effect = Types.NO_EFFECTS; + + public ELambda(Case[] cases) { + this.cases = cases; + } + + public ELambda(Case case_) { + this(new Case[] {case_}); + } + + public ELambda(long loc, Case ... cases) { + super(loc); + this.cases = cases; + } + + public ELambda(long loc, Expression pat, Expression exp) { + this(loc, new Case(new Expression[] {pat}, exp)); + } + + public void collectRefs(TObjectIntHashMap allRefs, TIntHashSet refs) { + for(Case case_ : cases) + case_.collectRefs(allRefs, refs); + } + + @Override + public void collectVars(TObjectIntHashMap allVars, + TIntHashSet vars) { + for(Case case_ : cases) + case_.collectVars(allVars, vars); + } + + public Expression decomposeMatching() { + Expression[] patterns = cases[0].patterns; + int arity = patterns.length; + + // Simple cases + if(cases.length == 1 && + !(cases[0].value instanceof GuardedExpressionGroup)) { + boolean noMatchingNeeded = true; + for(int i=0;i=0;--i) { + Variable var = ((EVariable)patterns[i]).getVariable(); + decomposed = new ESimpleLambda(getLocation(), var, effect, decomposed); + effect = Types.NO_EFFECTS; + } + return decomposed; + } + } + + // Complex case + Variable[] vars = new Variable[arity]; + Expression[] scrutinee = new Expression[arity]; + for(int i=0;i=0;--i) { + decomposed = new ESimpleLambda(getLocation(), vars[i], curEffect, decomposed); + curEffect = Types.NO_EFFECTS; + } + return decomposed; + } + + @Override + protected void updateType() throws MatchException { + setType(Types.functionE(Types.getTypes(cases[0].patterns), effect, cases[0].value.getType())); + } + + @Override + public Expression simplify(SimplificationContext context) { + return decomposeMatching().simplify(context); + } + + @Override + public void collectFreeVariables(THashSet vars) { + for(Case case_ : cases) + case_.collectFreeVariables(vars); + } + + @Override + public Expression resolve(TranslationContext context) { + for(Case case_ : cases) + case_.resolve(context); + return this; + } + + @Override + public void setLocationDeep(long loc) { + if(location == Locations.NO_LOCATION) { + location = loc; + for(Case case_ : cases) + case_.setLocationDeep(loc); + } + } + + @Override + public Expression replace(ReplaceContext context) { + Case[] newCases = new Case[cases.length]; + for(int i=0;i effects) { + for(Case case_ : cases) { + for(Expression pattern : case_.patterns) + pattern.collectEffects(effects); + case_.value.collectEffects(effects); + } + } + + @Override + public void accept(ExpressionVisitor visitor) { + visitor.visit(this); + } + + @Override + public void forVariables(VariableProcedure procedure) { + for(Case case_ : cases) + case_.forVariables(procedure); + } + + @Override + public Expression accept(ExpressionTransformer transformer) { + return transformer.transform(this); + } + + @Override + public int getSyntacticFunctionArity() { + int result = 0; + for(Case case_ : cases) + result = Math.max(result, case_.patterns.length + case_.value.getSyntacticFunctionArity()); + return result; + } + +} diff --git a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/expressions/ELambdaType.java b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/expressions/ELambdaType.java index 8e9a74cd5..08e47bf95 100755 --- a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/expressions/ELambdaType.java +++ b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/expressions/ELambdaType.java @@ -1,129 +1,134 @@ -package org.simantics.scl.compiler.elaboration.expressions; - -import org.simantics.scl.compiler.common.exceptions.InternalCompilerError; -import org.simantics.scl.compiler.elaboration.contexts.ReplaceContext; -import org.simantics.scl.compiler.elaboration.contexts.SimplificationContext; -import org.simantics.scl.compiler.elaboration.contexts.TranslationContext; -import org.simantics.scl.compiler.elaboration.contexts.TypingContext; -import org.simantics.scl.compiler.environment.Environment; -import org.simantics.scl.compiler.errors.Locations; -import org.simantics.scl.compiler.internal.codegen.references.IVal; -import org.simantics.scl.compiler.internal.codegen.writer.CodeWriter; -import org.simantics.scl.compiler.internal.elaboration.utils.ExpressionDecorator; -import org.simantics.scl.compiler.internal.interpreted.IExpression; -import org.simantics.scl.compiler.top.ExpressionInterpretationContext; -import org.simantics.scl.compiler.types.TVar; -import org.simantics.scl.compiler.types.Type; -import org.simantics.scl.compiler.types.Types; -import org.simantics.scl.compiler.types.exceptions.MatchException; - -import gnu.trove.map.hash.TObjectIntHashMap; -import gnu.trove.set.hash.THashSet; -import gnu.trove.set.hash.TIntHashSet; - -public class ELambdaType extends Expression { - public TVar[] parameters; - public Expression value; - - public ELambdaType(TVar[] parameters, Expression value) { - super(value.getLocation()); - this.parameters = parameters; - this.value = value; - } - - public void collectRefs(TObjectIntHashMap allRefs, TIntHashSet refs) { - value.collectRefs(allRefs, refs); - } - - @Override - public void collectVars(TObjectIntHashMap allVars, - TIntHashSet vars) { - value.collectVars(allVars, vars); - } - - @Override - protected void updateType() throws MatchException { - setType(Types.forAll(parameters, value.getType())); - } - - @Override - public IVal toVal(Environment env, CodeWriter w) { - return lambdaToVal(env, w); - } - - @Override - public void collectFreeVariables(THashSet vars) { - value.collectFreeVariables(vars); - } - - @Override - public Expression simplify(SimplificationContext context) { - value = value.simplify(context); - return this; - } - - @Override - public Expression resolve(TranslationContext context) { - value = value.resolve(context); - return this; - } - - @Override - public Expression replace(ReplaceContext context) { - TVar[] newParameters = new TVar[parameters.length]; - for(int i=0;i effects) { - } - - @Override - public void setLocationDeep(long loc) { - if(location == Locations.NO_LOCATION) { - location = loc; - value.setLocationDeep(loc); - } - } - - @Override - public void accept(ExpressionVisitor visitor) { - visitor.visit(this); - } - - @Override - public void forVariables(VariableProcedure procedure) { - value.forVariables(procedure); - } - - @Override - public Expression accept(ExpressionTransformer transformer) { - return transformer.transform(this); - } - -} +package org.simantics.scl.compiler.elaboration.expressions; + +import org.simantics.scl.compiler.common.exceptions.InternalCompilerError; +import org.simantics.scl.compiler.elaboration.contexts.ReplaceContext; +import org.simantics.scl.compiler.elaboration.contexts.SimplificationContext; +import org.simantics.scl.compiler.elaboration.contexts.TranslationContext; +import org.simantics.scl.compiler.elaboration.contexts.TypingContext; +import org.simantics.scl.compiler.environment.Environment; +import org.simantics.scl.compiler.errors.Locations; +import org.simantics.scl.compiler.internal.codegen.references.IVal; +import org.simantics.scl.compiler.internal.codegen.writer.CodeWriter; +import org.simantics.scl.compiler.internal.elaboration.utils.ExpressionDecorator; +import org.simantics.scl.compiler.internal.interpreted.IExpression; +import org.simantics.scl.compiler.top.ExpressionInterpretationContext; +import org.simantics.scl.compiler.types.TVar; +import org.simantics.scl.compiler.types.Type; +import org.simantics.scl.compiler.types.Types; +import org.simantics.scl.compiler.types.exceptions.MatchException; + +import gnu.trove.map.hash.TObjectIntHashMap; +import gnu.trove.set.hash.THashSet; +import gnu.trove.set.hash.TIntHashSet; + +public class ELambdaType extends Expression { + public TVar[] parameters; + public Expression value; + + public ELambdaType(TVar[] parameters, Expression value) { + super(value.getLocation()); + this.parameters = parameters; + this.value = value; + } + + public void collectRefs(TObjectIntHashMap allRefs, TIntHashSet refs) { + value.collectRefs(allRefs, refs); + } + + @Override + public void collectVars(TObjectIntHashMap allVars, + TIntHashSet vars) { + value.collectVars(allVars, vars); + } + + @Override + protected void updateType() throws MatchException { + setType(Types.forAll(parameters, value.getType())); + } + + @Override + public IVal toVal(Environment env, CodeWriter w) { + return lambdaToVal(env, w); + } + + @Override + public void collectFreeVariables(THashSet vars) { + value.collectFreeVariables(vars); + } + + @Override + public Expression simplify(SimplificationContext context) { + value = value.simplify(context); + return this; + } + + @Override + public Expression resolve(TranslationContext context) { + value = value.resolve(context); + return this; + } + + @Override + public Expression replace(ReplaceContext context) { + TVar[] newParameters = new TVar[parameters.length]; + for(int i=0;i effects) { + } + + @Override + public void setLocationDeep(long loc) { + if(location == Locations.NO_LOCATION) { + location = loc; + value.setLocationDeep(loc); + } + } + + @Override + public void accept(ExpressionVisitor visitor) { + visitor.visit(this); + } + + @Override + public void forVariables(VariableProcedure procedure) { + value.forVariables(procedure); + } + + @Override + public Expression accept(ExpressionTransformer transformer) { + return transformer.transform(this); + } + + @Override + public int getSyntacticFunctionArity() { + return value.getSyntacticFunctionArity(); + } + +} diff --git a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/expressions/ELet.java b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/expressions/ELet.java index bbbc25c4d..d10066f90 100755 --- a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/expressions/ELet.java +++ b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/expressions/ELet.java @@ -1,257 +1,262 @@ -package org.simantics.scl.compiler.elaboration.expressions; - -import java.util.ArrayList; - -import org.simantics.scl.compiler.common.exceptions.InternalCompilerError; -import org.simantics.scl.compiler.elaboration.contexts.ReplaceContext; -import org.simantics.scl.compiler.elaboration.contexts.SimplificationContext; -import org.simantics.scl.compiler.elaboration.contexts.TranslationContext; -import org.simantics.scl.compiler.elaboration.contexts.TypingContext; -import org.simantics.scl.compiler.environment.Environment; -import org.simantics.scl.compiler.errors.Locations; -import org.simantics.scl.compiler.internal.codegen.references.BoundVar; -import org.simantics.scl.compiler.internal.codegen.references.IVal; -import org.simantics.scl.compiler.internal.codegen.writer.CodeWriter; -import org.simantics.scl.compiler.internal.codegen.writer.RecursiveDefinitionWriter; -import org.simantics.scl.compiler.internal.elaboration.decomposed.DecomposedExpression; -import org.simantics.scl.compiler.internal.elaboration.utils.ExpressionDecorator; -import org.simantics.scl.compiler.internal.elaboration.utils.StronglyConnectedComponents; -import org.simantics.scl.compiler.types.Type; -import org.simantics.scl.compiler.types.Types; -import org.simantics.scl.compiler.types.exceptions.MatchException; -import org.simantics.scl.compiler.types.kinds.Kinds; - -import gnu.trove.map.hash.TObjectIntHashMap; -import gnu.trove.set.hash.THashSet; -import gnu.trove.set.hash.TIntHashSet; - -public class ELet extends Expression { - public Assignment[] assignments; - public Expression in; - - public ELet(long loc, Assignment[] assignments, Expression in) { - super(loc); - this.assignments = assignments; - this.in = in; - } - - @Override - public void collectRefs(final TObjectIntHashMap allRefs, final TIntHashSet refs) { - for(Assignment assign : assignments) - assign.value.collectRefs(allRefs, refs); - in.collectRefs(allRefs, refs); - } - - @Override - public void collectVars(TObjectIntHashMap allVars, - TIntHashSet vars) { - for(Assignment assign : assignments) - assign.value.collectVars(allVars, vars); - in.collectVars(allVars, vars); - } - - @Override - protected void updateType() throws MatchException { - setType(in.getType()); - } - - /** - * Splits let - */ - @Override - public Expression simplify(SimplificationContext context) { - - // Simplify assignments - for(Assignment assignment : assignments) { - assignment.value = assignment.value.simplify(context); - } - - // Find strongly connected components - final TObjectIntHashMap allVars = new TObjectIntHashMap( - 2*assignments.length, 0.5f, -1); - - for(int i=0;i components = new ArrayList(Math.max(10, assignments.length)); - new StronglyConnectedComponents(assignments.length) { - @Override - protected int[] findDependencies(int u) { - TIntHashSet vars = new TIntHashSet(); - assignments[u].value.collectVars(allVars, vars); - if(vars.contains(u)) - isRecursive[u] = true; - return vars.toArray(); - } - - @Override - protected void reportComponent(int[] component) { - components.add(component); - } - - }.findComponents(); - - // Simplify in - Expression result = in.simplify(context); - - // Handle each component - for(int j=components.size()-1;j>=0;--j) { - int[] component = components.get(j); - boolean recursive = component.length > 1 || isRecursive[component[0]]; - if(recursive) { - Assignment[] cAssignments = new Assignment[component.length]; - for(int i=0;i vars) { - in.collectFreeVariables(vars); - for(Assignment assign : assignments) - assign.value.collectFreeVariables(vars); - for(Assignment assign : assignments) - assign.pattern.removeFreeVariables(vars); - } - - @Override - public Expression resolve(TranslationContext context) { - throw new InternalCompilerError("ELet should be already resolved."); - } - - @Override - public Expression replace(ReplaceContext context) { - Assignment[] newAssignments = new Assignment[assignments.length]; - for(int i=0;i effects) { - for(Assignment assignment : assignments) { - assignment.pattern.collectEffects(effects); - assignment.value.collectEffects(effects); - } - in.collectEffects(effects); - } - - @Override - public void setLocationDeep(long loc) { - if(location == Locations.NO_LOCATION) { - location = loc; - for(Assignment assignment : assignments) - assignment.setLocationDeep(loc); - in.setLocationDeep(loc); - } - } - - @Override - public void accept(ExpressionVisitor visitor) { - visitor.visit(this); - } - - @Override - public void forVariables(VariableProcedure procedure) { - for(Assignment assignment : assignments) - assignment.forVariables(procedure); - in.forVariables(procedure); - } - - @Override - public Expression accept(ExpressionTransformer transformer) { - return transformer.transform(this); - } - -} +package org.simantics.scl.compiler.elaboration.expressions; + +import java.util.ArrayList; + +import org.simantics.scl.compiler.common.exceptions.InternalCompilerError; +import org.simantics.scl.compiler.elaboration.contexts.ReplaceContext; +import org.simantics.scl.compiler.elaboration.contexts.SimplificationContext; +import org.simantics.scl.compiler.elaboration.contexts.TranslationContext; +import org.simantics.scl.compiler.elaboration.contexts.TypingContext; +import org.simantics.scl.compiler.environment.Environment; +import org.simantics.scl.compiler.errors.Locations; +import org.simantics.scl.compiler.internal.codegen.references.BoundVar; +import org.simantics.scl.compiler.internal.codegen.references.IVal; +import org.simantics.scl.compiler.internal.codegen.writer.CodeWriter; +import org.simantics.scl.compiler.internal.codegen.writer.RecursiveDefinitionWriter; +import org.simantics.scl.compiler.internal.elaboration.decomposed.DecomposedExpression; +import org.simantics.scl.compiler.internal.elaboration.utils.ExpressionDecorator; +import org.simantics.scl.compiler.internal.elaboration.utils.StronglyConnectedComponents; +import org.simantics.scl.compiler.types.Type; +import org.simantics.scl.compiler.types.Types; +import org.simantics.scl.compiler.types.exceptions.MatchException; +import org.simantics.scl.compiler.types.kinds.Kinds; + +import gnu.trove.map.hash.TObjectIntHashMap; +import gnu.trove.set.hash.THashSet; +import gnu.trove.set.hash.TIntHashSet; + +public class ELet extends Expression { + public Assignment[] assignments; + public Expression in; + + public ELet(long loc, Assignment[] assignments, Expression in) { + super(loc); + this.assignments = assignments; + this.in = in; + } + + @Override + public void collectRefs(final TObjectIntHashMap allRefs, final TIntHashSet refs) { + for(Assignment assign : assignments) + assign.value.collectRefs(allRefs, refs); + in.collectRefs(allRefs, refs); + } + + @Override + public void collectVars(TObjectIntHashMap allVars, + TIntHashSet vars) { + for(Assignment assign : assignments) + assign.value.collectVars(allVars, vars); + in.collectVars(allVars, vars); + } + + @Override + protected void updateType() throws MatchException { + setType(in.getType()); + } + + /** + * Splits let + */ + @Override + public Expression simplify(SimplificationContext context) { + + // Simplify assignments + for(Assignment assignment : assignments) { + assignment.value = assignment.value.simplify(context); + } + + // Find strongly connected components + final TObjectIntHashMap allVars = new TObjectIntHashMap( + 2*assignments.length, 0.5f, -1); + + for(int i=0;i components = new ArrayList(Math.max(10, assignments.length)); + new StronglyConnectedComponents(assignments.length) { + @Override + protected int[] findDependencies(int u) { + TIntHashSet vars = new TIntHashSet(); + assignments[u].value.collectVars(allVars, vars); + if(vars.contains(u)) + isRecursive[u] = true; + return vars.toArray(); + } + + @Override + protected void reportComponent(int[] component) { + components.add(component); + } + + }.findComponents(); + + // Simplify in + Expression result = in.simplify(context); + + // Handle each component + for(int j=components.size()-1;j>=0;--j) { + int[] component = components.get(j); + boolean recursive = component.length > 1 || isRecursive[component[0]]; + if(recursive) { + Assignment[] cAssignments = new Assignment[component.length]; + for(int i=0;i vars) { + in.collectFreeVariables(vars); + for(Assignment assign : assignments) + assign.value.collectFreeVariables(vars); + for(Assignment assign : assignments) + assign.pattern.removeFreeVariables(vars); + } + + @Override + public Expression resolve(TranslationContext context) { + throw new InternalCompilerError("ELet should be already resolved."); + } + + @Override + public Expression replace(ReplaceContext context) { + Assignment[] newAssignments = new Assignment[assignments.length]; + for(int i=0;i effects) { + for(Assignment assignment : assignments) { + assignment.pattern.collectEffects(effects); + assignment.value.collectEffects(effects); + } + in.collectEffects(effects); + } + + @Override + public void setLocationDeep(long loc) { + if(location == Locations.NO_LOCATION) { + location = loc; + for(Assignment assignment : assignments) + assignment.setLocationDeep(loc); + in.setLocationDeep(loc); + } + } + + @Override + public void accept(ExpressionVisitor visitor) { + visitor.visit(this); + } + + @Override + public void forVariables(VariableProcedure procedure) { + for(Assignment assignment : assignments) + assignment.forVariables(procedure); + in.forVariables(procedure); + } + + @Override + public Expression accept(ExpressionTransformer transformer) { + return transformer.transform(this); + } + + @Override + public int getSyntacticFunctionArity() { + return in.getSyntacticFunctionArity(); + } + +} diff --git a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/expressions/EMatch.java b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/expressions/EMatch.java index 11877a60e..d1a96d04a 100755 --- a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/expressions/EMatch.java +++ b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/expressions/EMatch.java @@ -1,213 +1,220 @@ -package org.simantics.scl.compiler.elaboration.expressions; - -import java.util.ArrayList; - -import org.simantics.scl.compiler.elaboration.contexts.ReplaceContext; -import org.simantics.scl.compiler.elaboration.contexts.SimplificationContext; -import org.simantics.scl.compiler.elaboration.contexts.TranslationContext; -import org.simantics.scl.compiler.elaboration.contexts.TypingContext; -import org.simantics.scl.compiler.environment.Environment; -import org.simantics.scl.compiler.errors.Locations; -import org.simantics.scl.compiler.internal.codegen.references.IVal; -import org.simantics.scl.compiler.internal.codegen.ssa.exits.Throw; -import org.simantics.scl.compiler.internal.codegen.writer.CodeWriter; -import org.simantics.scl.compiler.internal.elaboration.matching.PatternMatchingCompiler; -import org.simantics.scl.compiler.internal.elaboration.matching.Row; -import org.simantics.scl.compiler.internal.elaboration.utils.ExpressionDecorator; -import org.simantics.scl.compiler.types.Type; -import org.simantics.scl.compiler.types.Types; -import org.simantics.scl.compiler.types.kinds.Kinds; - -import gnu.trove.map.hash.TObjectIntHashMap; -import gnu.trove.set.hash.THashSet; -import gnu.trove.set.hash.TIntHashSet; - -public class EMatch extends Expression { - - public Expression[] scrutinee; - public Case[] cases; - - public EMatch(Expression[] scrutinee, Case ... cases) { - this.scrutinee = scrutinee; - this.cases = cases; - } - - public EMatch(Expression scrutinee, Case ... cases) { - this(new Expression[] {scrutinee}, cases); - } - - public EMatch(long loc, Expression[] scrutinee, Case ... cases) { - super(loc); - this.scrutinee = scrutinee; - this.cases = cases; - } - - public void collectRefs(TObjectIntHashMap allRefs, TIntHashSet refs) { - for(Expression s : scrutinee) - s.collectRefs(allRefs, refs); - for(Case case_ : cases) - case_.collectRefs(allRefs, refs); - } - - @Override - public void collectVars(TObjectIntHashMap allVars, - TIntHashSet vars) { - for(Expression s : scrutinee) - s.collectVars(allVars, vars); - for(Case case_ : cases) - case_.collectVars(allVars, vars); - } - - @Override - protected void updateType() { - setType(cases[0].value.getType()); - } - - @Override - public IVal toVal(Environment env, CodeWriter w) { - ArrayList rows = new ArrayList(cases.length); - for(Case case_ : cases) - rows.add(new Row(case_.patterns, case_.value)); - - IVal[] scrutineeVals = new IVal[scrutinee.length]; - for(int i=0;i vars) { - for(Expression s : scrutinee) - s.collectFreeVariables(vars); - for(Case case_ : cases) - case_.collectFreeVariables(vars); - } - - @Override - public Expression simplify(SimplificationContext context) { - for(int i=0;i effects) { - for(Expression s : scrutinee) - s.collectEffects(effects); - for(Case case_ : cases) { - for(Expression pattern : case_.patterns) - pattern.collectEffects(effects); - case_.value.collectEffects(effects); - } - } - - @Override - public void accept(ExpressionVisitor visitor) { - visitor.visit(this); - } - - public Expression[] getScrutinee() { - return scrutinee; - } - - public Case[] getCases() { - return cases; - } - - @Override - public void forVariables(VariableProcedure procedure) { - for(Expression s : scrutinee) - s.forVariables(procedure); - for(Case case_ : cases) - case_.forVariables(procedure); - } - - @Override - public Expression accept(ExpressionTransformer transformer) { - return transformer.transform(this); - } - -} +package org.simantics.scl.compiler.elaboration.expressions; + +import java.util.ArrayList; + +import org.simantics.scl.compiler.elaboration.contexts.ReplaceContext; +import org.simantics.scl.compiler.elaboration.contexts.SimplificationContext; +import org.simantics.scl.compiler.elaboration.contexts.TranslationContext; +import org.simantics.scl.compiler.elaboration.contexts.TypingContext; +import org.simantics.scl.compiler.environment.Environment; +import org.simantics.scl.compiler.errors.Locations; +import org.simantics.scl.compiler.internal.codegen.references.IVal; +import org.simantics.scl.compiler.internal.codegen.ssa.exits.Throw; +import org.simantics.scl.compiler.internal.codegen.writer.CodeWriter; +import org.simantics.scl.compiler.internal.elaboration.matching.PatternMatchingCompiler; +import org.simantics.scl.compiler.internal.elaboration.matching.Row; +import org.simantics.scl.compiler.internal.elaboration.utils.ExpressionDecorator; +import org.simantics.scl.compiler.types.Type; +import org.simantics.scl.compiler.types.Types; +import org.simantics.scl.compiler.types.kinds.Kinds; + +import gnu.trove.map.hash.TObjectIntHashMap; +import gnu.trove.set.hash.THashSet; +import gnu.trove.set.hash.TIntHashSet; + +public class EMatch extends Expression { + + public Expression[] scrutinee; + public Case[] cases; + + public EMatch(Expression[] scrutinee, Case ... cases) { + this.scrutinee = scrutinee; + this.cases = cases; + } + + public EMatch(Expression scrutinee, Case ... cases) { + this(new Expression[] {scrutinee}, cases); + } + + public EMatch(long loc, Expression[] scrutinee, Case ... cases) { + super(loc); + this.scrutinee = scrutinee; + this.cases = cases; + } + + public void collectRefs(TObjectIntHashMap allRefs, TIntHashSet refs) { + for(Expression s : scrutinee) + s.collectRefs(allRefs, refs); + for(Case case_ : cases) + case_.collectRefs(allRefs, refs); + } + + @Override + public void collectVars(TObjectIntHashMap allVars, + TIntHashSet vars) { + for(Expression s : scrutinee) + s.collectVars(allVars, vars); + for(Case case_ : cases) + case_.collectVars(allVars, vars); + } + + @Override + protected void updateType() { + setType(cases[0].value.getType()); + } + + @Override + public IVal toVal(Environment env, CodeWriter w) { + ArrayList rows = new ArrayList(cases.length); + for(Case case_ : cases) + rows.add(new Row(case_.patterns, case_.value)); + + IVal[] scrutineeVals = new IVal[scrutinee.length]; + for(int i=0;i vars) { + for(Expression s : scrutinee) + s.collectFreeVariables(vars); + for(Case case_ : cases) + case_.collectFreeVariables(vars); + } + + @Override + public Expression simplify(SimplificationContext context) { + for(int i=0;i effects) { + for(Expression s : scrutinee) + s.collectEffects(effects); + for(Case case_ : cases) { + for(Expression pattern : case_.patterns) + pattern.collectEffects(effects); + case_.value.collectEffects(effects); + } + } + + @Override + public void accept(ExpressionVisitor visitor) { + visitor.visit(this); + } + + public Expression[] getScrutinee() { + return scrutinee; + } + + public Case[] getCases() { + return cases; + } + + @Override + public void forVariables(VariableProcedure procedure) { + for(Expression s : scrutinee) + s.forVariables(procedure); + for(Case case_ : cases) + case_.forVariables(procedure); + } + + @Override + public Expression accept(ExpressionTransformer transformer) { + return transformer.transform(this); + } + + @Override + public int getSyntacticFunctionArity() { + int result = 0; + for(Case case_ : cases) + result = Math.max(result, case_.value.getSyntacticFunctionArity()); + return result; + } +} diff --git a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/expressions/EPreLet.java b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/expressions/EPreLet.java index 8d8883eae..c78b9f457 100755 --- a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/expressions/EPreLet.java +++ b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/expressions/EPreLet.java @@ -1,97 +1,102 @@ -package org.simantics.scl.compiler.elaboration.expressions; - -import java.util.ArrayList; -import java.util.List; - -import org.simantics.scl.compiler.elaboration.contexts.TranslationContext; -import org.simantics.scl.compiler.elaboration.errors.NotPatternException; -import org.simantics.scl.compiler.elaboration.expressions.block.LetStatement; -import org.simantics.scl.compiler.elaboration.expressions.lhstype.FunctionDefinitionLhs; -import org.simantics.scl.compiler.elaboration.expressions.lhstype.LhsType; -import org.simantics.scl.compiler.errors.Locations; - -import gnu.trove.map.hash.THashMap; -import gnu.trove.procedure.TObjectObjectProcedure; - -public class EPreLet extends ASTExpression { - - List assignments; - Expression in; - - public EPreLet(List assignments, Expression in) { - this.assignments = assignments; - this.in = in; - } - - @Override - public Expression resolve(final TranslationContext context) { - context.pushFrame(); - THashMap> functionDefinitions = - new THashMap>(); - ArrayList otherDefinitions = new ArrayList(); - final THashMap localVars = new THashMap(); - try { - for(LetStatement assign : assignments) { - LhsType lhsType = assign.pattern.getLhsType(); - if(!(assign.pattern instanceof EVar) && lhsType instanceof FunctionDefinitionLhs) { - String name = ((FunctionDefinitionLhs)lhsType).functionName; - ArrayList group = functionDefinitions.get(name); - if(group == null) { - group = new ArrayList(2); - functionDefinitions.put(name, group); - } - group.add(assign); - localVars.put(name, context.newVariable(name)); - } - else { - otherDefinitions.add(assign); - assign.pattern = assign.pattern.resolveAsPattern(context); - } - } - } catch (NotPatternException e) { - context.getErrorLog().log(e.getExpression().location, "Not a pattern."); - return new EError(); - } - - final ArrayList as = new ArrayList(functionDefinitions.size() + otherDefinitions.size()); - functionDefinitions.forEachEntry(new TObjectObjectProcedure>() { - @Override - public boolean execute(String name, ArrayList cases) { - as.add(new Assignment( - new EVariable(cases.size()==1 ? cases.get(0).pattern.location : location, localVars.get(name)), - context.translateCases(cases))); - return true; - } - }); - for(LetStatement stat : otherDefinitions) - as.add(new Assignment( - stat.pattern /* already resolved above */, - stat.value.resolve(context))); - Expression inExpr = in.resolve(context); - context.popFrame(); - - ELet result = new ELet(location, as.toArray(new Assignment[as.size()]), inExpr); - /*System.out.println("-----------------------------------------"); - System.out.println(this); - System.out.println("-----------------------------------------"); - System.out.println(result); - System.out.println("-----------------------------------------");*/ - return result; - } - - @Override - public void setLocationDeep(long loc) { - if(location == Locations.NO_LOCATION) { - location = loc; - for(LetStatement assignment : assignments) - assignment.setLocationDeep(loc); - in.setLocationDeep(loc); - } - } - - @Override - public Expression accept(ExpressionTransformer transformer) { - return transformer.transform(this); - } - -} +package org.simantics.scl.compiler.elaboration.expressions; + +import java.util.ArrayList; +import java.util.List; + +import org.simantics.scl.compiler.elaboration.contexts.TranslationContext; +import org.simantics.scl.compiler.elaboration.errors.NotPatternException; +import org.simantics.scl.compiler.elaboration.expressions.block.LetStatement; +import org.simantics.scl.compiler.elaboration.expressions.lhstype.FunctionDefinitionLhs; +import org.simantics.scl.compiler.elaboration.expressions.lhstype.LhsType; +import org.simantics.scl.compiler.errors.Locations; + +import gnu.trove.map.hash.THashMap; +import gnu.trove.procedure.TObjectObjectProcedure; + +public class EPreLet extends ASTExpression { + + List assignments; + Expression in; + + public EPreLet(List assignments, Expression in) { + this.assignments = assignments; + this.in = in; + } + + @Override + public Expression resolve(final TranslationContext context) { + context.pushFrame(); + THashMap> functionDefinitions = + new THashMap>(); + ArrayList otherDefinitions = new ArrayList(); + final THashMap localVars = new THashMap(); + try { + for(LetStatement assign : assignments) { + LhsType lhsType = assign.pattern.getLhsType(); + if(!(assign.pattern instanceof EVar) && lhsType instanceof FunctionDefinitionLhs) { + String name = ((FunctionDefinitionLhs)lhsType).functionName; + ArrayList group = functionDefinitions.get(name); + if(group == null) { + group = new ArrayList(2); + functionDefinitions.put(name, group); + } + group.add(assign); + localVars.put(name, context.newVariable(name)); + } + else { + otherDefinitions.add(assign); + assign.pattern = assign.pattern.resolveAsPattern(context); + } + } + } catch (NotPatternException e) { + context.getErrorLog().log(e.getExpression().location, "Not a pattern."); + return new EError(); + } + + final ArrayList as = new ArrayList(functionDefinitions.size() + otherDefinitions.size()); + functionDefinitions.forEachEntry(new TObjectObjectProcedure>() { + @Override + public boolean execute(String name, ArrayList cases) { + as.add(new Assignment( + new EVariable(cases.size()==1 ? cases.get(0).pattern.location : location, localVars.get(name)), + context.translateCases(cases))); + return true; + } + }); + for(LetStatement stat : otherDefinitions) + as.add(new Assignment( + stat.pattern /* already resolved above */, + stat.value.resolve(context))); + Expression inExpr = in.resolve(context); + context.popFrame(); + + ELet result = new ELet(location, as.toArray(new Assignment[as.size()]), inExpr); + /*System.out.println("-----------------------------------------"); + System.out.println(this); + System.out.println("-----------------------------------------"); + System.out.println(result); + System.out.println("-----------------------------------------");*/ + return result; + } + + @Override + public void setLocationDeep(long loc) { + if(location == Locations.NO_LOCATION) { + location = loc; + for(LetStatement assignment : assignments) + assignment.setLocationDeep(loc); + in.setLocationDeep(loc); + } + } + + @Override + public Expression accept(ExpressionTransformer transformer) { + return transformer.transform(this); + } + + @Override + public int getSyntacticFunctionArity() { + return in.getSyntacticFunctionArity(); + } + +} diff --git a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/expressions/EPreRuleset.java b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/expressions/EPreRuleset.java index 74f24ebb8..41880a022 100644 --- a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/expressions/EPreRuleset.java +++ b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/expressions/EPreRuleset.java @@ -1,83 +1,88 @@ -package org.simantics.scl.compiler.elaboration.expressions; - -import org.simantics.scl.compiler.elaboration.contexts.TranslationContext; -import org.simantics.scl.compiler.elaboration.expressions.ERuleset.DatalogRule; -import org.simantics.scl.compiler.elaboration.expressions.block.RuleStatement; -import org.simantics.scl.compiler.elaboration.relations.LocalRelation; -import org.simantics.scl.compiler.errors.Locations; - -import gnu.trove.map.hash.THashMap; - -public class EPreRuleset extends ASTExpression { - - RuleStatement[] statements; - Expression in; - - public EPreRuleset(RuleStatement[] statements, Expression in) { - this.statements = statements; - this.in = in; - } - - @Override - public Expression resolve(TranslationContext context) { - THashMap relations = new THashMap(); - DatalogRule[] rules = new DatalogRule[statements.length]; - context.pushRelationFrame(); - try { - for(int i=0;i relations = new THashMap(); + DatalogRule[] rules = new DatalogRule[statements.length]; + context.pushRelationFrame(); + try { + for(int i=0;i allRefs, TIntHashSet refs) { - value.collectRefs(allRefs, refs); - } - - @Override - public void collectVars(TObjectIntHashMap allVars, - TIntHashSet vars) { - value.collectVars(allVars, vars); - } - - public Expression decomposeMatching() { - value = value.decomposeMatching(); - return this; - } - - @Override - protected void updateType() throws MatchException { - setType(Types.functionE(Types.canonical(parameter.type), - effect, value.getType())); - } - - @Override - public IVal toVal(Environment env, CodeWriter w) { - return lambdaToVal(env, w); - } - - @Override - public void collectFreeVariables(THashSet vars) { - value.collectFreeVariables(vars); - vars.remove(parameter); - } - - @Override - public Expression simplify(SimplificationContext context) { - value = value.simplify(context); - return this; - } - - @Override - public Expression resolve(TranslationContext context) { - value = value.resolve(context); - return this; - } - - @Override - public Expression replace(ReplaceContext context) { - Variable newParameter = parameter.copy(); - context.varMap.put(parameter, new EVariable(newParameter)); - ESimpleLambda result = new ESimpleLambda(getLocation(), - newParameter, - effect.replace(context.tvarMap), - value.replace(context)); - // not absolutely needed, but maybe good for performance - context.varMap.remove(parameter); - return result; - } - - public Type getLocalEffect() { - if(SCLCompilerConfiguration.DEBUG) - if(effect == null) - throw new InternalCompilerError(); - return effect; - } - - public void setEffect(Type effect) { - if(effect == null) - throw new InternalCompilerError(); - this.effect = effect; - } - - @Override - public IExpression toIExpression(ExpressionInterpretationContext context) { - // Find parameters of the whole function definition - ArrayList parameters = new ArrayList(2); - parameters.add(parameter); - Expression cur = value; - while(true) { - if(cur instanceof ESimpleLambda) { - ESimpleLambda lambda = (ESimpleLambda)cur; - parameters.add(lambda.parameter); - cur = lambda.value; - } - else if(cur instanceof ELambdaType) { - cur = ((ELambdaType)cur).value; - } - else - break; - - } - - // Free variables; - ExpressionInterpretationContext innerContext = context.createNewContext(); - THashSet freeVariables = cur.getFreeVariables(); - for(Variable parameter : parameters) - freeVariables.remove(parameter); - int i=0; - int[] inheritedVariableIds = new int[freeVariables.size()]; - for(Variable var : freeVariables) { - innerContext.push(var); - inheritedVariableIds[i++] = context.getVariableId(var); - } - - // Parameters - for(Variable parameter : parameters) - innerContext.push(parameter); - - // Construct lambda - IExpression body = cur.toIExpression(innerContext); - return new ILambda(inheritedVariableIds, - parameters.size(), - innerContext.getMaxVariableId(), - body); - } - - public Expression checkBasicType(TypingContext context, Type requiredType) { - MultiFunction mfun; - try { - mfun = Types.unifyFunction(requiredType, 1); - } catch (UnificationException e) { - context.getErrorLog().log(location, "Required type is <" + requiredType + "> which is incompatible with lambda."); - setType(Types.metaVar(Kinds.STAR)); - return this; - } - - effect = mfun.effect; - context.pushEffectUpperBound(location, mfun.effect); - parameter.setType(mfun.parameterTypes[0]); - value = value.checkType(context, mfun.returnType); - context.popEffectUpperBound(); - return this; - } - - @Override - public Expression inferType(TypingContext context) { - effect = Types.metaVar(Kinds.EFFECT); - context.pushEffectUpperBound(location, effect); - if(parameter.type == null) - parameter.setType(Types.metaVar(Kinds.STAR)); - value = value.checkType(context, Types.metaVar(Kinds.STAR)); - context.popEffectUpperBound(); - return this; - } - - @Override - public Expression decorate(ExpressionDecorator decorator) { - if(decorator.decorateSubstructure(this)) - value = value.decorate(decorator); - return decorator.decorate(this); - } - - @Override - public boolean isEffectful() { - return false; - } - - @Override - public void collectEffects(THashSet effects) { - } - - @Override - public void setLocationDeep(long loc) { - if(location == Locations.NO_LOCATION) { - location = loc; - value.setLocationDeep(loc); - } - } - - @Override - public void accept(ExpressionVisitor visitor) { - visitor.visit(this); - } - - public Expression getValue() { - return value; - } - - public Variable getParameter() { - return parameter; - } - - @Override - public void forVariables(VariableProcedure procedure) { - value.forVariables(procedure); - } - - @Override - public Expression accept(ExpressionTransformer transformer) { - return transformer.transform(this); - } - -} +package org.simantics.scl.compiler.elaboration.expressions; + +import java.util.ArrayList; + +import org.simantics.scl.compiler.common.exceptions.InternalCompilerError; +import org.simantics.scl.compiler.elaboration.contexts.ReplaceContext; +import org.simantics.scl.compiler.elaboration.contexts.SimplificationContext; +import org.simantics.scl.compiler.elaboration.contexts.TranslationContext; +import org.simantics.scl.compiler.elaboration.contexts.TypingContext; +import org.simantics.scl.compiler.environment.Environment; +import org.simantics.scl.compiler.errors.Locations; +import org.simantics.scl.compiler.internal.codegen.references.IVal; +import org.simantics.scl.compiler.internal.codegen.writer.CodeWriter; +import org.simantics.scl.compiler.internal.elaboration.utils.ExpressionDecorator; +import org.simantics.scl.compiler.internal.interpreted.IExpression; +import org.simantics.scl.compiler.internal.interpreted.ILambda; +import org.simantics.scl.compiler.top.ExpressionInterpretationContext; +import org.simantics.scl.compiler.top.SCLCompilerConfiguration; +import org.simantics.scl.compiler.types.Type; +import org.simantics.scl.compiler.types.Types; +import org.simantics.scl.compiler.types.exceptions.MatchException; +import org.simantics.scl.compiler.types.exceptions.UnificationException; +import org.simantics.scl.compiler.types.kinds.Kinds; +import org.simantics.scl.compiler.types.util.MultiFunction; + +import gnu.trove.map.hash.TObjectIntHashMap; +import gnu.trove.set.hash.THashSet; +import gnu.trove.set.hash.TIntHashSet; + +public class ESimpleLambda extends Expression { + public Variable parameter; + public Expression value; + public Type effect = Types.NO_EFFECTS; + + public ESimpleLambda(Variable parameter, Expression value) { + this.parameter = parameter; + this.value = value; + } + + public ESimpleLambda(Type effect, Variable parameter, Expression value) { + this.parameter = parameter; + this.value = value; + this.effect = effect; + } + + public ESimpleLambda(long loc, Variable parameter, Expression value) { + super(loc); + this.parameter = parameter; + this.value = value; + } + + public ESimpleLambda(long loc, Variable parameter, Type effect, Expression value) { + super(loc); + this.parameter = parameter; + this.value = value; + this.effect = effect; + } + + public void collectRefs(TObjectIntHashMap allRefs, TIntHashSet refs) { + value.collectRefs(allRefs, refs); + } + + @Override + public void collectVars(TObjectIntHashMap allVars, + TIntHashSet vars) { + value.collectVars(allVars, vars); + } + + public Expression decomposeMatching() { + value = value.decomposeMatching(); + return this; + } + + @Override + protected void updateType() throws MatchException { + setType(Types.functionE(Types.canonical(parameter.type), + effect, value.getType())); + } + + @Override + public IVal toVal(Environment env, CodeWriter w) { + return lambdaToVal(env, w); + } + + @Override + public void collectFreeVariables(THashSet vars) { + value.collectFreeVariables(vars); + vars.remove(parameter); + } + + @Override + public Expression simplify(SimplificationContext context) { + value = value.simplify(context); + return this; + } + + @Override + public Expression resolve(TranslationContext context) { + value = value.resolve(context); + return this; + } + + @Override + public Expression replace(ReplaceContext context) { + Variable newParameter = parameter.copy(); + context.varMap.put(parameter, new EVariable(newParameter)); + ESimpleLambda result = new ESimpleLambda(getLocation(), + newParameter, + effect.replace(context.tvarMap), + value.replace(context)); + // not absolutely needed, but maybe good for performance + context.varMap.remove(parameter); + return result; + } + + public Type getLocalEffect() { + if(SCLCompilerConfiguration.DEBUG) + if(effect == null) + throw new InternalCompilerError(); + return effect; + } + + public void setEffect(Type effect) { + if(effect == null) + throw new InternalCompilerError(); + this.effect = effect; + } + + @Override + public IExpression toIExpression(ExpressionInterpretationContext context) { + // Find parameters of the whole function definition + ArrayList parameters = new ArrayList(2); + parameters.add(parameter); + Expression cur = value; + while(true) { + if(cur instanceof ESimpleLambda) { + ESimpleLambda lambda = (ESimpleLambda)cur; + parameters.add(lambda.parameter); + cur = lambda.value; + } + else if(cur instanceof ELambdaType) { + cur = ((ELambdaType)cur).value; + } + else + break; + + } + + // Free variables; + ExpressionInterpretationContext innerContext = context.createNewContext(); + THashSet freeVariables = cur.getFreeVariables(); + for(Variable parameter : parameters) + freeVariables.remove(parameter); + int i=0; + int[] inheritedVariableIds = new int[freeVariables.size()]; + for(Variable var : freeVariables) { + innerContext.push(var); + inheritedVariableIds[i++] = context.getVariableId(var); + } + + // Parameters + for(Variable parameter : parameters) + innerContext.push(parameter); + + // Construct lambda + IExpression body = cur.toIExpression(innerContext); + return new ILambda(inheritedVariableIds, + parameters.size(), + innerContext.getMaxVariableId(), + body); + } + + public Expression checkBasicType(TypingContext context, Type requiredType) { + MultiFunction mfun; + try { + mfun = Types.unifyFunction(requiredType, 1); + } catch (UnificationException e) { + context.getErrorLog().log(location, "Required type is <" + requiredType + "> which is incompatible with lambda."); + setType(Types.metaVar(Kinds.STAR)); + return this; + } + + effect = mfun.effect; + context.pushEffectUpperBound(location, mfun.effect); + parameter.setType(mfun.parameterTypes[0]); + value = value.checkType(context, mfun.returnType); + context.popEffectUpperBound(); + return this; + } + + @Override + public Expression inferType(TypingContext context) { + effect = Types.metaVar(Kinds.EFFECT); + context.pushEffectUpperBound(location, effect); + if(parameter.type == null) + parameter.setType(Types.metaVar(Kinds.STAR)); + value = value.checkType(context, Types.metaVar(Kinds.STAR)); + context.popEffectUpperBound(); + return this; + } + + @Override + public Expression decorate(ExpressionDecorator decorator) { + if(decorator.decorateSubstructure(this)) + value = value.decorate(decorator); + return decorator.decorate(this); + } + + @Override + public boolean isEffectful() { + return false; + } + + @Override + public void collectEffects(THashSet effects) { + } + + @Override + public void setLocationDeep(long loc) { + if(location == Locations.NO_LOCATION) { + location = loc; + value.setLocationDeep(loc); + } + } + + @Override + public void accept(ExpressionVisitor visitor) { + visitor.visit(this); + } + + public Expression getValue() { + return value; + } + + public Variable getParameter() { + return parameter; + } + + @Override + public void forVariables(VariableProcedure procedure) { + value.forVariables(procedure); + } + + @Override + public Expression accept(ExpressionTransformer transformer) { + return transformer.transform(this); + } + + @Override + public int getSyntacticFunctionArity() { + return 1 + value.getSyntacticFunctionArity(); + } + +} diff --git a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/expressions/ESimpleLet.java b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/expressions/ESimpleLet.java index 8e73b2392..047d77a47 100755 --- a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/expressions/ESimpleLet.java +++ b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/expressions/ESimpleLet.java @@ -1,220 +1,224 @@ -package org.simantics.scl.compiler.elaboration.expressions; - -import org.simantics.scl.compiler.elaboration.contexts.ReplaceContext; -import org.simantics.scl.compiler.elaboration.contexts.SimplificationContext; -import org.simantics.scl.compiler.elaboration.contexts.TranslationContext; -import org.simantics.scl.compiler.elaboration.contexts.TypingContext; -import org.simantics.scl.compiler.environment.Environment; -import org.simantics.scl.compiler.errors.Locations; -import org.simantics.scl.compiler.internal.codegen.references.IVal; -import org.simantics.scl.compiler.internal.codegen.writer.CodeWriter; -import org.simantics.scl.compiler.internal.elaboration.utils.ExpressionDecorator; -import org.simantics.scl.compiler.internal.interpreted.IExpression; -import org.simantics.scl.compiler.internal.interpreted.ILet; -import org.simantics.scl.compiler.internal.interpreted.ISeq; -import org.simantics.scl.compiler.top.ExpressionInterpretationContext; -import org.simantics.scl.compiler.types.Type; -import org.simantics.scl.compiler.types.exceptions.MatchException; - -import gnu.trove.map.hash.TObjectIntHashMap; -import gnu.trove.set.hash.THashSet; -import gnu.trove.set.hash.TIntHashSet; - -public class ESimpleLet extends Expression { - Variable variable; // may be null - Expression value; - Expression in; - - public ESimpleLet(Variable variable, Expression value, Expression in) { - if(value == null) - throw new NullPointerException(); - if(in == null) - throw new NullPointerException(); - this.variable = variable; - this.value = value; - this.in = in; - } - - public ESimpleLet(long loc, Variable variable, Expression value, Expression in) { - super(loc); - if(value == null) - throw new NullPointerException(); - if(in == null) - throw new NullPointerException(); - this.variable = variable; - this.value = value; - this.in = in; - } - - public void collectRefs(TObjectIntHashMap allRefs, TIntHashSet refs) { - value.collectRefs(allRefs, refs); - in.collectRefs(allRefs, refs); - } - - @Override - public void collectVars(TObjectIntHashMap allVars, - TIntHashSet vars) { - value.collectVars(allVars, vars); - in.collectVars(allVars, vars); - } - - @Override - protected void updateType() throws MatchException { - setType(in.getType()); - } - - @Override - public IVal toVal(Environment env, CodeWriter w) { - IVal valueVal = value.toVal(env, w); - if(variable != null) - variable.setVal(valueVal); - return in.toVal(env, w); - } - - @Override - public void collectFreeVariables(THashSet vars) { - value.collectFreeVariables(vars); - in.collectFreeVariables(vars); - vars.remove(variable); - } - - @Override - public Expression simplify(SimplificationContext context) { - value = value.simplify(context); - if(value instanceof EConstant || value instanceof ELiteral) { - context.addInlinedVariable(variable, value); - return in.simplify(context); - } - in = in.simplify(context); - return this; - } - - @Override - public Expression resolve(TranslationContext context) { - value = value.resolve(context); - in = in.resolve(context); - return this; - } - - @Override - public Expression replace(ReplaceContext context) { - if(variable == null) - return new ESimpleLet(location, - null, - value.replace(context), - in.replace(context)); - else { - Variable newVariable = variable.copy(); - context.varMap.put(variable, new EVariable(newVariable)); - ESimpleLet result = new ESimpleLet(location, newVariable, - value.replace(context), - in.replace(context)); - context.varMap.remove(variable); - return result; - } - } - - @Override - public void setLocationDeep(long loc) { - if(location == Locations.NO_LOCATION) { - location = loc; - value.setLocationDeep(loc); - in.setLocationDeep(loc); - } - } - - @Override - public IExpression toIExpression(ExpressionInterpretationContext context) { - if(variable == null) { - IExpression valueI = value.toIExpression(context); - IExpression inI = in.toIExpression(context); - return new ISeq(valueI, inI); - } - else { - IExpression valueI = value.toIExpression(context); - int variableId = context.push(variable); - IExpression inI = in.toIExpression(context); - context.pop(variable); - return new ILet(variableId, valueI, inI); - } - } - - private void checkBinding(TypingContext context) { - if(variable == null) - value = value.checkIgnoredType(context); - else if(variable.getType() == null) { - value = value.inferType(context); - variable.setType(value.getType()); - } - else - value = value.checkType(context, variable.type); - /*else { - if(variable.getType() == null) - variable.setType(Types.metaVar(Kinds.STAR)); - value = value.checkType(context, variable.type); - }*/ - } - - @Override - public Expression inferType(TypingContext context) { - checkBinding(context); - in = in.inferType(context); - return this; - } - - @Override - public Expression checkBasicType(TypingContext context, Type requiredType) { - checkBinding(context); - in = in.checkType(context, requiredType); - return this; - } - - @Override - public Expression checkIgnoredType(TypingContext context) { - checkBinding(context); - in = in.checkIgnoredType(context); - return this; - } - - @Override - public Expression decorate(ExpressionDecorator decorator) { - value = value.decorate(decorator); - in = in.decorate(decorator); - return decorator.decorate(this); - } - - @Override - public void collectEffects(THashSet effects) { - value.collectEffects(effects); - in.collectEffects(effects); - } - - @Override - public void accept(ExpressionVisitor visitor) { - visitor.visit(this); - } - - public Expression getValue() { - return value; - } - - public Variable getVariable() { - return variable; - } - - public Expression getIn() { - return in; - } - - @Override - public void forVariables(VariableProcedure procedure) { - value.forVariables(procedure); - in.forVariables(procedure); - } - - @Override - public Expression accept(ExpressionTransformer transformer) { - return transformer.transform(this); - } - -} +package org.simantics.scl.compiler.elaboration.expressions; + +import org.simantics.scl.compiler.elaboration.contexts.ReplaceContext; +import org.simantics.scl.compiler.elaboration.contexts.SimplificationContext; +import org.simantics.scl.compiler.elaboration.contexts.TranslationContext; +import org.simantics.scl.compiler.elaboration.contexts.TypingContext; +import org.simantics.scl.compiler.environment.Environment; +import org.simantics.scl.compiler.errors.Locations; +import org.simantics.scl.compiler.internal.codegen.references.IVal; +import org.simantics.scl.compiler.internal.codegen.writer.CodeWriter; +import org.simantics.scl.compiler.internal.elaboration.utils.ExpressionDecorator; +import org.simantics.scl.compiler.internal.interpreted.IExpression; +import org.simantics.scl.compiler.internal.interpreted.ILet; +import org.simantics.scl.compiler.internal.interpreted.ISeq; +import org.simantics.scl.compiler.top.ExpressionInterpretationContext; +import org.simantics.scl.compiler.types.Type; +import org.simantics.scl.compiler.types.exceptions.MatchException; + +import gnu.trove.map.hash.TObjectIntHashMap; +import gnu.trove.set.hash.THashSet; +import gnu.trove.set.hash.TIntHashSet; + +public class ESimpleLet extends Expression { + Variable variable; // may be null + Expression value; + Expression in; + + public ESimpleLet(Variable variable, Expression value, Expression in) { + if(value == null) + throw new NullPointerException(); + if(in == null) + throw new NullPointerException(); + this.variable = variable; + this.value = value; + this.in = in; + } + + public ESimpleLet(long loc, Variable variable, Expression value, Expression in) { + super(loc); + if(value == null) + throw new NullPointerException(); + if(in == null) + throw new NullPointerException(); + this.variable = variable; + this.value = value; + this.in = in; + } + + public void collectRefs(TObjectIntHashMap allRefs, TIntHashSet refs) { + value.collectRefs(allRefs, refs); + in.collectRefs(allRefs, refs); + } + + @Override + public void collectVars(TObjectIntHashMap allVars, + TIntHashSet vars) { + value.collectVars(allVars, vars); + in.collectVars(allVars, vars); + } + + @Override + protected void updateType() throws MatchException { + setType(in.getType()); + } + + @Override + public IVal toVal(Environment env, CodeWriter w) { + IVal valueVal = value.toVal(env, w); + if(variable != null) + variable.setVal(valueVal); + return in.toVal(env, w); + } + + @Override + public void collectFreeVariables(THashSet vars) { + value.collectFreeVariables(vars); + in.collectFreeVariables(vars); + vars.remove(variable); + } + + @Override + public Expression simplify(SimplificationContext context) { + value = value.simplify(context); + if(value instanceof EConstant || value instanceof ELiteral) { + context.addInlinedVariable(variable, value); + return in.simplify(context); + } + in = in.simplify(context); + return this; + } + + @Override + public Expression resolve(TranslationContext context) { + value = value.resolve(context); + in = in.resolve(context); + return this; + } + + @Override + public Expression replace(ReplaceContext context) { + if(variable == null) + return new ESimpleLet(location, + null, + value.replace(context), + in.replace(context)); + else { + Variable newVariable = variable.copy(); + context.varMap.put(variable, new EVariable(newVariable)); + ESimpleLet result = new ESimpleLet(location, newVariable, + value.replace(context), + in.replace(context)); + context.varMap.remove(variable); + return result; + } + } + + @Override + public void setLocationDeep(long loc) { + if(location == Locations.NO_LOCATION) { + location = loc; + value.setLocationDeep(loc); + in.setLocationDeep(loc); + } + } + + @Override + public IExpression toIExpression(ExpressionInterpretationContext context) { + if(variable == null) { + IExpression valueI = value.toIExpression(context); + IExpression inI = in.toIExpression(context); + return new ISeq(valueI, inI); + } + else { + IExpression valueI = value.toIExpression(context); + int variableId = context.push(variable); + IExpression inI = in.toIExpression(context); + context.pop(variable); + return new ILet(variableId, valueI, inI); + } + } + + private void checkBinding(TypingContext context) { + if(variable == null) + value = value.checkIgnoredType(context); + else if(variable.getType() == null) { + value = value.inferType(context); + variable.setType(value.getType()); + } + else + value = value.checkType(context, variable.type); + /*else { + if(variable.getType() == null) + variable.setType(Types.metaVar(Kinds.STAR)); + value = value.checkType(context, variable.type); + }*/ + } + + @Override + public Expression inferType(TypingContext context) { + checkBinding(context); + in = in.inferType(context); + return this; + } + + @Override + public Expression checkBasicType(TypingContext context, Type requiredType) { + checkBinding(context); + in = in.checkType(context, requiredType); + return this; + } + + @Override + public Expression checkIgnoredType(TypingContext context) { + checkBinding(context); + in = in.checkIgnoredType(context); + return this; + } + + @Override + public Expression decorate(ExpressionDecorator decorator) { + value = value.decorate(decorator); + in = in.decorate(decorator); + return decorator.decorate(this); + } + + @Override + public void collectEffects(THashSet effects) { + value.collectEffects(effects); + in.collectEffects(effects); + } + + @Override + public void accept(ExpressionVisitor visitor) { + visitor.visit(this); + } + + public Expression getValue() { + return value; + } + + public Variable getVariable() { + return variable; + } + + public Expression getIn() { + return in; + } + + @Override + public void forVariables(VariableProcedure procedure) { + value.forVariables(procedure); + in.forVariables(procedure); + } + + @Override + public Expression accept(ExpressionTransformer transformer) { + return transformer.transform(this); + } + + @Override + public int getSyntacticFunctionArity() { + return in.getSyntacticFunctionArity(); + } +} diff --git a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/expressions/EVar.java b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/expressions/EVar.java index 5ad1e3126..f1c3e31e0 100755 --- a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/expressions/EVar.java +++ b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/expressions/EVar.java @@ -1,82 +1,82 @@ -package org.simantics.scl.compiler.elaboration.expressions; - -import java.util.ArrayList; - -import org.simantics.scl.compiler.elaboration.contexts.TranslationContext; -import org.simantics.scl.compiler.elaboration.errors.NotPatternException; -import org.simantics.scl.compiler.elaboration.expressions.lhstype.FunctionDefinitionLhs; -import org.simantics.scl.compiler.elaboration.expressions.lhstype.LhsType; -import org.simantics.scl.compiler.elaboration.expressions.lhstype.PatternMatchingLhs; -import org.simantics.scl.compiler.errors.Locations; - -public class EVar extends ASTExpression { - public final String name; - - public EVar(long location, String name) { - this.location = location; - this.name = name; - } - - public EVar(String name) { - this(Locations.NO_LOCATION, name); - } - - @Override - public EVar getPatternHead() { - return this; - } - - @Override - public LhsType getLhsType() throws NotPatternException { - if(TranslationContext.isConstructorName(name)) - return new PatternMatchingLhs(); - else - return new FunctionDefinitionLhs(name); - } - - @Override - protected void collectVariableNames(PatternMatchingLhs lhsType) - throws NotPatternException { - if(!TranslationContext.isConstructorName(name)) - lhsType.variableNames.add(name); - } - - @Override - public Expression resolve(TranslationContext context) { - return context.resolveExpression(location, name); - } - - @Override - public void getParameters(TranslationContext translationContext, - ArrayList parameters) { - } - - @Override - public Expression resolveAsPattern(TranslationContext context) { - return context.resolvePattern(this); - } - - @Override - public int getFunctionDefinitionArity() throws NotPatternException { - if(TranslationContext.isConstructorName(name)) - throw new NotPatternException(this); - else - return 0; - } - - @Override - public boolean isConstructorApplication() { - return TranslationContext.isConstructorName(name); - } - - @Override - public void setLocationDeep(long loc) { - if(location == Locations.NO_LOCATION) - location = loc; - } - - @Override - public Expression accept(ExpressionTransformer transformer) { - return transformer.transform(this); - } -} +package org.simantics.scl.compiler.elaboration.expressions; + +import java.util.ArrayList; + +import org.simantics.scl.compiler.elaboration.contexts.TranslationContext; +import org.simantics.scl.compiler.elaboration.errors.NotPatternException; +import org.simantics.scl.compiler.elaboration.expressions.lhstype.FunctionDefinitionLhs; +import org.simantics.scl.compiler.elaboration.expressions.lhstype.LhsType; +import org.simantics.scl.compiler.elaboration.expressions.lhstype.PatternMatchingLhs; +import org.simantics.scl.compiler.errors.Locations; + +public class EVar extends ASTExpression { + public final String name; + + public EVar(long location, String name) { + this.location = location; + this.name = name; + } + + public EVar(String name) { + this(Locations.NO_LOCATION, name); + } + + @Override + public EVar getPatternHead() { + return this; + } + + @Override + public LhsType getLhsType() throws NotPatternException { + if(TranslationContext.isConstructorName(name)) + return new PatternMatchingLhs(); + else + return new FunctionDefinitionLhs(name); + } + + @Override + protected void collectVariableNames(PatternMatchingLhs lhsType) + throws NotPatternException { + if(!TranslationContext.isConstructorName(name)) + lhsType.variableNames.add(name); + } + + @Override + public Expression resolve(TranslationContext context) { + return context.resolveExpression(location, name); + } + + @Override + public void getParameters(TranslationContext translationContext, + ArrayList parameters) { + } + + @Override + public Expression resolveAsPattern(TranslationContext context) { + return context.resolvePattern(this); + } + + @Override + public int getFunctionDefinitionPatternArity() throws NotPatternException { + if(TranslationContext.isConstructorName(name)) + throw new NotPatternException(this); + else + return 0; + } + + @Override + public boolean isConstructorApplication() { + return TranslationContext.isConstructorName(name); + } + + @Override + public void setLocationDeep(long loc) { + if(location == Locations.NO_LOCATION) + location = loc; + } + + @Override + public Expression accept(ExpressionTransformer transformer) { + return transformer.transform(this); + } +} diff --git a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/expressions/Expression.java b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/expressions/Expression.java index 9a5fefb9f..8adf33936 100755 --- a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/expressions/Expression.java +++ b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/expressions/Expression.java @@ -1,386 +1,395 @@ -package org.simantics.scl.compiler.elaboration.expressions; - -import java.util.ArrayList; - -import org.simantics.scl.compiler.common.exceptions.InternalCompilerError; -import org.simantics.scl.compiler.common.precedence.Precedence; -import org.simantics.scl.compiler.constants.NoRepConstant; -import org.simantics.scl.compiler.elaboration.contexts.EnvironmentalContext; -import org.simantics.scl.compiler.elaboration.contexts.ReplaceContext; -import org.simantics.scl.compiler.elaboration.contexts.SimplificationContext; -import org.simantics.scl.compiler.elaboration.contexts.TranslationContext; -import org.simantics.scl.compiler.elaboration.contexts.TypingContext; -import org.simantics.scl.compiler.elaboration.errors.NotPatternException; -import org.simantics.scl.compiler.elaboration.expressions.lhstype.LhsType; -import org.simantics.scl.compiler.elaboration.expressions.lhstype.PatternMatchingLhs; -import org.simantics.scl.compiler.elaboration.expressions.printing.ExpressionToStringVisitor; -import org.simantics.scl.compiler.elaboration.query.QAtom; -import org.simantics.scl.compiler.elaboration.relations.SCLRelation; -import org.simantics.scl.compiler.environment.Environment; -import org.simantics.scl.compiler.internal.codegen.references.IVal; -import org.simantics.scl.compiler.internal.codegen.writer.CodeWriter; -import org.simantics.scl.compiler.internal.elaboration.decomposed.DecomposedExpression; -import org.simantics.scl.compiler.internal.elaboration.utils.ExpressionDecorator; -import org.simantics.scl.compiler.internal.interpreted.IExpression; -import org.simantics.scl.compiler.internal.parsing.Symbol; -import org.simantics.scl.compiler.top.ExpressionInterpretationContext; -import org.simantics.scl.compiler.types.TForAll; -import org.simantics.scl.compiler.types.TFun; -import org.simantics.scl.compiler.types.TPred; -import org.simantics.scl.compiler.types.TVar; -import org.simantics.scl.compiler.types.Type; -import org.simantics.scl.compiler.types.Types; -import org.simantics.scl.compiler.types.exceptions.MatchException; -import org.simantics.scl.compiler.types.kinds.Kinds; -import org.simantics.scl.compiler.types.util.Typed; - -import gnu.trove.map.hash.TObjectIntHashMap; -import gnu.trove.set.hash.THashSet; -import gnu.trove.set.hash.TIntHashSet; - -public abstract class Expression extends Symbol implements Typed { - public static final Expression[] EMPTY_ARRAY = new Expression[0]; - - transient - private Type type; - - public Expression() { - } - - public Expression(long loc) { - this.location = loc; - } - - @Override - public Type getType() { - if(type == null) { - try { - updateType(); - } catch (MatchException e) { - throw new InternalCompilerError(e); - } - if(type == null) - throw new InternalCompilerError(getClass().getSimpleName() + - ".updateType couldn't compute its type."); - } - return type; - } - - public void setType(Type type) { - if(type == null) - throw new NullPointerException(); - this.type = type; - } - - /** - * Infers the type of the expression without any context. Adds type - * applications and lambdas if needed. - */ - public Expression inferType(TypingContext context) { - return checkBasicType(context, Types.metaVar(Kinds.STAR)); - } - - public Expression checkBasicType(TypingContext context, Type requiredType) { - return context.subsume(inferType(context), requiredType); - } - - protected Expression applyPUnit(EnvironmentalContext context) { - Type type = Types.canonical(getType()); - if(type instanceof TFun) { - TFun fun = (TFun)type; - if(fun.getCanonicalDomain() == Types.PUNIT) { - EApply result = new EApply(location, this, new ELiteral(NoRepConstant.PUNIT)); - result.effect = fun.getCanonicalEffect(); - return result; - } - } - return this; - } - - public Expression checkIgnoredType(TypingContext context) { - Expression expression = inferType(context); - if(Types.canonical(expression.getType()) != Types.UNIT) - expression = new ESimpleLet(location, null, expression, new ELiteral(NoRepConstant.PUNIT)); - return expression; - } - - /** - * Checks the type of the expression against the given type. Adds type - * applications and lambdas if needed. - */ - public final Expression checkType(TypingContext context, Type requiredType) { - //System.out.println("checkType: " + this + " :: " + requiredType); - if(!context.isInPattern()) { - requiredType = Types.canonical(requiredType); - if(requiredType instanceof TForAll) { - TForAll forAll = (TForAll)requiredType; - TVar var = forAll.var; - TVar newVar = Types.var(var.getKind()); - requiredType = Types.canonical(forAll.type).replace(var, newVar); - return new ELambdaType(new TVar[] {newVar}, checkType(context, requiredType)); - } - while(requiredType instanceof TFun) { - TFun fun = (TFun)requiredType; - if(fun.domain instanceof TPred) { // No need to canonicalize - ArrayList constraints = new ArrayList(2); - while(true) { - constraints.add(new Variable("constraint", fun.domain)); - requiredType = Types.canonical(fun.range); - if(!(requiredType instanceof TFun)) - break; - fun = (TFun)requiredType; - if(!(fun.domain instanceof TPred)) - break; - } - context.pushConstraintFrame(constraints.toArray(new Variable[constraints.size()])); - Expression expression = checkType(context, requiredType); - context.popConstraintFrame(); - for(int i=constraints.size()-1;i>=0;--i) - expression = new ESimpleLambda(constraints.get(i), expression); - return expression; - } - else if(fun.domain == Types.PUNIT) { - context.pushEffectUpperBound(location, fun.effect); - Expression expr = checkType(context, fun.range); - context.popEffectUpperBound(); - - // Wrap - Variable var = new Variable("punit", Types.PUNIT); - return new ESimpleLambda(location, var, fun.effect, expr); - } - else - break; - } - } - return checkBasicType(context, requiredType); - } - - public abstract void collectRefs(TObjectIntHashMap allRefs, TIntHashSet refs); - public abstract void collectVars(TObjectIntHashMap allVars, TIntHashSet vars); - public abstract void forVariables(VariableProcedure procedure); - - public Expression decomposeMatching() { - return this; - } - - public String toString() { - StringBuilder b = new StringBuilder(); - ExpressionToStringVisitor visitor = new ExpressionToStringVisitor(b); - accept(visitor); - return b.toString(); - } - - protected abstract void updateType() throws MatchException; - - public static class TypeValidationException extends Exception { - private static final long serialVersionUID = 3181298127162041248L; - - long loc; - - public TypeValidationException(long loc) { - this.loc = loc; - } - - public long getLoc() { - return loc; - } - - public TypeValidationException(long loc, Throwable cause) { - super(cause); - this.loc = loc; - } - } - - public static void assertEquals(long loc, Type a, Type b) throws TypeValidationException { - if(!Types.equals(a, b)) - throw new TypeValidationException(loc); - } - - public abstract IVal toVal(Environment env, CodeWriter w); - - public Expression closure(TVar ... vars) { - if(vars.length == 0) - return this; - return new ELambdaType(vars, this); - } - - public abstract void collectFreeVariables(THashSet vars); - - public Expression simplify(SimplificationContext context) { - System.out.println("#############################"); - System.out.println(this); - throw new InternalCompilerError(location, getClass().getSimpleName() + " does not support simplify method."); - } - - public abstract Expression resolve(TranslationContext context); - - /** - * Returns head of the pattern. - */ - public EVar getPatternHead() throws NotPatternException { - throw new NotPatternException(this); - } - - public LhsType getLhsType() throws NotPatternException { - throw new NotPatternException(this); - } - - protected void collectVariableNames(PatternMatchingLhs lhsType) throws NotPatternException { - throw new NotPatternException(this); - } - - public void getParameters(TranslationContext translationContext, - ArrayList parameters) { - throw new InternalCompilerError("Class " + getClass().getSimpleName() + " does not support getParameters."); - } - - public Expression resolveAsPattern(TranslationContext context) { - context.getErrorLog().log(location, "Pattern was expected here."); - return new EError(); - } - - public void removeFreeVariables(THashSet vars) { - throw new InternalCompilerError(getClass().getSimpleName() + " is not a pattern."); - } - - public Expression checkTypeAsPattern(TypingContext context, Type requiredType) { - if(context.isInPattern()) - throw new InternalCompilerError("Already in a pattern."); - context.setInPattern(true); - Expression expression = checkType(context, requiredType); - context.setInPattern(false); - return expression; - } - - public THashSet getFreeVariables() { - THashSet result = new THashSet(); - collectFreeVariables(result); - return result; - } - - public static Expression[] concat(Expression[] a, Expression[] b) { - if(a.length == 0) - return b; - if(b.length == 0) - return a; - Expression[] result = new Expression[a.length + b.length]; - for(int i=0;i effects); - - public Type getEffect() { - THashSet effects = new THashSet(); - collectEffects(effects); - return Types.union(effects.toArray(new Type[effects.size()])); - } - - public abstract void accept(ExpressionVisitor visitor); - - public void collectRelationRefs( - final TObjectIntHashMap allRefs, final TIntHashSet refs) { - accept(new StandardExpressionVisitor() { - @Override - public void visit(QAtom query) { - int id = allRefs.get(query.relation); - if(id >= 0) - refs.add(id); - } - }); - } - - public boolean isFunctionDefinitionLhs() { - return false; - } - - public Precedence getPrecedence() { - return Precedence.DEFAULT; - } - - public boolean isPattern(int arity) { - return false; - } - - public abstract Expression accept(ExpressionTransformer transformer); - - // TODO implement for all expressions - public boolean equalsExpression(Expression expression) { - return false; - } -} +package org.simantics.scl.compiler.elaboration.expressions; + +import java.util.ArrayList; + +import org.simantics.scl.compiler.common.exceptions.InternalCompilerError; +import org.simantics.scl.compiler.common.precedence.Precedence; +import org.simantics.scl.compiler.constants.NoRepConstant; +import org.simantics.scl.compiler.elaboration.contexts.EnvironmentalContext; +import org.simantics.scl.compiler.elaboration.contexts.ReplaceContext; +import org.simantics.scl.compiler.elaboration.contexts.SimplificationContext; +import org.simantics.scl.compiler.elaboration.contexts.TranslationContext; +import org.simantics.scl.compiler.elaboration.contexts.TypingContext; +import org.simantics.scl.compiler.elaboration.errors.NotPatternException; +import org.simantics.scl.compiler.elaboration.expressions.lhstype.LhsType; +import org.simantics.scl.compiler.elaboration.expressions.lhstype.PatternMatchingLhs; +import org.simantics.scl.compiler.elaboration.expressions.printing.ExpressionToStringVisitor; +import org.simantics.scl.compiler.elaboration.query.QAtom; +import org.simantics.scl.compiler.elaboration.relations.SCLRelation; +import org.simantics.scl.compiler.environment.Environment; +import org.simantics.scl.compiler.internal.codegen.references.IVal; +import org.simantics.scl.compiler.internal.codegen.writer.CodeWriter; +import org.simantics.scl.compiler.internal.elaboration.decomposed.DecomposedExpression; +import org.simantics.scl.compiler.internal.elaboration.utils.ExpressionDecorator; +import org.simantics.scl.compiler.internal.interpreted.IExpression; +import org.simantics.scl.compiler.internal.parsing.Symbol; +import org.simantics.scl.compiler.top.ExpressionInterpretationContext; +import org.simantics.scl.compiler.types.TForAll; +import org.simantics.scl.compiler.types.TFun; +import org.simantics.scl.compiler.types.TPred; +import org.simantics.scl.compiler.types.TVar; +import org.simantics.scl.compiler.types.Type; +import org.simantics.scl.compiler.types.Types; +import org.simantics.scl.compiler.types.exceptions.MatchException; +import org.simantics.scl.compiler.types.kinds.Kinds; +import org.simantics.scl.compiler.types.util.Typed; + +import gnu.trove.map.hash.TObjectIntHashMap; +import gnu.trove.set.hash.THashSet; +import gnu.trove.set.hash.TIntHashSet; + +public abstract class Expression extends Symbol implements Typed { + public static final Expression[] EMPTY_ARRAY = new Expression[0]; + + transient + private Type type; + + public Expression() { + } + + public Expression(long loc) { + this.location = loc; + } + + @Override + public Type getType() { + if(type == null) { + try { + updateType(); + } catch (MatchException e) { + throw new InternalCompilerError(e); + } + if(type == null) + throw new InternalCompilerError(getClass().getSimpleName() + + ".updateType couldn't compute its type."); + } + return type; + } + + public void setType(Type type) { + if(type == null) + throw new NullPointerException(); + this.type = type; + } + + /** + * Infers the type of the expression without any context. Adds type + * applications and lambdas if needed. + */ + public Expression inferType(TypingContext context) { + return checkBasicType(context, Types.metaVar(Kinds.STAR)); + } + + public Expression checkBasicType(TypingContext context, Type requiredType) { + return context.subsume(inferType(context), requiredType); + } + + protected Expression applyPUnit(EnvironmentalContext context) { + Type type = Types.canonical(getType()); + if(type instanceof TFun) { + TFun fun = (TFun)type; + if(fun.getCanonicalDomain() == Types.PUNIT) { + EApply result = new EApply(location, this, new ELiteral(NoRepConstant.PUNIT)); + result.effect = fun.getCanonicalEffect(); + return result; + } + } + return this; + } + + public Expression checkIgnoredType(TypingContext context) { + Expression expression = inferType(context); + if(Types.canonical(expression.getType()) != Types.UNIT) + expression = new ESimpleLet(location, null, expression, new ELiteral(NoRepConstant.PUNIT)); + return expression; + } + + /** + * Checks the type of the expression against the given type. Adds type + * applications and lambdas if needed. + */ + public final Expression checkType(TypingContext context, Type requiredType) { + //System.out.println("checkType: " + this + " :: " + requiredType); + if(!context.isInPattern()) { + requiredType = Types.canonical(requiredType); + if(requiredType instanceof TForAll) { + TForAll forAll = (TForAll)requiredType; + TVar var = forAll.var; + TVar newVar = Types.var(var.getKind()); + requiredType = Types.canonical(forAll.type).replace(var, newVar); + return new ELambdaType(new TVar[] {newVar}, checkType(context, requiredType)); + } + while(requiredType instanceof TFun) { + TFun fun = (TFun)requiredType; + if(fun.domain instanceof TPred) { // No need to canonicalize + ArrayList constraints = new ArrayList(2); + while(true) { + constraints.add(new Variable("constraint", fun.domain)); + requiredType = Types.canonical(fun.range); + if(!(requiredType instanceof TFun)) + break; + fun = (TFun)requiredType; + if(!(fun.domain instanceof TPred)) + break; + } + context.pushConstraintFrame(constraints.toArray(new Variable[constraints.size()])); + Expression expression = checkType(context, requiredType); + context.popConstraintFrame(); + for(int i=constraints.size()-1;i>=0;--i) + expression = new ESimpleLambda(constraints.get(i), expression); + return expression; + } + else if(fun.domain == Types.PUNIT) { + context.pushEffectUpperBound(location, fun.effect); + Expression expr = checkType(context, fun.range); + context.popEffectUpperBound(); + + // Wrap + Variable var = new Variable("punit", Types.PUNIT); + return new ESimpleLambda(location, var, fun.effect, expr); + } + else + break; + } + } + return checkBasicType(context, requiredType); + } + + public abstract void collectRefs(TObjectIntHashMap allRefs, TIntHashSet refs); + public abstract void collectVars(TObjectIntHashMap allVars, TIntHashSet vars); + public abstract void forVariables(VariableProcedure procedure); + + public Expression decomposeMatching() { + return this; + } + + public String toString() { + StringBuilder b = new StringBuilder(); + ExpressionToStringVisitor visitor = new ExpressionToStringVisitor(b); + accept(visitor); + return b.toString(); + } + + protected abstract void updateType() throws MatchException; + + public static class TypeValidationException extends Exception { + private static final long serialVersionUID = 3181298127162041248L; + + long loc; + + public TypeValidationException(long loc) { + this.loc = loc; + } + + public long getLoc() { + return loc; + } + + public TypeValidationException(long loc, Throwable cause) { + super(cause); + this.loc = loc; + } + } + + public static void assertEquals(long loc, Type a, Type b) throws TypeValidationException { + if(!Types.equals(a, b)) + throw new TypeValidationException(loc); + } + + public abstract IVal toVal(Environment env, CodeWriter w); + + public Expression closure(TVar ... vars) { + if(vars.length == 0) + return this; + return new ELambdaType(vars, this); + } + + public abstract void collectFreeVariables(THashSet vars); + + public Expression simplify(SimplificationContext context) { + System.out.println("#############################"); + System.out.println(this); + throw new InternalCompilerError(location, getClass().getSimpleName() + " does not support simplify method."); + } + + public abstract Expression resolve(TranslationContext context); + + /** + * Returns head of the pattern. + */ + public EVar getPatternHead() throws NotPatternException { + throw new NotPatternException(this); + } + + public LhsType getLhsType() throws NotPatternException { + throw new NotPatternException(this); + } + + protected void collectVariableNames(PatternMatchingLhs lhsType) throws NotPatternException { + throw new NotPatternException(this); + } + + public void getParameters(TranslationContext translationContext, + ArrayList parameters) { + throw new InternalCompilerError("Class " + getClass().getSimpleName() + " does not support getParameters."); + } + + public Expression resolveAsPattern(TranslationContext context) { + context.getErrorLog().log(location, "Pattern was expected here."); + return new EError(); + } + + public void removeFreeVariables(THashSet vars) { + throw new InternalCompilerError(getClass().getSimpleName() + " is not a pattern."); + } + + public Expression checkTypeAsPattern(TypingContext context, Type requiredType) { + if(context.isInPattern()) + throw new InternalCompilerError("Already in a pattern."); + context.setInPattern(true); + Expression expression = checkType(context, requiredType); + context.setInPattern(false); + return expression; + } + + public THashSet getFreeVariables() { + THashSet result = new THashSet(); + collectFreeVariables(result); + return result; + } + + public static Expression[] concat(Expression[] a, Expression[] b) { + if(a.length == 0) + return b; + if(b.length == 0) + return a; + Expression[] result = new Expression[a.length + b.length]; + for(int i=0;i effects); + + public Type getEffect() { + THashSet effects = new THashSet(); + collectEffects(effects); + return Types.union(effects.toArray(new Type[effects.size()])); + } + + public abstract void accept(ExpressionVisitor visitor); + + public void collectRelationRefs( + final TObjectIntHashMap allRefs, final TIntHashSet refs) { + accept(new StandardExpressionVisitor() { + @Override + public void visit(QAtom query) { + int id = allRefs.get(query.relation); + if(id >= 0) + refs.add(id); + } + }); + } + + public boolean isFunctionDefinitionLhs() { + return false; + } + + public Precedence getPrecedence() { + return Precedence.DEFAULT; + } + + public boolean isPattern(int arity) { + return false; + } + + public abstract Expression accept(ExpressionTransformer transformer); + + // TODO implement for all expressions + public boolean equalsExpression(Expression expression) { + return false; + } + + /** + * This method returns a lower bound for the function arity of the value this expression defines. + * The lower bound is calculated purely looking the syntax of the expression, not the + * types of the constants and variables the expression refers to. + */ + public int getSyntacticFunctionArity() { + return 0; + } +} diff --git a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/expressions/GuardedExpressionGroup.java b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/expressions/GuardedExpressionGroup.java index 48f72eeac..890d11f8c 100755 --- a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/expressions/GuardedExpressionGroup.java +++ b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/expressions/GuardedExpressionGroup.java @@ -1,181 +1,186 @@ -package org.simantics.scl.compiler.elaboration.expressions; - -import org.simantics.scl.compiler.elaboration.contexts.ReplaceContext; -import org.simantics.scl.compiler.elaboration.contexts.SimplificationContext; -import org.simantics.scl.compiler.elaboration.contexts.TranslationContext; -import org.simantics.scl.compiler.elaboration.contexts.TypingContext; -import org.simantics.scl.compiler.environment.Environment; -import org.simantics.scl.compiler.errors.Locations; -import org.simantics.scl.compiler.internal.codegen.continuations.ICont; -import org.simantics.scl.compiler.internal.codegen.references.IVal; -import org.simantics.scl.compiler.internal.codegen.ssa.exits.Throw; -import org.simantics.scl.compiler.internal.codegen.writer.CodeWriter; -import org.simantics.scl.compiler.internal.elaboration.utils.ExpressionDecorator; -import org.simantics.scl.compiler.types.Type; -import org.simantics.scl.compiler.types.Types; -import org.simantics.scl.compiler.types.exceptions.MatchException; - -import gnu.trove.map.hash.TObjectIntHashMap; -import gnu.trove.set.hash.THashSet; -import gnu.trove.set.hash.TIntHashSet; - -public class GuardedExpressionGroup extends Expression { - public GuardedExpression[] expressions; - - public GuardedExpressionGroup(GuardedExpression[] expressions) { - this.expressions = expressions; - } - - @Override - public void collectRefs(TObjectIntHashMap allRefs, - TIntHashSet refs) { - for(GuardedExpression expression : expressions) { - for(Expression guard : expression.guards) - guard.collectRefs(allRefs, refs); - expression.value.collectRefs(allRefs, refs); - } - } - - @Override - public void collectVars(TObjectIntHashMap allVars, - TIntHashSet vars) { - for(GuardedExpression expression : expressions) { - for(Expression guard : expression.guards) - guard.collectVars(allVars, vars); - expression.value.collectVars(allVars, vars); - } - } - - @Override - protected void updateType() throws MatchException { - setType(expressions[0].value.getType()); - } - - @Override - public IVal toVal(Environment env, CodeWriter w) { - CodeWriter success = w.createBlock(getType()); - IVal result = success.getParameters()[0]; - CodeWriter failure = w.createBlock(); - compile(env, w, success.getContinuation(), failure.getContinuation()); - w.continueAs(success); - failure.throw_(location, Throw.MatchingException, "Matching failure at: " + toString()); - return result; - //throw new InternalCompilerError("GuardedExpressionGroup should be handled in match compilation."); - } - - @Override - public void collectFreeVariables(THashSet vars) { - for(GuardedExpression expression : expressions) { - for(Expression guard : expression.guards) - guard.collectFreeVariables(vars); - expression.value.collectFreeVariables(vars); - } - } - - @Override - public Expression simplify(SimplificationContext context) { - for(GuardedExpression expression : expressions) { - for(int i=0;i effects) { - for(GuardedExpression ge : expressions) { - for(Expression guard : ge.guards) - guard.collectEffects(effects); - ge.value.collectEffects(effects); - } - } - - @Override - public void setLocationDeep(long loc) { - if(location == Locations.NO_LOCATION) { - location = loc; - for(GuardedExpression expression : expressions) - expression.setLocationDeep(loc); - } - } - - @Override - public void accept(ExpressionVisitor visitor) { - visitor.visit(this); - } - - @Override - public void forVariables(VariableProcedure procedure) { - for(GuardedExpression expression : expressions) - expression.forVariables(procedure); - } - - @Override - public Expression accept(ExpressionTransformer transformer) { - return transformer.transform(this); - } -} +package org.simantics.scl.compiler.elaboration.expressions; + +import org.simantics.scl.compiler.elaboration.contexts.ReplaceContext; +import org.simantics.scl.compiler.elaboration.contexts.SimplificationContext; +import org.simantics.scl.compiler.elaboration.contexts.TranslationContext; +import org.simantics.scl.compiler.elaboration.contexts.TypingContext; +import org.simantics.scl.compiler.environment.Environment; +import org.simantics.scl.compiler.errors.Locations; +import org.simantics.scl.compiler.internal.codegen.continuations.ICont; +import org.simantics.scl.compiler.internal.codegen.references.IVal; +import org.simantics.scl.compiler.internal.codegen.ssa.exits.Throw; +import org.simantics.scl.compiler.internal.codegen.writer.CodeWriter; +import org.simantics.scl.compiler.internal.elaboration.utils.ExpressionDecorator; +import org.simantics.scl.compiler.types.Type; +import org.simantics.scl.compiler.types.Types; +import org.simantics.scl.compiler.types.exceptions.MatchException; + +import gnu.trove.map.hash.TObjectIntHashMap; +import gnu.trove.set.hash.THashSet; +import gnu.trove.set.hash.TIntHashSet; + +public class GuardedExpressionGroup extends Expression { + public GuardedExpression[] expressions; + + public GuardedExpressionGroup(GuardedExpression[] expressions) { + this.expressions = expressions; + } + + @Override + public void collectRefs(TObjectIntHashMap allRefs, + TIntHashSet refs) { + for(GuardedExpression expression : expressions) { + for(Expression guard : expression.guards) + guard.collectRefs(allRefs, refs); + expression.value.collectRefs(allRefs, refs); + } + } + + @Override + public void collectVars(TObjectIntHashMap allVars, + TIntHashSet vars) { + for(GuardedExpression expression : expressions) { + for(Expression guard : expression.guards) + guard.collectVars(allVars, vars); + expression.value.collectVars(allVars, vars); + } + } + + @Override + protected void updateType() throws MatchException { + setType(expressions[0].value.getType()); + } + + @Override + public IVal toVal(Environment env, CodeWriter w) { + CodeWriter success = w.createBlock(getType()); + IVal result = success.getParameters()[0]; + CodeWriter failure = w.createBlock(); + compile(env, w, success.getContinuation(), failure.getContinuation()); + w.continueAs(success); + failure.throw_(location, Throw.MatchingException, "Matching failure at: " + toString()); + return result; + //throw new InternalCompilerError("GuardedExpressionGroup should be handled in match compilation."); + } + + @Override + public void collectFreeVariables(THashSet vars) { + for(GuardedExpression expression : expressions) { + for(Expression guard : expression.guards) + guard.collectFreeVariables(vars); + expression.value.collectFreeVariables(vars); + } + } + + @Override + public Expression simplify(SimplificationContext context) { + for(GuardedExpression expression : expressions) { + for(int i=0;i effects) { + for(GuardedExpression ge : expressions) { + for(Expression guard : ge.guards) + guard.collectEffects(effects); + ge.value.collectEffects(effects); + } + } + + @Override + public void setLocationDeep(long loc) { + if(location == Locations.NO_LOCATION) { + location = loc; + for(GuardedExpression expression : expressions) + expression.setLocationDeep(loc); + } + } + + @Override + public void accept(ExpressionVisitor visitor) { + visitor.visit(this); + } + + @Override + public void forVariables(VariableProcedure procedure) { + for(GuardedExpression expression : expressions) + expression.forVariables(procedure); + } + + @Override + public Expression accept(ExpressionTransformer transformer) { + return transformer.transform(this); + } + + @Override + public int getSyntacticFunctionArity() { + return expressions[0].value.getSyntacticFunctionArity(); + } +} diff --git a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/errors/ErrorLog.java b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/errors/ErrorLog.java index 13e80fc6d..2287f919b 100644 --- a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/errors/ErrorLog.java +++ b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/errors/ErrorLog.java @@ -61,4 +61,8 @@ public class ErrorLog { public String toString() { return getErrorsAsString(); } + + public int getErrorCount() { + return errors.size(); + } } diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Arity1.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Arity1.scl index fa48e47c1..fc21692fc 100644 --- a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Arity1.scl +++ b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/Arity1.scl @@ -1,9 +1,22 @@ - -data Foo a = Foo a - -f :: Foo a -> a -f = \Foo a -> a - -main = "Not to be executed" --- -5:6-5:11: Arity is 1 but 2 patterns have been given. \ No newline at end of file +data Foo a = Foo a + +f :: Foo a -> a +f = \Foo a -> a + +main = "Not to be executed" +-- +3:1-3:2: Possible problem: type declaration has 1 parameter types, but function definition has 2 parameters. +4:6-4:11: Arity is 1 but 2 patterns have been given. +-- +import "Prelude" + +f :: Integer -> Integer -> Integer +f x = do + print x + x + +main = "Not to be executed" +-- +3:1-3:2: Possible problem: type declaration has 2 parameter types, but function definition has 1 parameters. +5:5-5:12: No side-effects allowed here. +6:5-6:6: Expected Integer> got . \ No newline at end of file -- 2.47.1