--- /dev/null
+package org.simantics.scl.compiler.elaboration.expressions.printing;\r
+\r
+import java.util.Map.Entry;\r
+\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.EConstant;\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.ECoveringBranchPoint;\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.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.getCondition().accept(this);\r
+ ++indentation;\r
+ newLine();\r
+ b.append("then ");\r
+ expression.getThen().accept(this);\r
+ newLine();\r
+ b.append("else ");\r
+ expression.getElse().accept(this);\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(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("_".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