]> gerrit.simantics Code Review - simantics/platform.git/blobdiff - bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/expressions/printing/ExpressionToStringVisitor.java
(refs #7375) Replaced collectEffects by CollectEffectsVisitor
[simantics/platform.git] / bundles / org.simantics.scl.compiler / src / org / simantics / scl / compiler / elaboration / expressions / printing / ExpressionToStringVisitor.java
index ce2af3b929a4f3a53d62d19c622df926a35f4920..b1a05d70e2e42a6541d180bfe38d085d8dc9d319 100644 (file)
-package org.simantics.scl.compiler.elaboration.expressions.printing;\r
-\r
-import java.util.Map.Entry;\r
-\r
-import org.simantics.scl.compiler.elaboration.chr.CHRLiteral;\r
-import org.simantics.scl.compiler.elaboration.chr.CHRQuery;\r
-import org.simantics.scl.compiler.elaboration.chr.CHRRule;\r
-import org.simantics.scl.compiler.elaboration.chr.relations.CHRConstraint;\r
-import org.simantics.scl.compiler.elaboration.expressions.Assignment;\r
-import org.simantics.scl.compiler.elaboration.expressions.Case;\r
-import org.simantics.scl.compiler.elaboration.expressions.EApply;\r
-import org.simantics.scl.compiler.elaboration.expressions.EApplyType;\r
-import org.simantics.scl.compiler.elaboration.expressions.EAsPattern;\r
-import org.simantics.scl.compiler.elaboration.expressions.EBind;\r
-import org.simantics.scl.compiler.elaboration.expressions.ECHRRuleset;\r
-import org.simantics.scl.compiler.elaboration.expressions.EConstant;\r
-import org.simantics.scl.compiler.elaboration.expressions.ECoveringBranchPoint;\r
-import org.simantics.scl.compiler.elaboration.expressions.EEnforce;\r
-import org.simantics.scl.compiler.elaboration.expressions.EEquations;\r
-import org.simantics.scl.compiler.elaboration.expressions.EError;\r
-import org.simantics.scl.compiler.elaboration.expressions.EExternalConstant;\r
-import org.simantics.scl.compiler.elaboration.expressions.EFieldAccess;\r
-import org.simantics.scl.compiler.elaboration.expressions.EGetConstraint;\r
-import org.simantics.scl.compiler.elaboration.expressions.EIf;\r
-import org.simantics.scl.compiler.elaboration.expressions.EIntegerLiteral;\r
-import org.simantics.scl.compiler.elaboration.expressions.ELambda;\r
-import org.simantics.scl.compiler.elaboration.expressions.ELambdaType;\r
-import org.simantics.scl.compiler.elaboration.expressions.ELet;\r
-import org.simantics.scl.compiler.elaboration.expressions.EListComprehension;\r
-import org.simantics.scl.compiler.elaboration.expressions.EListLiteral;\r
-import org.simantics.scl.compiler.elaboration.expressions.ELiteral;\r
-import org.simantics.scl.compiler.elaboration.expressions.EMatch;\r
-import org.simantics.scl.compiler.elaboration.expressions.EPlaceholder;\r
-import org.simantics.scl.compiler.elaboration.expressions.ERealLiteral;\r
-import org.simantics.scl.compiler.elaboration.expressions.ERuleset;\r
-import org.simantics.scl.compiler.elaboration.expressions.ESelect;\r
-import org.simantics.scl.compiler.elaboration.expressions.ESimpleLambda;\r
-import org.simantics.scl.compiler.elaboration.expressions.ESimpleLet;\r
-import org.simantics.scl.compiler.elaboration.expressions.ETransformation;\r
-import org.simantics.scl.compiler.elaboration.expressions.ETypeAnnotation;\r
-import org.simantics.scl.compiler.elaboration.expressions.EVariable;\r
-import org.simantics.scl.compiler.elaboration.expressions.EViewPattern;\r
-import org.simantics.scl.compiler.elaboration.expressions.EWhen;\r
-import org.simantics.scl.compiler.elaboration.expressions.Expression;\r
-import org.simantics.scl.compiler.elaboration.expressions.ExpressionVisitor;\r
-import org.simantics.scl.compiler.elaboration.expressions.GuardedExpression;\r
-import org.simantics.scl.compiler.elaboration.expressions.GuardedExpressionGroup;\r
-import org.simantics.scl.compiler.elaboration.expressions.Variable;\r
-import org.simantics.scl.compiler.elaboration.java.EqRelation;\r
-import org.simantics.scl.compiler.elaboration.java.MemberRelation;\r
-import org.simantics.scl.compiler.elaboration.query.QAlternative;\r
-import org.simantics.scl.compiler.elaboration.query.QAtom;\r
-import org.simantics.scl.compiler.elaboration.query.QConjunction;\r
-import org.simantics.scl.compiler.elaboration.query.QDisjunction;\r
-import org.simantics.scl.compiler.elaboration.query.QExists;\r
-import org.simantics.scl.compiler.elaboration.query.QIf;\r
-import org.simantics.scl.compiler.elaboration.query.QMapping;\r
-import org.simantics.scl.compiler.elaboration.query.QNegation;\r
-import org.simantics.scl.compiler.elaboration.query.Query;\r
-import org.simantics.scl.compiler.elaboration.query.QueryVisitor;\r
-import org.simantics.scl.compiler.elaboration.rules.SectionName;\r
-import org.simantics.scl.compiler.elaboration.rules.TransformationRule;\r
-\r
-public class ExpressionToStringVisitor implements ExpressionVisitor, QueryVisitor {\r
-\r
-    StringBuilder b = new StringBuilder();\r
-    int indentation;\r
-    \r
-    public ExpressionToStringVisitor(StringBuilder b) {\r
-        this.b = b;\r
-    }\r
-\r
-    public void show(Variable variable) {\r
-        if(variable == null)\r
-            b.append("NULL_VARIABLE");\r
-        else\r
-            b.append(variable.getName());\r
-    }\r
-    \r
-    private void newLine() {\r
-        b.append('\n');\r
-        for(int i=0;i<indentation;++i)\r
-            b.append("  ");\r
-    }\r
-    \r
-    public void showPar(Expression expression) {\r
-        boolean needsPar = false;\r
-        while(true) {\r
-            if(expression instanceof EPlaceholder)\r
-                expression = ((EPlaceholder)expression).expression;\r
-            else if(expression instanceof ETypeAnnotation)\r
-                expression = ((ETypeAnnotation)expression).getValue();\r
-            else if(expression instanceof EApplyType)\r
-                expression = ((EApplyType)expression).getExpression();\r
-            else if(expression instanceof ELambdaType)\r
-                expression = ((ELambdaType)expression).value;\r
-            else if(expression instanceof ECoveringBranchPoint)\r
-                expression = ((ECoveringBranchPoint)expression).expression;\r
-            else\r
-                break;\r
-        }\r
-        if(expression instanceof EApply ||\r
-                expression instanceof EIf ||\r
-                expression instanceof ESimpleLambda ||\r
-                expression instanceof ESimpleLet)\r
-            needsPar = true;\r
-        if(needsPar)\r
-            b.append('(');\r
-        expression.accept(this);\r
-        if(needsPar)\r
-            b.append(')');\r
-    }\r
-    \r
-    @Override\r
-    public void visit(EApply expression) {\r
-        showPar(expression.getFunction());\r
-        for(Expression parameter : expression.getParameters()) {\r
-            b.append(' ');\r
-            showPar(parameter);\r
-        }\r
-    }\r
-\r
-    @Override\r
-    public void visit(EApplyType expression) {\r
-        expression.getExpression().accept(this);\r
-    }\r
-\r
-    @Override\r
-    public void visit(EAsPattern expression) {\r
-        show(expression.getVariable());\r
-        b.append('@');\r
-        showPar(expression.getPattern());\r
-    }\r
-\r
-    @Override\r
-    public void visit(EBind expression) {\r
-        b.append("EBind");\r
-    }\r
-\r
-    @Override\r
-    public void visit(EConstant expression) {\r
-        String name = expression.getValue().getName().name;\r
-        if(Character.isJavaIdentifierStart(name.charAt(0)))\r
-            b.append(name);\r
-        else\r
-            b.append('(').append(name).append(')');\r
-    }\r
-\r
-    @Override\r
-    public void visit(EEnforce expression) {\r
-        b.append("enforce ");\r
-        expression.getQuery().accept(this);\r
-    }\r
-\r
-    @Override\r
-    public void visit(EError expression) {\r
-        b.append("EError");\r
-    }\r
-\r
-    @Override\r
-    public void visit(EExternalConstant expression) {\r
-        b.append(expression.getValue());\r
-    }\r
-\r
-    @Override\r
-    public void visit(EFieldAccess expression) {\r
-        b.append("EFieldAccess");\r
-    }\r
-\r
-    @Override\r
-    public void visit(EGetConstraint expression) {\r
-        b.append("EGetConstraint");\r
-    }\r
-\r
-    @Override\r
-    public void visit(EIf expression) {\r
-        b.append("if ");\r
-        expression.condition.accept(this);\r
-        ++indentation;\r
-        newLine();\r
-        b.append("then ");\r
-        expression.then_.accept(this);\r
-        if(expression.else_ != null) {\r
-            newLine();\r
-            b.append("else ");\r
-            expression.else_.accept(this);\r
-        }\r
-        --indentation;\r
-    }\r
-    \r
-    @Override\r
-    public void visit(QIf query) {\r
-        b.append("if ");\r
-        query.condition.accept(this);\r
-        ++indentation;\r
-        newLine();\r
-        b.append("then ");\r
-        query.thenQuery.accept(this);\r
-        newLine();\r
-        b.append("else ");\r
-        query.elseQuery.accept(this);\r
-        --indentation;\r
-    }\r
-\r
-    @Override\r
-    public void visit(EIntegerLiteral expression) {\r
-        b.append(expression.getValue());\r
-    }\r
-\r
-    @Override\r
-    public void visit(ELambda expression) {\r
-        b.append('\\');\r
-        ++indentation;\r
-        for(Case case_ : expression.getCases()) {\r
-            newLine();\r
-            for(Expression pat : case_.patterns) {\r
-                showPar(pat);\r
-                b.append(' ');\r
-            }\r
-            b.append("-> ");\r
-            ++indentation;\r
-            case_.value.accept(this);\r
-            --indentation;\r
-        }\r
-        --indentation;\r
-    }\r
-    \r
-    @Override\r
-    public void visit(EViewPattern expression) {\r
-        b.append('(');\r
-        expression.expression.accept(this);\r
-        b.append(" -> ");\r
-        expression.pattern.accept(this);\r
-        b.append(')');\r
-    }\r
-\r
-    @Override\r
-    public void visit(ELambdaType expression) {\r
-        expression.value.accept(this);\r
-    }\r
-\r
-    @Override\r
-    public void visit(ELet expression) {\r
-        b.append("do");\r
-        ++indentation;\r
-        printAsDo(expression);\r
-        --indentation;\r
-    }\r
-\r
-    @Override\r
-    public void visit(EListComprehension expression) {\r
-        b.append("EListComprehension");\r
-    }\r
-\r
-    @Override\r
-    public void visit(EListLiteral expression) {\r
-        b.append('[');\r
-        boolean first = true;\r
-        for(Expression component : expression.getComponents()) {\r
-            if(first)\r
-                first = false;\r
-            else\r
-                b.append(',');\r
-            component.accept(this);\r
-        }\r
-        b.append(']');\r
-    }\r
-\r
-    @Override\r
-    public void visit(ELiteral expression) {\r
-        b.append(expression.getValue().toString());\r
-    }\r
-\r
-    @Override\r
-    public void visit(EMatch expression) {\r
-        b.append("match");\r
-        for(Expression s : expression.getScrutinee()) {\r
-            b.append(' ');\r
-            showPar(s);\r
-        }\r
-        b.append(" with");\r
-        ++indentation;\r
-        for(Case case_ : expression.getCases()) {\r
-            newLine();\r
-            for(Expression pat : case_.patterns) {\r
-                showPar(pat);\r
-                b.append(' ');\r
-            }\r
-            b.append("-> ");\r
-            ++indentation;\r
-            case_.value.accept(this);\r
-            --indentation;\r
-        }\r
-        --indentation;\r
-    }\r
-\r
-    @Override\r
-    public void visit(EPlaceholder expression) {\r
-        expression.expression.accept(this);\r
-    }\r
-\r
-    @Override\r
-    public void visit(ERealLiteral expression) {\r
-        b.append(expression.getValue());\r
-    }\r
-\r
-    @Override\r
-    public void visit(ERuleset expression) {\r
-        b.append("let\n");\r
-        ++indentation;\r
-        for(ERuleset.DatalogRule rule : expression.getRules()) {\r
-            newLine();\r
-            visit(rule);\r
-        }\r
-        --indentation;\r
-        b.append("\nin ");\r
-        expression.getIn().accept(this);\r
-    }\r
-\r
-    @Override\r
-    public void visit(ESelect expression) {\r
-        b.append("ESelect");\r
-    }\r
-\r
-    @Override\r
-    public void visit(ESimpleLambda expression) {\r
-        b.append('\\');\r
-        show(expression.getParameter());\r
-        while(expression.getValue() instanceof ESimpleLambda) {\r
-            expression = (ESimpleLambda)expression.getValue();\r
-            b.append(' ');\r
-            show(expression.getParameter());\r
-        }\r
-        b.append(" -> ");\r
-        expression.getValue().accept(this);\r
-    }\r
-\r
-    @Override\r
-    public void visit(ESimpleLet expression) {\r
-        b.append("do");\r
-        ++indentation;\r
-        printAsDo(expression);\r
-        --indentation;\r
-    }\r
-    \r
-    private void printAsDo(Expression expression) {\r
-        if(expression instanceof ESimpleLet) {\r
-            ESimpleLet let = (ESimpleLet)expression;\r
-            Variable variable = let.getVariable();\r
-            Expression value = let.getValue();\r
-            if(variable == null || "_".equals(variable.getName()))\r
-                printAsDo(value);\r
-            else {\r
-                newLine();\r
-                show(variable);\r
-                b.append(" = ");\r
-                value.accept(this);\r
-            }\r
-            printAsDo(let.getIn());\r
-        }\r
-        else if(expression instanceof ELet) {\r
-            ELet let = (ELet)expression;\r
-            for(Assignment assignment : let.assignments) {\r
-                newLine();\r
-                assignment.pattern.accept(this);\r
-                b.append(" = ");\r
-                assignment.value.accept(this);\r
-            }\r
-            printAsDo(let.in);\r
-        }\r
-        else {\r
-            newLine();\r
-            expression.accept(this);\r
-        }\r
-    }\r
-\r
-    @Override\r
-    public void visit(ETransformation expression) {\r
-        b.append("<transformation>");\r
-    }\r
-\r
-    @Override\r
-    public void visit(ETypeAnnotation expression) {\r
-        expression.getValue().accept(this);\r
-    }\r
-\r
-    @Override\r
-    public void visit(EVariable expression) {\r
-        show(expression.getVariable());\r
-    }\r
-\r
-    @Override\r
-    public void visit(EWhen expression) {\r
-        b.append("when ");\r
-        expression.getQuery().accept(this);\r
-        b.append("\n");\r
-        expression.getAction().accept(this);\r
-    }\r
-\r
-    @Override\r
-    public void visit(GuardedExpressionGroup expression) {\r
-        boolean first = true;\r
-        for(GuardedExpression gexp : expression.expressions) {\r
-            if(first)\r
-                first = false;\r
-            else\r
-                newLine();\r
-            b.append("| ");\r
-            for(int i=0;i<gexp.guards.length;++i) {\r
-                if(i > 0)\r
-                    b.append(", ");\r
-                gexp.guards[i].accept(this);\r
-            }\r
-            b.append(" = ");\r
-            gexp.value.accept(this);\r
-        }\r
-    }\r
-\r
-    @Override\r
-    public void visit(QAlternative query) {\r
-        b.append("QAlternative");\r
-    }\r
-\r
-    @Override\r
-    public void visit(QAtom query) {\r
-        if(query.relation == EqRelation.INSTANCE) {\r
-            query.parameters[0].accept(this);\r
-            b.append(" = ");\r
-            query.parameters[1].accept(this);\r
-        }\r
-        else if(query.relation == MemberRelation.INSTANCE) {\r
-            query.parameters[0].accept(this);\r
-            b.append(" <- ");\r
-            query.parameters[1].accept(this);\r
-        }\r
-        else {\r
-            b.append(query.relation);\r
-            for(Expression parameter : query.parameters) {\r
-                b.append(' ');\r
-                showPar(parameter);\r
-            }\r
-        }\r
-    }\r
-\r
-    @Override\r
-    public void visit(QConjunction query) {\r
-        boolean first = true;\r
-        for(Query q : query.queries) {\r
-            if(first)\r
-                first = false;\r
-            else\r
-                newLine();\r
-            q.accept(this);\r
-        }\r
-    }\r
-\r
-    @Override\r
-    public void visit(QDisjunction query) {\r
-        b.append("QDisjunction");\r
-    }\r
-\r
-    @Override\r
-    public void visit(QExists query) {\r
-        b.append("QExists");\r
-    }\r
-\r
-    @Override\r
-    public void visit(QNegation query) {\r
-        b.append("QNegation");\r
-    }\r
-\r
-    @Override\r
-    public void visit(QMapping query) {\r
-        b.append(query.mappingRelation.name.name);\r
-        for(Expression parameter : query.parameters) {\r
-            b.append(' ');\r
-            parameter.accept(this);\r
-        }\r
-    }\r
-\r
-    public void visit(ERuleset.DatalogRule rule) {\r
-        b.append(rule.headRelation.getName());\r
-        for(Expression parameter : rule.headParameters) {\r
-            b.append(' ');\r
-            showPar(parameter);\r
-        }\r
-        b.append(" :-\n");\r
-        ++indentation;\r
-        rule.body.accept(this);\r
-        --indentation;\r
-    }\r
-\r
-    public void visit(TransformationRule rule) {\r
-        b.append("rule ").append(rule.name.name).append(" where");\r
-        for(Entry<SectionName, Query[]> section : rule.sections.entrySet()) {\r
-            b.append("\n@").append(section.getKey().name());\r
-            for(Query query : section.getValue()) {\r
-                b.append('\n');\r
-                query.accept(this);\r
-            }\r
-        }\r
-    }\r
-\r
-\r
-    @Override\r
-    public void visit(ECoveringBranchPoint expression) {\r
-        expression.expression.accept(this);\r
-    }\r
-\r
-    @Override\r
-    public void visit(EEquations eEquations) {\r
-        b.append("eq");\r
-    }\r
-\r
-    @Override\r
-    public void visit(ECHRRuleset echrRuleset) {\r
-        b.append("CHRRuleset");\r
-    }\r
-\r
-    public void visit(CHRRule rule) {\r
-        visit(rule.head);\r
-        b.append(" => ");\r
-        visit(rule.body);\r
-    }\r
-\r
-    public void visit(CHRQuery query) {\r
-        boolean first = true;\r
-        for(CHRLiteral literal : query.literals) {\r
-            if(first)\r
-                first = false;\r
-            else\r
-                b.append(", ");\r
-            visit(literal);\r
-        }\r
-    }\r
-\r
-    public void visit(CHRLiteral literal) {\r
-        if(literal.passive && literal.relation instanceof CHRConstraint)\r
-            b.append("@passive ");\r
-        if(literal.killAfterMatch)\r
-            b.append('-');\r
-        b.append(literal.relation);\r
-        for(Expression parameter : literal.parameters) {\r
-            b.append(' ');\r
-            showPar(parameter);\r
-        }\r
-    }\r
-}\r
+package org.simantics.scl.compiler.elaboration.expressions.printing;
+
+import java.util.Map.Entry;
+
+import org.simantics.scl.compiler.elaboration.chr.CHRLiteral;
+import org.simantics.scl.compiler.elaboration.chr.CHRQuery;
+import org.simantics.scl.compiler.elaboration.chr.CHRRule;
+import org.simantics.scl.compiler.elaboration.chr.relations.CHRConstraint;
+import org.simantics.scl.compiler.elaboration.expressions.Assignment;
+import org.simantics.scl.compiler.elaboration.expressions.Case;
+import org.simantics.scl.compiler.elaboration.expressions.EAmbiguous;
+import org.simantics.scl.compiler.elaboration.expressions.EApply;
+import org.simantics.scl.compiler.elaboration.expressions.EApplyType;
+import org.simantics.scl.compiler.elaboration.expressions.EAsPattern;
+import org.simantics.scl.compiler.elaboration.expressions.EBinary;
+import org.simantics.scl.compiler.elaboration.expressions.EBind;
+import org.simantics.scl.compiler.elaboration.expressions.EBlock;
+import org.simantics.scl.compiler.elaboration.expressions.ECHRRuleset;
+import org.simantics.scl.compiler.elaboration.expressions.ECHRRulesetConstructor;
+import org.simantics.scl.compiler.elaboration.expressions.ECHRSelect;
+import org.simantics.scl.compiler.elaboration.expressions.EConstant;
+import org.simantics.scl.compiler.elaboration.expressions.ECoveringBranchPoint;
+import org.simantics.scl.compiler.elaboration.expressions.EEnforce;
+import org.simantics.scl.compiler.elaboration.expressions.EEquations;
+import org.simantics.scl.compiler.elaboration.expressions.EError;
+import org.simantics.scl.compiler.elaboration.expressions.EExternalConstant;
+import org.simantics.scl.compiler.elaboration.expressions.EFieldAccess;
+import org.simantics.scl.compiler.elaboration.expressions.EGetConstraint;
+import org.simantics.scl.compiler.elaboration.expressions.EIf;
+import org.simantics.scl.compiler.elaboration.expressions.EIntegerLiteral;
+import org.simantics.scl.compiler.elaboration.expressions.ELambda;
+import org.simantics.scl.compiler.elaboration.expressions.ELambdaType;
+import org.simantics.scl.compiler.elaboration.expressions.ELet;
+import org.simantics.scl.compiler.elaboration.expressions.EListComprehension;
+import org.simantics.scl.compiler.elaboration.expressions.EListLiteral;
+import org.simantics.scl.compiler.elaboration.expressions.ELiteral;
+import org.simantics.scl.compiler.elaboration.expressions.EMatch;
+import org.simantics.scl.compiler.elaboration.expressions.EPlaceholder;
+import org.simantics.scl.compiler.elaboration.expressions.EPreLet;
+import org.simantics.scl.compiler.elaboration.expressions.ERange;
+import org.simantics.scl.compiler.elaboration.expressions.ERealLiteral;
+import org.simantics.scl.compiler.elaboration.expressions.ERecord;
+import org.simantics.scl.compiler.elaboration.expressions.ERuleset;
+import org.simantics.scl.compiler.elaboration.expressions.ESelect;
+import org.simantics.scl.compiler.elaboration.expressions.ESimpleLambda;
+import org.simantics.scl.compiler.elaboration.expressions.ESimpleLet;
+import org.simantics.scl.compiler.elaboration.expressions.EStringLiteral;
+import org.simantics.scl.compiler.elaboration.expressions.ETransformation;
+import org.simantics.scl.compiler.elaboration.expressions.ETypeAnnotation;
+import org.simantics.scl.compiler.elaboration.expressions.EVar;
+import org.simantics.scl.compiler.elaboration.expressions.EVariable;
+import org.simantics.scl.compiler.elaboration.expressions.EViewPattern;
+import org.simantics.scl.compiler.elaboration.expressions.EWhen;
+import org.simantics.scl.compiler.elaboration.expressions.Expression;
+import org.simantics.scl.compiler.elaboration.expressions.ExpressionVisitor;
+import org.simantics.scl.compiler.elaboration.expressions.GuardedExpression;
+import org.simantics.scl.compiler.elaboration.expressions.GuardedExpressionGroup;
+import org.simantics.scl.compiler.elaboration.expressions.Variable;
+import org.simantics.scl.compiler.elaboration.java.EqRelation;
+import org.simantics.scl.compiler.elaboration.java.MemberRelation;
+import org.simantics.scl.compiler.elaboration.query.QAlternative;
+import org.simantics.scl.compiler.elaboration.query.QAtom;
+import org.simantics.scl.compiler.elaboration.query.QConjunction;
+import org.simantics.scl.compiler.elaboration.query.QDisjunction;
+import org.simantics.scl.compiler.elaboration.query.QExists;
+import org.simantics.scl.compiler.elaboration.query.QIf;
+import org.simantics.scl.compiler.elaboration.query.QMapping;
+import org.simantics.scl.compiler.elaboration.query.QNegation;
+import org.simantics.scl.compiler.elaboration.query.Query;
+import org.simantics.scl.compiler.elaboration.query.QueryVisitor;
+import org.simantics.scl.compiler.elaboration.rules.SectionName;
+import org.simantics.scl.compiler.elaboration.rules.TransformationRule;
+
+public class ExpressionToStringVisitor implements ExpressionVisitor, QueryVisitor {
+
+    StringBuilder b = new StringBuilder();
+    int indentation;
+    
+    public ExpressionToStringVisitor(StringBuilder b) {
+        this.b = b;
+    }
+
+    public void show(Variable variable) {
+        if(variable == null)
+            b.append("NULL_VARIABLE");
+        else
+            b.append(variable.getName());
+    }
+    
+    private void newLine() {
+        b.append('\n');
+        for(int i=0;i<indentation;++i)
+            b.append("  ");
+    }
+    
+    public void showPar(Expression expression) {
+        boolean needsPar = false;
+        while(true) {
+            if(expression instanceof EPlaceholder)
+                expression = ((EPlaceholder)expression).expression;
+            else if(expression instanceof ETypeAnnotation)
+                expression = ((ETypeAnnotation)expression).getValue();
+            else if(expression instanceof EApplyType)
+                expression = ((EApplyType)expression).getExpression();
+            else if(expression instanceof ELambdaType)
+                expression = ((ELambdaType)expression).value;
+            else if(expression instanceof ECoveringBranchPoint)
+                expression = ((ECoveringBranchPoint)expression).expression;
+            else
+                break;
+        }
+        if(expression instanceof EApply ||
+                expression instanceof EIf ||
+                expression instanceof ESimpleLambda ||
+                expression instanceof ESimpleLet)
+            needsPar = true;
+        if(needsPar)
+            b.append('(');
+        expression.accept(this);
+        if(needsPar)
+            b.append(')');
+    }
+    
+    @Override
+    public void visit(EApply expression) {
+        showPar(expression.getFunction());
+        for(Expression parameter : expression.getParameters()) {
+            b.append(' ');
+            showPar(parameter);
+        }
+    }
+
+    @Override
+    public void visit(EApplyType expression) {
+        expression.getExpression().accept(this);
+    }
+
+    @Override
+    public void visit(EAsPattern expression) {
+        show(expression.getVariable());
+        b.append('@');
+        showPar(expression.getPattern());
+    }
+
+    @Override
+    public void visit(EBind expression) {
+        b.append("EBind");
+    }
+
+    @Override
+    public void visit(EConstant expression) {
+        String name = expression.getValue().getName().name;
+        if(Character.isJavaIdentifierStart(name.charAt(0)))
+            b.append(name);
+        else
+            b.append('(').append(name).append(')');
+    }
+
+    @Override
+    public void visit(EEnforce expression) {
+        b.append("enforce ");
+        expression.getQuery().accept(this);
+    }
+
+    @Override
+    public void visit(EError expression) {
+        b.append("EError");
+    }
+
+    @Override
+    public void visit(EExternalConstant expression) {
+        b.append(expression.getValue());
+    }
+
+    @Override
+    public void visit(EFieldAccess expression) {
+        b.append("EFieldAccess");
+    }
+
+    @Override
+    public void visit(EGetConstraint expression) {
+        b.append("EGetConstraint");
+    }
+
+    @Override
+    public void visit(EIf expression) {
+        b.append("if ");
+        expression.condition.accept(this);
+        ++indentation;
+        newLine();
+        b.append("then ");
+        expression.then_.accept(this);
+        if(expression.else_ != null) {
+            newLine();
+            b.append("else ");
+            expression.else_.accept(this);
+        }
+        --indentation;
+    }
+    
+    @Override
+    public void visit(QIf query) {
+        b.append("if ");
+        query.condition.accept(this);
+        ++indentation;
+        newLine();
+        b.append("then ");
+        query.thenQuery.accept(this);
+        newLine();
+        b.append("else ");
+        query.elseQuery.accept(this);
+        --indentation;
+    }
+
+    @Override
+    public void visit(EIntegerLiteral expression) {
+        b.append(expression.getValue());
+    }
+
+    @Override
+    public void visit(ELambda expression) {
+        b.append('\\');
+        ++indentation;
+        for(Case case_ : expression.getCases()) {
+            newLine();
+            for(Expression pat : case_.patterns) {
+                showPar(pat);
+                b.append(' ');
+            }
+            b.append("-> ");
+            ++indentation;
+            case_.value.accept(this);
+            --indentation;
+        }
+        --indentation;
+    }
+    
+    @Override
+    public void visit(EViewPattern expression) {
+        b.append('(');
+        expression.expression.accept(this);
+        b.append(" -> ");
+        expression.pattern.accept(this);
+        b.append(')');
+    }
+
+    @Override
+    public void visit(ELambdaType expression) {
+        expression.value.accept(this);
+    }
+
+    @Override
+    public void visit(ELet expression) {
+        b.append("do");
+        ++indentation;
+        printAsDo(expression);
+        --indentation;
+    }
+
+    @Override
+    public void visit(EListComprehension expression) {
+        b.append("EListComprehension");
+    }
+
+    @Override
+    public void visit(EListLiteral expression) {
+        b.append('[');
+        boolean first = true;
+        for(Expression component : expression.getComponents()) {
+            if(first)
+                first = false;
+            else
+                b.append(',');
+            component.accept(this);
+        }
+        b.append(']');
+    }
+
+    @Override
+    public void visit(ELiteral expression) {
+        b.append(expression.getValue().toString());
+    }
+
+    @Override
+    public void visit(EMatch expression) {
+        b.append("match");
+        for(Expression s : expression.getScrutinee()) {
+            b.append(' ');
+            showPar(s);
+        }
+        b.append(" with");
+        ++indentation;
+        for(Case case_ : expression.getCases()) {
+            newLine();
+            for(Expression pat : case_.patterns) {
+                showPar(pat);
+                b.append(' ');
+            }
+            b.append("-> ");
+            ++indentation;
+            case_.value.accept(this);
+            --indentation;
+        }
+        --indentation;
+    }
+
+    @Override
+    public void visit(EPlaceholder expression) {
+        expression.expression.accept(this);
+    }
+
+    @Override
+    public void visit(ERealLiteral expression) {
+        b.append(expression.getValue());
+    }
+
+    @Override
+    public void visit(ERuleset expression) {
+        b.append("let\n");
+        ++indentation;
+        for(ERuleset.DatalogRule rule : expression.getRules()) {
+            newLine();
+            visit(rule);
+        }
+        --indentation;
+        b.append("\nin ");
+        expression.getIn().accept(this);
+    }
+
+    @Override
+    public void visit(ESelect expression) {
+        b.append("ESelect");
+    }
+    
+    @Override
+    public void visit(ECHRSelect expression) {
+        b.append("ECHRSelect");
+    }
+    
+    @Override
+    public void visit(ESimpleLambda expression) {
+        b.append('\\');
+        show(expression.getParameter());
+        while(expression.getValue() instanceof ESimpleLambda) {
+            expression = (ESimpleLambda)expression.getValue();
+            b.append(' ');
+            show(expression.getParameter());
+        }
+        b.append(" -> ");
+        expression.getValue().accept(this);
+    }
+
+    @Override
+    public void visit(ESimpleLet expression) {
+        b.append("do");
+        ++indentation;
+        printAsDo(expression);
+        --indentation;
+    }
+    
+    private void printAsDo(Expression expression) {
+        if(expression instanceof ESimpleLet) {
+            ESimpleLet let = (ESimpleLet)expression;
+            Variable variable = let.getVariable();
+            Expression value = let.getValue();
+            if(variable == null || "_".equals(variable.getName()))
+                printAsDo(value);
+            else {
+                newLine();
+                show(variable);
+                b.append(" = ");
+                value.accept(this);
+            }
+            printAsDo(let.getIn());
+        }
+        else if(expression instanceof ELet) {
+            ELet let = (ELet)expression;
+            for(Assignment assignment : let.assignments) {
+                newLine();
+                assignment.pattern.accept(this);
+                b.append(" = ");
+                assignment.value.accept(this);
+            }
+            printAsDo(let.in);
+        }
+        else {
+            newLine();
+            expression.accept(this);
+        }
+    }
+
+    @Override
+    public void visit(ETransformation expression) {
+        b.append("<transformation>");
+    }
+
+    @Override
+    public void visit(ETypeAnnotation expression) {
+        expression.getValue().accept(this);
+    }
+
+    @Override
+    public void visit(EVar expression) {
+        b.append(expression.name);
+    }
+
+    @Override
+    public void visit(EVariable expression) {
+        show(expression.getVariable());
+    }
+
+    @Override
+    public void visit(EWhen expression) {
+        b.append("when ");
+        expression.getQuery().accept(this);
+        b.append("\n");
+        expression.getAction().accept(this);
+    }
+
+    @Override
+    public void visit(GuardedExpressionGroup expression) {
+        boolean first = true;
+        for(GuardedExpression gexp : expression.expressions) {
+            if(first)
+                first = false;
+            else
+                newLine();
+            b.append("| ");
+            for(int i=0;i<gexp.guards.length;++i) {
+                if(i > 0)
+                    b.append(", ");
+                gexp.guards[i].accept(this);
+            }
+            b.append(" = ");
+            gexp.value.accept(this);
+        }
+    }
+
+    @Override
+    public void visit(QAlternative query) {
+        b.append("QAlternative");
+    }
+
+    @Override
+    public void visit(QAtom query) {
+        if(query.relation == EqRelation.INSTANCE) {
+            query.parameters[0].accept(this);
+            b.append(" = ");
+            query.parameters[1].accept(this);
+        }
+        else if(query.relation == MemberRelation.INSTANCE) {
+            query.parameters[0].accept(this);
+            b.append(" <- ");
+            query.parameters[1].accept(this);
+        }
+        else {
+            b.append(query.relation);
+            for(Expression parameter : query.parameters) {
+                b.append(' ');
+                showPar(parameter);
+            }
+        }
+    }
+
+    @Override
+    public void visit(QConjunction query) {
+        boolean first = true;
+        for(Query q : query.queries) {
+            if(first)
+                first = false;
+            else
+                newLine();
+            q.accept(this);
+        }
+    }
+
+    @Override
+    public void visit(QDisjunction query) {
+        b.append("QDisjunction");
+    }
+
+    @Override
+    public void visit(QExists query) {
+        b.append("QExists");
+    }
+
+    @Override
+    public void visit(QNegation query) {
+        b.append("QNegation");
+    }
+
+    @Override
+    public void visit(QMapping query) {
+        b.append(query.mappingRelation.name.name);
+        for(Expression parameter : query.parameters) {
+            b.append(' ');
+            parameter.accept(this);
+        }
+    }
+
+    public void visit(ERuleset.DatalogRule rule) {
+        b.append(rule.headRelation.getName());
+        for(Expression parameter : rule.headParameters) {
+            b.append(' ');
+            showPar(parameter);
+        }
+        b.append(" :-\n");
+        ++indentation;
+        rule.body.accept(this);
+        --indentation;
+    }
+
+    public void visit(TransformationRule rule) {
+        b.append("rule ").append(rule.name.name).append(" where");
+        for(Entry<SectionName, Query[]> section : rule.sections.entrySet()) {
+            b.append("\n@").append(section.getKey().name());
+            for(Query query : section.getValue()) {
+                b.append('\n');
+                query.accept(this);
+            }
+        }
+    }
+
+
+    @Override
+    public void visit(ECoveringBranchPoint expression) {
+        expression.expression.accept(this);
+    }
+
+    @Override
+    public void visit(EEquations expression) {
+        b.append("eq");
+    }
+
+    @Override
+    public void visit(ECHRRuleset expression) {
+        b.append("ECHRRuleset");
+    }
+    
+    @Override
+    public void visit(ECHRRulesetConstructor expression) {
+        b.append("ECHRRulesetConstructor");
+    }
+
+    public void visit(CHRRule rule) {
+        visit(rule.head);
+        b.append(" => ");
+        visit(rule.body);
+    }
+
+    public void visit(CHRQuery query) {
+        boolean first = true;
+        for(CHRLiteral literal : query.literals) {
+            if(first)
+                first = false;
+            else
+                b.append(", ");
+            visit(literal);
+        }
+    }
+
+    public void visit(CHRLiteral literal) {
+        if(literal.passive && literal.relation instanceof CHRConstraint)
+            b.append("@passive ");
+        if(literal.killAfterMatch)
+            b.append('-');
+        b.append(literal.relation);
+        for(Expression parameter : literal.parameters) {
+            b.append(' ');
+            showPar(parameter);
+        }
+    }
+
+    @Override
+    public void visit(EBinary expression) {
+        b.append("<EBinary>");
+    }
+
+    @Override
+    public void visit(EBlock expression) {
+        b.append("<EBlock>");
+    }
+
+    @Override
+    public void visit(EPreLet expression) {
+        b.append("<EPreLet>");
+    }
+
+    @Override
+    public void visit(ERange expression) {
+        b.append('[');
+        expression.from.accept(this);
+        b.append("..");
+        expression.to.accept(this);
+        b.append(']');
+    }
+
+    @Override
+    public void visit(ERecord expression) {
+        b.append("<ERecord>");
+    }
+
+    @Override
+    public void visit(EStringLiteral expression) {
+        b.append('"');
+        for(int i=0;i<expression.strings.length;++i) {
+            b.append(expression.strings[i]);
+            if(i < expression.expressions.length) {
+                b.append("\\(");
+                expression.expressions[i].accept(this);
+                b.append(')');
+            }
+        }
+        b.append('"');
+    }
+
+    @Override
+    public void visit(EAmbiguous eAmbiguous) {
+        b.append("EAmbigious");
+    }
+}