package qls.ast.visitor.prettyprinter; import ql.ast.Expression; import ql.ast.QLNode; import ql.ast.QLType; import ql.ast.expression.Identifier; import ql.ast.type.QLBoolean; import ql.ast.type.QLError; import ql.ast.type.QLFloat; import ql.ast.type.QLForm; import ql.ast.type.QLInteger; import ql.ast.type.QLNumeric; import ql.ast.type.QLString; import ql.ast.visitor.TypeVisitor; import ql.ast.visitor.prettyprinter.PrintWriter; import qls.ast.Statement; import qls.ast.expression.literal.BooleanLiteral; import qls.ast.expression.literal.FloatLiteral; import qls.ast.expression.literal.IntegerLiteral; import qls.ast.expression.literal.StringLiteral; import qls.ast.statement.DefaultStyle; import qls.ast.statement.DefaultWidget; import qls.ast.statement.Page; import qls.ast.statement.Block; import qls.ast.statement.Question; import qls.ast.statement.Section; import qls.ast.statement.Stylesheet; import qls.ast.statement.widget.Widget; import qls.ast.statement.widget.styling.Property; import qls.ast.statement.widget.styling.StyleProperties; import qls.ast.statement.widget.styling.property.Color; import qls.ast.statement.widget.styling.property.Font; import qls.ast.statement.widget.styling.property.FontSize; import qls.ast.statement.widget.styling.property.Height; import qls.ast.statement.widget.styling.property.Width; import qls.ast.statement.widget.type.Checkbox; import qls.ast.statement.widget.type.Default; import qls.ast.statement.widget.type.Spinbox; import qls.ast.statement.widget.type.TextField; import qls.ast.statement.widget.type.parameterised.Dropdown; import qls.ast.statement.widget.type.parameterised.RadioButton; import qls.ast.statement.widget.type.parameterised.Slider; import qls.ast.visitor.ExpressionVisitor; import qls.ast.visitor.StatementVisitor; public class PrettyPrinter extends StatementVisitor<String> implements ExpressionVisitor<String>, TypeVisitor<String> { /* * Expression with custom prefix */ public static void print(Expression expression, PrintWriter printWriter) { PrettyPrinter printer = new PrettyPrinter(); printWriter.printString(expression.accept(printer)); } /* * Statement with custom prefix */ public static void print(Statement statement, PrintWriter printWriter) { PrettyPrinter printer = new PrettyPrinter(); printWriter.printString(statement.accept(printer)); } /* * Statement with custom prefix */ public static void print(QLType type, PrintWriter printWriter) { PrettyPrinter printer = new PrettyPrinter(); printWriter.printString(type.accept(printer)); } private String prefix = ""; private PrettyPrinter() { super.setExpressionVisitor(this); super.setTypeVisitor(this); } /** * Indent the prefix to indicate that a printable block * of nodes has been entered. */ private void indent() { this.prefix += " "; } /** * Print a node in the console. The node its toString * method will be printed first, followed the the type * of the node, separated by a colon. * * @param node - The node to print. */ private String printNode(QLNode node) { String type = node.getClass().getSimpleName(); // Strip the string until only the name of the node is left. String nodeString = node.toString().split("\\(")[0]; return prefix + ("└── ") + nodeString + " : " + type + "\n"; } /** * Unindent the prefix. This happens when a block of * printable nodes has been printed and the function * exits. */ private void unindent() { this.prefix = this.prefix.substring(0, this.prefix.length() - 3); } @Override public String visit(BooleanLiteral booleanNode) { return printNode(booleanNode); } @Override public String visit(Checkbox checkboxNode) { return printNode(checkboxNode); } @Override public String visit(Color color) { StringBuilder colorString = new StringBuilder(printNode(color)); indent(); colorString.append(color.getLiteral().accept(this)); unindent(); return colorString.toString(); } @Override public String visit(Default defaultType) { return printNode(defaultType); } @Override public String visit(DefaultStyle defaultNode) { StringBuilder defaultStyleString = new StringBuilder(printNode(defaultNode)); indent(); defaultStyleString.append(defaultNode.getType().accept(this)); defaultStyleString.append(defaultNode.getStyleProperties().accept(this)); unindent(); return defaultStyleString.toString(); } @Override public String visit(DefaultWidget defaultNode) { StringBuilder defaultWidgetString = new StringBuilder(printNode(defaultNode)); indent(); defaultWidgetString.append(defaultNode.getType().accept(this)); defaultWidgetString.append(defaultNode.getWidget().accept(this)); unindent(); return defaultWidgetString.toString(); } @Override public String visit(Dropdown dropdownNode) { StringBuilder dropdownString = new StringBuilder(printNode(dropdownNode)); indent(); dropdownString.append(dropdownNode.getFirstValue().accept(this)); dropdownString.append(dropdownNode.getSecondValue().accept(this)); unindent(); return dropdownString.toString(); } @Override public String visit(FloatLiteral floatNode) { return printNode(floatNode); } @Override public String visit(Font font) { StringBuilder fontString = new StringBuilder(printNode(font)); indent(); fontString.append(font.getLiteral().accept(this)); unindent(); return fontString.toString(); } @Override public String visit(FontSize fontSize) { StringBuilder fontSizeString = new StringBuilder(printNode(fontSize)); indent(); fontSizeString.append(fontSize.getLiteral().accept(this)); unindent(); return fontSizeString.toString(); } @Override public String visit(Height height) { StringBuilder heightString = new StringBuilder(printNode(height)); indent(); heightString.append(height.getLiteral().accept(this)); unindent(); return heightString.toString(); } @Override public String visit(Identifier identNode) { return printNode(identNode); } @Override public String visit(IntegerLiteral intNode) { return printNode(intNode); } @Override public String visit(Page pageNode) { StringBuilder pageString = new StringBuilder(printNode(pageNode)); indent(); pageString.append(pageNode.getIdentifier().accept(this)); pageString.append(pageNode.getStatements().accept(this)); unindent(); return pageString.toString(); } @Override public String visit(QLBoolean booleanNode) { return printNode(booleanNode); } @Override public String visit(QLError qlError) { return printNode(qlError); } @Override public String visit(QLFloat floatNode) { return printNode(floatNode); } @Override public String visit(QLForm formNode) { return printNode(formNode); } @Override public String visit(QLInteger intNode) { return printNode(intNode); } @Override public String visit(QLNumeric numericNode) { return printNode(numericNode); } @Override public String visit(Block blockNode) { StringBuilder blockString = new StringBuilder(printNode(blockNode)); indent(); for(Statement statement : blockNode.getStatements()) { blockString.append(statement.accept(this)); } unindent(); return blockString.toString(); } @Override public String visit(QLString stringNode) { return printNode(stringNode); } @Override public String visit(Question questionNode) { StringBuilder questionString = new StringBuilder(printNode(questionNode)); indent(); questionString.append(questionNode.getIdentifier().accept(this)); questionString.append(questionNode.getWidget().accept(this)); unindent(); return questionString.toString(); } @Override public String visit(RadioButton radioNode) { StringBuilder radioString = new StringBuilder(printNode(radioNode)); indent(); radioString.append(radioNode.getFirstValue().accept(this)); radioString.append(radioNode.getSecondValue().accept(this)); unindent(); return radioString.toString(); } @Override public String visit(Section sectionNode) { StringBuilder sectionString = new StringBuilder(printNode(sectionNode)); indent(); sectionString.append(sectionNode.getHeader().accept(this)); sectionString.append(sectionNode.getStatements().accept(this)); unindent(); return sectionString.toString(); } @Override public String visit(Slider sliderNode) { StringBuilder sliderString = new StringBuilder(printNode(sliderNode)); indent(); sliderString.append(sliderNode.getFirstValue().accept(this)); sliderString.append(sliderNode.getSecondValue().accept(this)); unindent(); return sliderString.toString(); } @Override public String visit(Spinbox spinnerNode) { return printNode(spinnerNode); } @Override public String visit(StringLiteral stringNode) { return printNode(stringNode); } @Override public String visit(StyleProperties styleNode) { StringBuilder styleString = new StringBuilder(printNode(styleNode)); indent(); for(Property property : styleNode.getProperties().values()) { styleString.append(property.accept(this)); } unindent(); return styleString.toString(); } @Override public String visit(Stylesheet stylesheetNode) { StringBuilder stylesheetString = new StringBuilder(printNode(stylesheetNode)); indent(); stylesheetString.append(stylesheetNode.getIdentifier().accept(this)); stylesheetString.append(stylesheetNode.getPages().accept(this)); unindent(); return stylesheetString.toString(); } @Override public String visit(TextField textFieldNode) { return printNode(textFieldNode); } @Override public String visit(Widget widgetNode) { StringBuilder widgetString = new StringBuilder(printNode(widgetNode)); indent(); widgetString.append(widgetNode.getStyleRules().accept(this)); widgetString.append(widgetNode.getWidgetType().accept(this)); unindent(); return widgetString.toString(); } @Override public String visit(Width width) { StringBuilder widthString = new StringBuilder(printNode(width)); indent(); widthString.append(width.getLiteral().accept(this)); unindent(); return widthString.toString(); } }