/* * Copyright (c) 2007 BUSINESS OBJECTS SOFTWARE LIMITED * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * * Neither the name of Business Objects nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ /* * SourceModelCodeFormatter.java * Created: Feb 6, 2007 * By: rcypher */ package org.openquark.cal.compiler; import java.math.BigInteger; import java.util.ArrayList; import java.util.Collections; import java.util.Iterator; import java.util.List; import java.util.Set; import org.openquark.cal.compiler.SourceModel.ArgBindings; import org.openquark.cal.compiler.SourceModel.CALDoc; import org.openquark.cal.compiler.SourceModel.Constraint; import org.openquark.cal.compiler.SourceModel.Expr; import org.openquark.cal.compiler.SourceModel.TypeExprDefn.Function; import org.openquark.cal.compiler.SourceModel.Name; import org.openquark.cal.compiler.SourceModel.FieldPattern; import org.openquark.cal.compiler.SourceModel.FunctionDefn; import org.openquark.cal.compiler.SourceModel.FunctionTypeDeclaration; import org.openquark.cal.compiler.SourceModel.Import; import org.openquark.cal.compiler.SourceModel.InstanceDefn; import org.openquark.cal.compiler.SourceModel.LocalDefn; import org.openquark.cal.compiler.SourceModel.ModuleDefn; import org.openquark.cal.compiler.SourceModel.Parameter; import org.openquark.cal.compiler.SourceModel.Pattern; import org.openquark.cal.compiler.SourceModel.SourceElement; import org.openquark.cal.compiler.SourceModel.TypeClassDefn; import org.openquark.cal.compiler.SourceModel.TypeConstructorDefn; import org.openquark.cal.compiler.SourceModel.TypeExprDefn; import org.openquark.cal.compiler.SourceModel.TypeSignature; import org.openquark.cal.compiler.SourceModel.Expr.Associativity; import org.openquark.cal.compiler.SourceModel.InstanceDefn.InstanceMethod; import org.openquark.cal.compiler.SourceModel.TypeClassDefn.ClassMethodDefn; import org.openquark.cal.module.Cal.Core.CAL_Prelude; import org.openquark.cal.util.ArrayStack; /** * This class can be used to generated formatted CAL source from a SourceModel * instance. * * @author rcypher, mbyne * */ public final class SourceModelCodeFormatter { /** System Line separator. */ private static final String EOL = System.getProperty("line.separator"); /** this adds debugging information which shows the formatting combinators */ final private static boolean SHOW_DEBUG_LABELS = false; /** these are the default options for formatting */ final public static Options DEFAULT_OPTIONS = new OptionsBuilder().build(); /** this class is used to iterate through the embellishments */ final private static class EmbellishmentSource { final private List<SourceEmbellishment> embellishments; Iterator<SourceEmbellishment> it; SourceEmbellishment current; /** construct embellishment source from a list of embellishments */ EmbellishmentSource(List<SourceEmbellishment> embellishments) { this.embellishments = embellishments; it = this.embellishments.iterator(); if (it.hasNext()) { current = it.next(); } else { current = null; } } /** the current embellishment, or null if there are none left*/ SourceEmbellishment current() { return current; } /** true if there are no more embellishments */ boolean isEmpty() { return current == null; } /** advance to the next embellishment */ SourceEmbellishment next() { if (it.hasNext()) { current = (SourceEmbellishment) it.next(); } else { current = null; } return current; } } /** * Entry point for generating formatted CAL code from a source model * element. The text is appended to the supplied string builder. * * @param element - * the source model element * @param stringBuilder - * the string builder to append the source to. * @param options - * the CALFormatter options to use in generating the CAL source */ final public static void formatCode(SourceModel.SourceElement element, StringBuilder stringBuilder, Options options, List<SourceEmbellishment> embellishments) { if (element == null) { throw new NullPointerException("Argument element cannot be null."); } if (stringBuilder == null) { throw new NullPointerException( "Argument stringBuilder cannot be null."); } if (options == null) { throw new NullPointerException("Argument options cannot be null."); } if (embellishments == null) { throw new NullPointerException( "Argument embellishments cannot be null."); } SourceTextNodeBuilder f = new SourceTextNodeBuilder(new EmbellishmentSource(embellishments)); element.accept(f, options); SourceTextNode node = f.stack.peek(); node.toFormattedText(stringBuilder, 0, 0, options); } /** * Formats code at specified indent level. * * @param element * source element to format * @param stringBuilder * buffer to write formatted code to * @param options * options for formatting * @param embellishments * embellishments to include * @param indentLevel * the indent level to start at */ final static void formatCode(SourceModel.SourceElement element, StringBuilder stringBuilder, Options options, List<SourceEmbellishment> embellishments, int indentLevel) { if (element == null) { throw new NullPointerException("Argument element cannot be null."); } if (stringBuilder == null) { throw new NullPointerException( "Argument stringBuilder cannot be null."); } if (options == null) { throw new NullPointerException("Argument options cannot be null."); } if (embellishments == null) { throw new NullPointerException( "Argument embellishments cannot be null."); } if (indentLevel < 0) { throw new IllegalArgumentException("Indent level must be >= 0"); } SourceTextNodeBuilder f = new SourceTextNodeBuilder(new EmbellishmentSource(embellishments)); element.accept(f, options); SourceTextNode node = f.stack.peek(); node.toFormattedText(stringBuilder, indentLevel / options.tabWidth, 0, options); } /** * Entry point for generating formatted CAL code from a source model * element, returns the formated code. * * @param element - * the source model element * @param options - * the CALFormatter options to use in generating the CAL source * @return a String of CAL source */ final public static String formatCode(SourceModel.SourceElement element, Options options, List<SourceEmbellishment> embellishments) { StringBuilder sb = new StringBuilder(); if (options.getKeepParen()) { formatCode(element, sb, options, embellishments); } else { formatCode(element.accept(new SourceModelParenStripper(), null), sb, options, embellishments); } return sb.toString().replaceAll(" +" + EOL, EOL); } /** * Entry point for generating formatted CAL code from a source model * element, returns the formated code. The code is formatted at the * specified indent level - this is useful for formatting parts of * a module. * * @param element * the source model element * @param options * the CALFormatter options to use in generating the CAL source * @return a String of CAL source */ public static String formatCode(SourceModel.SourceElement element, Options options, List<SourceEmbellishment> embellishments, int indentLevel) { StringBuilder sb = new StringBuilder(); if (options.getKeepParen()) { formatCode(element, sb, options, embellishments, indentLevel); } else { formatCode(element.accept(new SourceModelParenStripper(), null), sb, options, embellishments, indentLevel); } return sb.toString().replaceAll(" +" + EOL, EOL); } /** * Emit an indent where the indent level is directly specified. * * @param sb * @param indentLevel * @param options * @return StringBuilder sb, returned for convenience. */ private static StringBuilder emitIndent(StringBuilder sb, int indentLevel, Options options) { for (int i = 0; i < indentLevel; i++) { sb.append(options.useSpacesForTabs ? options.indentString : "\t"); } return sb; } /** * Emit a line feed. This compresses the vertical space so that there can * not be more than one consecutive blank lines. * * @param sb * the StringBuilder to which to add the EOL. */ private static void emitEOL(StringBuilder sb) { int lastIndex = sb.length(); if (sb.length() < EOL.length() * 2 || !sb.subSequence(lastIndex - EOL.length() * 2, lastIndex) .equals(EOL + EOL)) { sb.append(EOL); } } /** * Emit an indent, some text, and an EOL. * * @param sb * the StringBuilder to which to add an indent. * @param indent * the number of indents to add. * @param options * @param text * the text to add. */ private static void emitIndentedText(StringBuilder sb, int indent, String text, Options options) { emitIndent(sb, indent, options); sb.append(text + EOL); } /** * The options builder is used to build formating options * * @author Magnus Byne */ public static final class OptionsBuilder { /** the line length for the Options that are built */ private int lineLength = 80; private boolean keepParen = true; /** * If this is true non-CALDoc comments will be wrapped */ private boolean wordWrapNonCalDocComments = true; /** create default options builder */ public OptionsBuilder() { } /** * Set the line width. In general formatted source will not exceed this * amount, but certain comments and quoted strings, very long * identifiers and very heavily nested code may do so */ final public OptionsBuilder withLineLength(int lineWidth) { this.lineLength = lineWidth; return this; } /** * If keepParen is true all the parentheses from the original source * will be preserved. Otherwise the formatted code will contain the * minimum necessary. */ final public OptionsBuilder withKeepParentheses(boolean keep) { keepParen = keep; return this; } /** if this is true non CALDoc comments will be * formatted to fit the line length. Note that CALDoc comments are always * formatted. */ final public OptionsBuilder withFormatComments(boolean format) { wordWrapNonCalDocComments = format; return this; } /** create the new options */ final public Options build() { return new Options(lineLength, keepParen, wordWrapNonCalDocComments); } } /** * The settings used to generate formatted CAL source code from a source * model instance. * * @author rcypher * */ public static final class Options { /** * Maximum number of columns to print before wrapping lines. In some * cases lines may exceed this, for example comments are not currently * wrapped, and quoted strings are not broken, identifier names could * exceed the line length, etc */ final private int maxLineLength; /** * When splitting a binary operator expression across two lines place * the operator at the beginning of the second line. */ final private boolean operatorsAtBeginningOfLine = true; /** * When this is true all of the parens from the original source * expressions will be preserved. If it is is false the minimum number * of parens will appear in the formated source. */ final private boolean keepParen; /** * If true than the using clauses in an import statement will be grouped * so that there is only a single clause for each type, i.e. function, * typeclass, etc. */ final private boolean groupImportUsingClauses = false; /** * this controls the maximum bracket nesting before a line will be split */ final private int maxNestingDepthOnOneLine = 4; /** * A set of functions that should appear on their own line when used in * infix notation - typically this just includes seq */ final private Set<String> infixFunctionsOnSeperateLine = Collections .singleton(CAL_Prelude.Functions.seq.getUnqualifiedName()); /** * If true than the items in a using clause will be sorted * alphabetically. */ final private boolean sortImportUsingClauseItems = false; /** * If true spaces will be used for indenting otherwise tab characters. */ final private boolean useSpacesForTabs = true; /** * Width of an individual tab. */ final private int tabWidth = 4; /** * String used for putting tabs at the beginning of a line of code. */ final private String indentString = " "; /** if this is true non caldoc comments will be word wrapped */ final private boolean wordWrapNonCalDocComments; /** * Create an options instance with specified line width and keepParen */ private Options(int lineWidth, boolean keepParen, boolean wordWrapNonCalDocComments) { maxLineLength = lineWidth; this.keepParen = keepParen; this.wordWrapNonCalDocComments = wordWrapNonCalDocComments; } /** * Creates a new options with restricted max columns * this is used for nested formatting - e.g. formatting * caldoc within a separate formatter. * @param maxColumns * @return the options with new max line length */ Options withRestrictedLineLength(int maxColumns) { if (maxColumns >= maxLineLength || maxColumns < 1) { throw new IllegalArgumentException("The maxColumns parameter is invalid"); } return new Options(maxColumns, keepParen, wordWrapNonCalDocComments); } public String toString() { StringBuilder sb = new StringBuilder(); sb.append("Options:" + EOL); sb.append("maxColumns=" + maxLineLength + EOL); sb.append("tabWidth=" + tabWidth + EOL); sb.append("useSpacesForTabs=" + useSpacesForTabs + EOL); sb.append("sortImportUsingClauseItems=" + sortImportUsingClauseItems + EOL); sb.append("operatorsAtBeginningOfLine=" + operatorsAtBeginningOfLine + EOL); sb.append("groupImportUsingClauses=" + groupImportUsingClauses + EOL); sb.append("infixFunctions formated on separate lines=" + infixFunctionsOnSeperateLine + EOL); sb.append("maxNestingDepthOnOneLine=" + maxNestingDepthOnOneLine + EOL); sb.append("keepParen=" + keepParen + EOL); sb.append("wordWrapNonCalDocComments=" + wordWrapNonCalDocComments + EOL); return sb.toString(); } /** * @return the groupImportUsingClauses */ public boolean isGroupImportUsingClauses() { return groupImportUsingClauses; } /** * @return the tabWidth */ public int getTabWidth() { return tabWidth; } /** * @return keepParen */ public boolean getKeepParen() { return keepParen; } /** true iff non cal doc comments should be wrapped */ public boolean getWordWrapNonCalDocComments() { return wordWrapNonCalDocComments; } /** * true iff the given function should appear on its own line, this is * the convention for seq * * @param function * @return true iff the given function should appear on its own line */ public boolean putInfixFunctionOnSeperateLine(String function) { return infixFunctionsOnSeperateLine.contains(function); } /** return the string used for indenting*/ public String getIndentString() { return indentString; } /** * Get the maximum number of columns before wrapping a line. NOTE: Some * source model elements may ignore this. * * @return the maxColumns */ public int getMaxColumns() { return maxLineLength; } /** * Returns true if the setting indicates that when splitting a binary * operator expression the operator should appear at the beginning of * the second line. * * @return the operatorsAtBeginningOfLine */ public boolean isOperatorsAtBeginningOfLine() { return operatorsAtBeginningOfLine; } /** * Get the value of the flag indicating that items in an import using * clause should be sorted alphabetically. * * @return the sortImportUsingClauseItems */ public boolean isSortImportUsingClauseItems() { return sortImportUsingClauseItems; } } /** * This class is used to build up a tree of SourceTextNode instances from a * source model element. The SourceTextNode tree can then be used to * generate formatted source where the formating/layout varies based on the * context in which the source occurs. * * @author rcypher * */ public static final class SourceTextNodeBuilder extends SourceModelTraverser<Options, Void> { /** * Stack used to keep track of the 'current' node. */ private final ArrayStack<SourceTextNode> stack = ArrayStack.make(); /** * the embellishments used to augment the source model */ private final EmbellishmentSource embellishments; /** * Create a new SourceTextNodeBuilder which will use the supplied * options. */ SourceTextNodeBuilder(EmbellishmentSource embellishments) { stack.push(new SourceTextNode( SourceTextNode.FormatStyle.CHILDREN_AT_SAME_LEVEL)); this.embellishments = embellishments; } /** * This adds a new node as a child of the node on the top of the stack. * It checks for embellishments and adds extra nodes if needed to * include them. * * Embellishments are not stored in the source model as it is hard to * associate them with particular elements. For example comments are * often used as section breaks. * * @param element * @param node * @return the original SourceTextNode that was passed */ private SourceTextNode addNodeForSourceElementWithEmbellishments( SourceElement element, SourceTextNode node) { return addNodeForSourceElementWithEmbellishments(element .getSourceRange(), node); } /** * This adds a new node as a child of the node on the top of the stack. * It checks for embellishments and adds extra nodes if needed to * include them. * * Embellishments are not stored in the source model as it is hard to * associate them with particular elements. For example comments are * often used as section breaks. * * @param range * of the source element to embellish * @param node * @return the original SourceTextNode that was passed */ private SourceTextNode addNodeForSourceElementWithEmbellishments( SourceRange range, SourceTextNode node) { // is there a comment that appears before this node SourceTextNode embellishmentNode = null; // add embellishments that come before this source element while (!embellishments.isEmpty() && range != null && embellishments.current().getSourceRange().getStartLine() < range .getStartLine()) { if (embellishments.current() instanceof SourceEmbellishment.BlankLine) { if (embellishmentNode == null) { embellishmentNode = new SourceTextNode( "", SourceTextNode.FormatStyle.CHILDREN_AT_SAME_LEVEL); embellishmentNode.setForcedBreak(); } embellishmentNode.addChild(new SourceTextNode("", SourceTextNode.FormatStyle.EMBELLISHMENT)); } else { if (embellishmentNode == null) { embellishmentNode = new SourceTextNode( SourceTextNode.FormatStyle.CHILDREN_AT_SAME_LEVEL); embellishmentNode.setForcedBreak(); } embellishmentNode.addChild(new SourceTextNode( embellishments.current().getText().replaceAll( "(\r\n)|\n|\r", EOL), SourceTextNode.FormatStyle.EMBELLISHMENT)); } embellishments.next(); } // add embellishments that come on the same line as the source // element if (!embellishments.isEmpty() && (embellishments.current() instanceof SourceEmbellishment.SingleLineComment || embellishments .current() instanceof SourceEmbellishment.MultiLineComment) && range != null && embellishments.current().getSourceRange().getStartLine() == range .getStartLine()) { SourceTextNode top = new SourceTextNode( SourceTextNode.FormatStyle.CHILDREN_AT_SAME_LEVEL); top.setForcedBreak(); top.addChild(new SourceTextNode( SourceTextNode.FormatStyle.CODE_FOLLOWED_BY_COMMENT)); top.getNthChild(0).addChild(node); top.getNthChild(0).addChild( new SourceTextNode(embellishments.current().getText() .replaceAll("(\r\n)|\n|\r", EOL), SourceTextNode.FormatStyle.EMBELLISHMENT)); embellishments.next(); node = top; } if (embellishmentNode == null) { stack.peek().addChild(node); } else { SourceTextNode newRoot = new SourceTextNode( SourceTextNode.FormatStyle.COMMENTS_FOLLOWED_BY_CODE); ((SourceTextNode)stack.peek()).addChild(newRoot); newRoot.addChild(embellishmentNode); newRoot.addChild(node); } return node; } @Override protected Void visit_CALDoc_Comment_Helper(CALDoc.Comment comment, Options options) { formatCALDocComment(comment); return null; } @Override public Void visit_Expr_Parenthesized(Expr.Parenthesized parenthesized, Options options) { SourceTextNode node = new SourceTextNode( SourceTextNode.FormatStyle.CHILDREN_AT_SAME_LEVEL); addNodeForSourceElementWithEmbellishments(parenthesized, node); stack.push(node); parenthesized.getExpression().accept(this, options); parenthesizeExpression(node.getNthChild(0)); stack.pop(); return null; } @Override public Void visit_Expr_Application(Expr.Application application, Options options) { SourceTextNode node = new SourceTextNode( SourceTextNode.FormatStyle.APPLICATION); addNodeForSourceElementWithEmbellishments(application, node); stack.push(node); // If the leftmost expression is an application we want to flatten // it. This is // because we want to treat '(compose a b) c' as 'compose a b c'. List<Expr> children = new ArrayList<Expr>(); for (int i = 0, nExprs = application.getNExpressions(); i < nExprs; ++i) { children.add(application.getNthExpression(i)); } for (Expr child0 = children.get(0); child0 instanceof Expr.Application;) { children.remove(0); Expr.Application childApp = (Expr.Application) child0; for (int i = 0, n = childApp.getNExpressions(); i < n; ++i) { children.add(i, childApp.getNthExpression(i)); } child0 = children.get(0); } for (int i = 0, nExprs = children.size(); i < nExprs; ++i) { Expr expr = children.get(i); expr.accept(this, options); if (expr.precedenceLevel() <= application.precedenceLevel() && (i != 0 || expr.precedenceLevel() != application .precedenceLevel())) { parenthesizeExpression(node .getNthChild(node.getNChildren() - 1)); } } stack.pop(); return null; } @Override public Void visit_Expr_DataCons(Expr.DataCons cons, Options options) { return super.visit_Expr_DataCons(cons, options); } @Override public Void visit_Expr_Var(Expr.Var var, Options options) { SourceModel.verifyArg(var, "var"); var.getVarName().accept(this, options); return null; } @Override public Void visit_Expr_Let(Expr.Let let, Options options) { SourceTextNode root = new SourceTextNode( SourceTextNode.FormatStyle.CHILDREN_AT_SAME_LEVEL); root.setForcedBreak(); addNodeForSourceElementWithEmbellishments(let, root); SourceTextNode letNode = new SourceTextNode( "let", SourceTextNode.FormatStyle.CHILDREN_IN_ONE_LEVEL); letNode.setForcedBreak(); root.addChild(letNode); stack.push(letNode); final int nLocalDefns = let.getNLocalDefinitions(); for (int i = 0; i < nLocalDefns; i++) { LocalDefn localDefn = let.getNthLocalDefinition(i); localDefn.accept(this, options); } stack.pop(); SourceTextNode inNode = new SourceTextNode( "in", SourceTextNode.FormatStyle.CHILDREN_IN_ONE_LEVEL); inNode.setForcedBreak(); root.addChild(inNode); stack.push(inNode); let.getInExpr().accept(this, options); stack.pop(); return null; } @Override public Void visit_Expr_Case(Expr.Case caseExpr, Options options) { SourceTextNode rootNode = new SourceTextNode( SourceTextNode.FormatStyle.CHILDREN_AT_SAME_LEVEL); rootNode.setForcedBreak(); addNodeForSourceElementWithEmbellishments(caseExpr, rootNode); stack.push(rootNode); SourceTextNode casePart = new SourceTextNode( SourceTextNode.FormatStyle.ALTERNATE_CHILDREN); rootNode.addChild(casePart); stack.push(casePart); casePart.addChild(new SourceTextNode("case", SourceTextNode.FormatStyle.ATOMIC)); caseExpr.getConditionExpr().accept(this, options); casePart.addChild(new SourceTextNode("of", SourceTextNode.FormatStyle.ATOMIC)); stack.pop(); final int nCaseAlts = caseExpr.getNCaseAlts(); for (int i = 0; i < nCaseAlts; i++) { caseExpr.getNthCaseAlt(i).accept(this, options); } stack.pop(); return null; } @Override public Void visit_Expr_Case_Alt_Default( Expr.Case.Alt.Default defaultAlt, Options options) { SourceTextNode rootNode = new SourceTextNode("_ ->", SourceTextNode.FormatStyle.CHILDREN_IN_ONE_LEVEL); addNodeForSourceElementWithEmbellishments(defaultAlt, rootNode); SourceTextNode altExprRoot = new SourceTextNode( SourceTextNode.FormatStyle.CHILDREN_AT_SAME_LEVEL); rootNode.addChild(altExprRoot); stack.push(altExprRoot); super.visit_Expr_Case_Alt_Default(defaultAlt, options); altExprRoot.addChild(new SourceTextNode(";", SourceTextNode.FormatStyle.ATOMIC)); stack.pop(); return null; } /** * Adds specified parens to a source text node. * @param exprRoot the root node of the source to be parenthesized */ private void parenthesizeExpression(SourceTextNode exprRoot) { parenthesizeExpression(exprRoot, "(", ")"); } /** * Adds specified parens to a source text node. * @param exprRoot the root node of the source to be parenthesized * @param open the opening paren * @param close the closing paren */ private void parenthesizeExpression(SourceTextNode exprRoot, String open, String close) { // we have a special case for applications, so that the function // name is placed on the same line as the open paren if (exprRoot.formatStyle == SourceTextNode.FormatStyle.APPLICATION && !exprRoot.startsWithBracket()) { exprRoot.prefixText(open); exprRoot.addChild(new SourceTextNode(close, SourceTextNode.FormatStyle.ATOMIC)); exprRoot.formatStyle = SourceTextNode.FormatStyle.INNER_CHILDREN_IN_ONE_LEVEL; } else { SourceTextNode newExprRoot2 = new SourceTextNode(exprRoot .getThisText(), exprRoot.getFormatType()); newExprRoot2.forcedBreak = exprRoot.forcedBreak; exprRoot.forcedBreak = false; for (int i = 0, n = exprRoot.getNChildren(); i < n; ++i) { newExprRoot2.addChild(exprRoot.getNthChild(i)); } while (exprRoot.getNChildren() > 0) { exprRoot.removeChild(0); } exprRoot.myText = ""; exprRoot.addChild(new SourceTextNode(open, SourceTextNode.FormatStyle.ATOMIC)); exprRoot.addChild(newExprRoot2); exprRoot.addChild(new SourceTextNode(close, SourceTextNode.FormatStyle.ATOMIC)); exprRoot.formatStyle = SourceTextNode.FormatStyle.INNER_CHILDREN_IN_ONE_LEVEL; } } @Override public Void visit_Expr_Case_Alt_UnpackTuple( Expr.Case.Alt.UnpackTuple tuple, Options options) { SourceTextNode rootNode = new SourceTextNode( SourceTextNode.FormatStyle.CHILDREN_AT_SAME_LEVEL); addNodeForSourceElementWithEmbellishments(tuple, rootNode); stack.push(rootNode); SourceTextNode tupleRoot = new SourceTextNode( SourceTextNode.FormatStyle.CHILDREN_AT_SAME_LEVEL); rootNode.addChild(tupleRoot); stack.push(tupleRoot); for (int i = 0, nPatterns = tuple.getNPatterns(); i < nPatterns; i++) { tuple.getNthPattern(i).accept(this, options); } stack.pop(); for (int i = 0, n = tupleRoot.getNChildren() - 1; i < n; ++i) { tupleRoot.getNthChild(i).suffixText(","); } parenthesizeExpression(tupleRoot); SourceTextNode arrow = new SourceTextNode("->", SourceTextNode.FormatStyle.CHILDREN_IN_ONE_LEVEL); rootNode.addChild(arrow); stack.push(arrow); tuple.getAltExpr().accept(this, options); stack.pop(); arrow.addChild(new SourceTextNode(";", SourceTextNode.FormatStyle.ATOMIC)); stack.pop(); return null; } @Override public Void visit_Expr_Case_Alt_UnpackUnit( Expr.Case.Alt.UnpackUnit unit, Options options) { SourceTextNode rootNode = new SourceTextNode("() ->", SourceTextNode.FormatStyle.CHILDREN_IN_ONE_LEVEL); addNodeForSourceElementWithEmbellishments(unit, rootNode); SourceTextNode altExprRoot = new SourceTextNode( SourceTextNode.FormatStyle.CHILDREN_AT_SAME_LEVEL); rootNode.addChild(altExprRoot); stack.push(altExprRoot); super.visit_Expr_Case_Alt_UnpackUnit(unit, options); altExprRoot.addChild(new SourceTextNode(";", SourceTextNode.FormatStyle.ATOMIC)); stack.pop(); return null; } @Override public Void visit_Expr_Case_Alt_UnpackDataCons( Expr.Case.Alt.UnpackDataCons cons, Options options) { SourceTextNode rootNode = new SourceTextNode( SourceTextNode.FormatStyle.FIRST_CHILD_AT_LEVEL); addNodeForSourceElementWithEmbellishments(cons, rootNode); stack.push(rootNode); SourceTextNode dcRoot = new SourceTextNode( SourceTextNode.FormatStyle.CHILDREN_AT_SAME_LEVEL); rootNode.addChild(dcRoot); stack.push(dcRoot); SourceTextNode dcRoot2 = new SourceTextNode( SourceTextNode.FormatStyle.CHILDREN_AT_SAME_LEVEL); dcRoot.addChild(dcRoot2); stack.push(dcRoot2); for (int i = 0, nDataConsNames = cons.getNDataConsNames(); i < nDataConsNames; i++) { cons.getNthDataConsName(i).accept(this, options); } if (dcRoot2.getNChildren() > 1 || cons.getParenthesized()) { for (int i = 1, n = dcRoot2.getNChildren(); i < n; ++i) { dcRoot2.getNthChild(i).prefixText("| "); } parenthesizeExpression(dcRoot2); } stack.pop(); cons.getArgBindings().accept(this, options); stack.pop(); // SourceTextNode arrow = new SourceTextNode("->", // SourceTextNode.FormatStyle.CHILDREN_IN_ONE_LEVEL); // rootNode.addChild(arrow); rootNode.suffixText(" ->"); SourceTextNode exprRoot = new SourceTextNode( SourceTextNode.FormatStyle.CHILDREN_AT_SAME_LEVEL); rootNode.addChild(exprRoot); stack.push(exprRoot); cons.getAltExpr().accept(this, options); stack.pop(); exprRoot.addChild(new SourceTextNode(";", SourceTextNode.FormatStyle.ATOMIC)); stack.pop(); return null; } @Override public Void visit_ArgBindings_Matching( ArgBindings.Matching argBindings, Options options) { SourceTextNode root = new SourceTextNode( SourceTextNode.FormatStyle.CHILDREN_AT_SAME_LEVEL); addNodeForSourceElementWithEmbellishments(argBindings, root); stack.push(root); super.visit_ArgBindings_Matching(argBindings, options); for (int i = 0, n = root.getNChildren() - 1; i < n; ++i) { root.getNthChild(i).suffixText(","); } parenthesizeExpression(root, "{", "}"); stack.pop(); return null; } @Override public Void visit_ArgBindings_Positional( ArgBindings.Positional argBindings, Options options) { if (argBindings.getNPatterns() == 0) { return null; } SourceTextNode root = new SourceTextNode( SourceTextNode.FormatStyle.CONCAT_CHILDREN_TO_LINE_END_INDENT_SECOND_LINE); addNodeForSourceElementWithEmbellishments(argBindings, root); stack.push(root); super.visit_ArgBindings_Positional(argBindings, options); stack.pop(); return null; } @Override public Void visit_Expr_Case_Alt_UnpackInt( Expr.Case.Alt.UnpackInt intAlt, Options options) { SourceTextNode root = new SourceTextNode( SourceTextNode.FormatStyle.FIRST_CHILD_AT_LEVEL); addNodeForSourceElementWithEmbellishments(intAlt, root); stack.push(root); BigInteger[] bigIntValues = intAlt.getIntValues(); StringBuilder sb = new StringBuilder(); if (bigIntValues.length == 1) { sb.append(bigIntValues[0]); sb.append(" ->"); } else { sb.append('('); for (int i = 0; i < bigIntValues.length; i++) { if (i > 0) { sb.append(" | "); } sb.append(bigIntValues[i]); } sb.append(") ->"); } root.addChild(new SourceTextNode(sb.toString(), SourceTextNode.FormatStyle.ATOMIC)); SourceTextNode exprRoot = new SourceTextNode( SourceTextNode.FormatStyle.CHILDREN_AT_SAME_LEVEL); root.addChild(exprRoot); stack.push(exprRoot); super.visit_Expr_Case_Alt_UnpackInt(intAlt, options); exprRoot.addChild(new SourceTextNode(";", SourceTextNode.FormatStyle.ATOMIC)); stack.pop(); stack.pop(); return null; } @Override public Void visit_Expr_Case_Alt_UnpackChar( Expr.Case.Alt.UnpackChar charAlt, Options options) { SourceTextNode root = new SourceTextNode( SourceTextNode.FormatStyle.FIRST_CHILD_AT_LEVEL); addNodeForSourceElementWithEmbellishments(charAlt, root); stack.push(root); StringBuilder sb = new StringBuilder(); char[] charValues = charAlt.getCharValues(); if (charValues.length == 1) { sb.append(StringEncoder.encodeChar(charValues[0])); sb.append(" ->"); } else { sb.append('('); for (int i = 0; i < charValues.length; i++) { if (i > 0) { sb.append(" | "); } sb.append(StringEncoder.encodeChar(charValues[i])); } sb.append(") ->"); } root.addChild(new SourceTextNode(sb.toString(), SourceTextNode.FormatStyle.ATOMIC)); SourceTextNode exprRoot = new SourceTextNode( SourceTextNode.FormatStyle.CHILDREN_AT_SAME_LEVEL); root.addChild(exprRoot); stack.push(exprRoot); super.visit_Expr_Case_Alt_UnpackChar(charAlt, options); exprRoot.addChild(new SourceTextNode(";", SourceTextNode.FormatStyle.ATOMIC)); stack.pop(); stack.pop(); return null; } @Override public Void visit_Expr_Case_Alt_UnpackListCons( Expr.Case.Alt.UnpackListCons cons, Options options) { // Root node for the case alt SourceTextNode root = new SourceTextNode( SourceTextNode.FormatStyle.FIRST_CHILD_AT_LEVEL); addNodeForSourceElementWithEmbellishments(cons, root); stack.push(root); // Root node for the list left hand side. i.e. x : xs -> SourceTextNode listRoot = new SourceTextNode( SourceTextNode.FormatStyle.ATOMIC); root.addChild(listRoot); stack.push(listRoot); cons.getHeadPattern().accept(this, options); cons.getTailPattern().accept(this, options); stack.pop(); listRoot.getNthChild(0).suffixText(" :"); listRoot.getNthChild(1).suffixText(" ->"); // Root for the expression. SourceTextNode exprRoot = new SourceTextNode( SourceTextNode.FormatStyle.CHILDREN_AT_SAME_LEVEL); root.addChild(exprRoot); stack.push(exprRoot); cons.getAltExpr().accept(this, options); exprRoot.addChild(new SourceTextNode(";", SourceTextNode.FormatStyle.ATOMIC)); stack.pop(); stack.pop(); return null; } @Override public Void visit_Expr_Case_Alt_UnpackListNil( Expr.Case.Alt.UnpackListNil nil, Options options) { SourceTextNode rootNode = new SourceTextNode("[] ->", SourceTextNode.FormatStyle.CHILDREN_IN_ONE_LEVEL); addNodeForSourceElementWithEmbellishments(nil, rootNode); SourceTextNode altExprRoot = new SourceTextNode( SourceTextNode.FormatStyle.CHILDREN_AT_SAME_LEVEL); rootNode.addChild(altExprRoot); stack.push(altExprRoot); super.visit_Expr_Case_Alt_UnpackListNil(nil, options); altExprRoot.addChild(new SourceTextNode(";", SourceTextNode.FormatStyle.ATOMIC)); stack.pop(); return null; } @Override public Void visit_Expr_Case_Alt_UnpackRecord( Expr.Case.Alt.UnpackRecord record, Options options) { // Root node for the case alt SourceTextNode root = new SourceTextNode( SourceTextNode.FormatStyle.FIRST_CHILD_AT_LEVEL); addNodeForSourceElementWithEmbellishments(record, root); stack.push(root); // Root for the record. i.e. { s | x = a, y = b} -> SourceTextNode recordRoot = new SourceTextNode( SourceTextNode.FormatStyle.CHILDREN_AT_SAME_LEVEL); root.addChild(recordRoot); stack.push(recordRoot); if (record.getBaseRecordPattern() != null) { record.getBaseRecordPattern().accept(this, options); recordRoot.suffixText(" | "); } final int nFieldPatterns = record.getNFieldPatterns(); for (int i = 0; i < nFieldPatterns; i++) { record.getNthFieldPattern(i).accept(this, options); if (i < nFieldPatterns - 1) { recordRoot.getNthChild(recordRoot.getNChildren() - 1) .suffixText(","); } } stack.pop(); parenthesizeExpression(recordRoot, "{", "}"); recordRoot.suffixText(" ->"); // Root node for the Alt expr. SourceTextNode exprRoot = new SourceTextNode( SourceTextNode.FormatStyle.CHILDREN_AT_SAME_LEVEL); root.addChild(exprRoot); stack.push(exprRoot); record.getAltExpr().accept(this, options); exprRoot.addChild(new SourceTextNode(";", SourceTextNode.FormatStyle.ATOMIC)); stack.pop(); stack.pop(); return null; } @Override public Void visit_FieldPattern(FieldPattern pattern, Options options) { SourceTextNode root = new SourceTextNode(getFieldNameString(pattern.getFieldName()), SourceTextNode.FormatStyle.ATOMIC); addNodeForSourceElementWithEmbellishments(pattern, root); stack.push(root); super.visit_FieldPattern(pattern, options); stack.pop(); if (root.getNChildren() > 0) { root.getNthChild(0).prefixText("= "); } return null; } @Override public Void visit_Expr_Lambda(Expr.Lambda lambda, Options options) { SourceTextNode root = new SourceTextNode( SourceTextNode.FormatStyle.FIRST_CHILD_AT_LEVEL); addNodeForSourceElementWithEmbellishments(lambda, root); stack.push(root); SourceTextNode argRoot = new SourceTextNode( SourceTextNode.FormatStyle.CHILDREN_AT_SAME_LEVEL); root.addChild(argRoot); stack.push(argRoot); for (int i = 0, nParameters = lambda.getNParameters(); i < nParameters; i++) { lambda.getNthParameter(i).accept(this, options); } stack.pop(); argRoot.prefixText("\\"); argRoot.suffixText(" ->"); SourceTextNode exprRoot = new SourceTextNode( SourceTextNode.FormatStyle.CHILDREN_AT_SAME_LEVEL); root.addChild(exprRoot); stack.push(exprRoot); lambda.getDefiningExpr().accept(this, options); stack.pop(); // pop root stack.pop(); return null; } @Override public Void visit_Expr_If(Expr.If ifExpr, Options options) { SourceTextNode root = new SourceTextNode( SourceTextNode.FormatStyle.ALTERNATE_CHILDREN); root.setForcedBreak(); addNodeForSourceElementWithEmbellishments(ifExpr, root); stack.push(root); SourceTextNode ifPart = new SourceTextNode( SourceTextNode.FormatStyle.ALTERNATE_CHILDREN); root.addChild(ifPart); stack.push(ifPart); ifPart.addChild(new SourceTextNode("if", SourceTextNode.FormatStyle.ATOMIC)); ifExpr.getConditionExpr().accept(this, options); ifPart.addChild(new SourceTextNode("then", SourceTextNode.FormatStyle.ATOMIC)); stack.pop(); ifExpr.getThenExpr().accept(this, options); boolean elsePartIsIf = ifExpr.getElseExpr() instanceof Expr.If; if (!elsePartIsIf) { root.addChild(new SourceTextNode("else", SourceTextNode.FormatStyle.ATOMIC)); } ifExpr.getElseExpr().accept(this, options); if (elsePartIsIf) { root.getNthChild(root.getNChildren() - 1).prefixText("else "); } stack.pop(); return null; } @Override public Void visit_Expr_Literal_Num(Expr.Literal.Num num, Options options) { addNodeForSourceElementWithEmbellishments(num, new SourceTextNode( num.getNumValue().toString(), SourceTextNode.FormatStyle.ATOMIC)); return null; } @Override public Void visit_Expr_Literal_Double( Expr.Literal.Double doubleLiteral, Options options) { SourceModel.verifyArg(doubleLiteral, "doubleLiteral"); String valueString; if (java.lang.Double.isNaN(doubleLiteral.getDoubleValue())) { valueString = CAL_Prelude.Functions.isNotANumber .getQualifiedName(); } else if (doubleLiteral.getDoubleValue() == java.lang.Double.POSITIVE_INFINITY) { valueString = CAL_Prelude.Functions.positiveInfinity .getQualifiedName(); } else if (doubleLiteral.getDoubleValue() == java.lang.Double.NEGATIVE_INFINITY) { valueString = CAL_Prelude.Functions.negativeInfinity .getQualifiedName(); } else { valueString = java.lang.Double.toString(doubleLiteral .getDoubleValue()); } addNodeForSourceElementWithEmbellishments(doubleLiteral, new SourceTextNode(valueString, SourceTextNode.FormatStyle.ATOMIC)); return null; } @Override public Void visit_Expr_Literal_Float(Expr.Literal.Float floatLiteral, Options options) { SourceModel.verifyArg(floatLiteral, "floatLiteral"); StringBuilder sb = new StringBuilder(); sb.append("(").append( CAL_Prelude.Functions.toFloat.getQualifiedName()).append( " "); if (java.lang.Double.isNaN(floatLiteral.getFloatValue())) { sb .append(CAL_Prelude.Functions.isNotANumber .getQualifiedName()); } else if (floatLiteral.getFloatValue() == java.lang.Double.POSITIVE_INFINITY) { sb.append(CAL_Prelude.Functions.positiveInfinity .getQualifiedName()); } else if (floatLiteral.getFloatValue() == java.lang.Double.NEGATIVE_INFINITY) { sb.append(CAL_Prelude.Functions.negativeInfinity .getQualifiedName()); } else if (floatLiteral.getFloatValue() < 0) { sb.append("(") .append( java.lang.Double.toString(floatLiteral .getFloatValue())).append(")"); } else { sb.append(java.lang.Double.toString(floatLiteral .getFloatValue())); } sb.append(")"); addNodeForSourceElementWithEmbellishments(floatLiteral, new SourceTextNode(sb.toString(), SourceTextNode.FormatStyle.ATOMIC)); return null; } @Override public Void visit_Expr_Literal_Char(Expr.Literal.Char charLiteral, Options options) { SourceModel.verifyArg(charLiteral, "charLiteral"); addNodeForSourceElementWithEmbellishments( charLiteral, new SourceTextNode(StringEncoder.encodeChar(charLiteral .getCharValue()), SourceTextNode.FormatStyle.ATOMIC)); return null; } @Override public Void visit_Expr_Literal_StringLit(Expr.Literal.StringLit string, Options options) { SourceModel.verifyArg(string, "string"); addNodeForSourceElementWithEmbellishments(string, new SourceTextNode(StringEncoder.encodeString(string .getStringValue()), SourceTextNode.FormatStyle.ATOMIC)); return null; } @Override public Void visit_Expr_UnaryOp_Negate(Expr.UnaryOp.Negate negate, Options options) { SourceTextNode root = new SourceTextNode( SourceTextNode.FormatStyle.CHILDREN_AT_SAME_LEVEL); addNodeForSourceElementWithEmbellishments(negate, root); stack.push(root); super.visit_Expr_UnaryOp_Negate(negate, options); if (negate.getExpr().precedenceLevel() <= negate.precedenceLevel()) { parenthesizeExpression(root); } root.prefixText(negate.getOpText()); stack.pop(); return null; } @Override public Void visit_Expr_BinaryOp_BackquotedOperator_Var( Expr.BinaryOp.BackquotedOperator.Var backquotedOperator, Options options) { SourceTextNode root; if (options.putInfixFunctionOnSeperateLine(backquotedOperator .getOperatorVarExpr().getVarName().getUnqualifiedName())) { root = new SourceTextNode( SourceTextNode.FormatStyle.CHILDREN_AT_SAME_LEVEL); root.setForcedBreak(); } else { root = new SourceTextNode( SourceTextNode.FormatStyle.CHILDREN_AT_SAME_LEVEL); } // SourceTextNode addNodeForSourceElementWithEmbellishments(backquotedOperator, root); stack.push(root); SourceModel.verifyArg(backquotedOperator, "backquotedOperator"); backquotedOperator.getLeftExpr().accept(this, options); backquotedOperator.getOperatorVarExpr().accept(this, options); backquotedOperator.getRightExpr().accept(this, options); stack.pop(); if (!(backquotedOperator.getLeftExpr().precedenceLevel() > backquotedOperator .precedenceLevel() || backquotedOperator.associativity() == Associativity.LEFT && backquotedOperator.getLeftExpr().precedenceLevel() == backquotedOperator .precedenceLevel())) { // parenthesize if neccessary parenthesizeExpression(root.getNthChild(0)); } root.getNthChild(1).prefixText("`"); root.getNthChild(1).suffixText("`"); if (!(backquotedOperator.getRightExpr().precedenceLevel() > backquotedOperator .precedenceLevel() || backquotedOperator.associativity() == Associativity.RIGHT && backquotedOperator.getRightExpr().precedenceLevel() == backquotedOperator .precedenceLevel())) { // parenthesize if neccessary parenthesizeExpression(root.getNthChild(2)); } return null; } @Override public Void visit_Expr_BinaryOp_BackquotedOperator_DataCons( Expr.BinaryOp.BackquotedOperator.DataCons backquotedOperator, Options options) { SourceTextNode root = new SourceTextNode( SourceTextNode.FormatStyle.CHILDREN_AT_SAME_LEVEL); addNodeForSourceElementWithEmbellishments(backquotedOperator, root); stack.push(root); SourceModel.verifyArg(backquotedOperator, "backquotedOperator"); backquotedOperator.getLeftExpr().accept(this, options); backquotedOperator.getOperatorDataConsExpr().accept(this, options); backquotedOperator.getRightExpr().accept(this, options); stack.pop(); if (!(backquotedOperator.getLeftExpr().precedenceLevel() > backquotedOperator .precedenceLevel() || backquotedOperator.associativity() == Associativity.LEFT && backquotedOperator.getLeftExpr().precedenceLevel() == backquotedOperator .precedenceLevel())) { // parenthesize if necessary parenthesizeExpression(root.getNthChild(0)); } root.getNthChild(1).prefixText(" `"); root.getNthChild(1).suffixText("` "); if (!(backquotedOperator.getRightExpr().precedenceLevel() > backquotedOperator .precedenceLevel() || backquotedOperator.associativity() == Associativity.RIGHT && backquotedOperator.getRightExpr().precedenceLevel() == backquotedOperator .precedenceLevel())) { // parenthesize if not necessary parenthesizeExpression(root.getNthChild(2)); } return null; } @Override protected Void visit_Expr_BinaryOp_Helper(Expr.BinaryOp binop, Options options) { SourceTextNode root; root = new SourceTextNode( SourceTextNode.FormatStyle.CHILDREN_AT_SAME_LEVEL); addNodeForSourceElementWithEmbellishments(binop, root); stack.push(root); SourceModel.verifyArg(binop, "binop"); binop.getLeftExpr().accept(this, options); binop.getRightExpr().accept(this, options); stack.pop(); if (!(binop.getLeftExpr().precedenceLevel() > binop .precedenceLevel() || binop.associativity() == Associativity.LEFT && binop.getLeftExpr().precedenceLevel() == binop .precedenceLevel())) { // parenthesize if necessary parenthesizeExpression(root.getNthChild(0)); } if (!(binop.getRightExpr().precedenceLevel() > binop .precedenceLevel() || binop.associativity() == Associativity.RIGHT && binop.getRightExpr().precedenceLevel() == binop .precedenceLevel())) { // parenthesize if necessary parenthesizeExpression(root.getNthChild(1)); } // indent left based on precedence if ((binop.getLeftExpr() instanceof Expr.BinaryOp && ((Expr.BinaryOp) binop .getLeftExpr()).precedenceLevel() > binop.precedenceLevel())) { SourceTextNode node = root.getNthChild(0) .getNodeWithoutComment(); node.formatStyle = SourceTextNode.FormatStyle.FIRST_CHILD_AT_LEVEL; // SourceTextNode node= root.getNthChild(0); Expr.BinaryOp child = (Expr.BinaryOp) binop.getLeftExpr(); while (child.getLeftExpr() instanceof Expr.BinaryOp && ((Expr.BinaryOp) binop.getLeftExpr()).getOpText() .equals(child.getOpText())) { node = node.getNthChild(0).getNodeWithoutComment(); node.formatStyle = SourceTextNode.FormatStyle.FIRST_CHILD_AT_LEVEL; child = (Expr.BinaryOp) child.getLeftExpr(); } } // indent right based on precedence if ((binop.getRightExpr() instanceof Expr.BinaryOp && ((Expr.BinaryOp) binop .getRightExpr()).precedenceLevel() > binop .precedenceLevel())) { SourceTextNode node = root.getNthChild(1) .getNodeWithoutComment(); node.formatStyle = SourceTextNode.FormatStyle.FIRST_CHILD_AT_LEVEL; Expr.BinaryOp child = (Expr.BinaryOp) binop.getRightExpr(); while (child.getLeftExpr() instanceof Expr.BinaryOp && ((Expr.BinaryOp) binop.getRightExpr()).getOpText() .equals(child.getOpText())) { node = node.getNthChild(0).getNodeWithoutComment(); node.formatStyle = SourceTextNode.FormatStyle.FIRST_CHILD_AT_LEVEL; child = (Expr.BinaryOp) child.getLeftExpr(); } } if (options.isOperatorsAtBeginningOfLine()) { root.getNthChild(1).prefixText(binop.getOpText() + " "); } else { root.getNthChild(0).suffixText(" " + binop.getOpText()); } // here we pack the right expression into the same node if it has // the same operator // ie if the expression is a && b && c, we pack the right expression // (b && c) // into the a && node so that if it is broken all parts will be on // separate lines // otherwise a could be have "a" on one line and "&& b && c" could // be an one. We do this packing // to ensure that if a is on it's own line then b and c will have // their own lines too if (binop.getRightExpr() instanceof Expr.BinaryOp && ((Expr.BinaryOp) binop.getRightExpr()).getOpText() .equals(binop.getOpText())) { SourceTextNode right = root.getNthChild(1); root.removeChild(1); if (right.myText.length() > 0) { root.addChild(new SourceTextNode(right.myText, SourceTextNode.FormatStyle.ATOMIC)); } for (int i = 0, n = right.getNChildren(); i < n; i++) { root.addChild(right.getNthChild(i)); } } return null; } @Override public Void visit_Expr_Unit(Expr.Unit unit, Options options) { addNodeForSourceElementWithEmbellishments(unit, new SourceTextNode( "()", SourceTextNode.FormatStyle.ATOMIC)); return null; } @Override public Void visit_Expr_Tuple(Expr.Tuple tuple, Options options) { SourceTextNode root = new SourceTextNode( SourceTextNode.FormatStyle.CHILDREN_AT_SAME_LEVEL); addNodeForSourceElementWithEmbellishments(tuple, root); stack.push(root); super.visit_Expr_Tuple(tuple, options); for (int i = 0, n = root.getNChildren() - 1; i < n; ++i) { root.getNthChild(i).suffixText(","); } parenthesizeExpression(root); stack.pop(); return null; } @Override public Void visit_Expr_List(Expr.List list, Options options) { SourceTextNode root = new SourceTextNode( SourceTextNode.FormatStyle.CHILDREN_AT_SAME_LEVEL); addNodeForSourceElementWithEmbellishments(list, root); stack.push(root); super.visit_Expr_List(list, options); stack.pop(); for (int i = 0, n = root.getNChildren() - 1; i < n; i++) { root.getNthChild(i).suffixText(","); } parenthesizeExpression(root, "[", "]"); return null; } @Override public Void visit_Expr_Record(Expr.Record record, Options options) { SourceTextNode root = new SourceTextNode( SourceTextNode.FormatStyle.CHILDREN_AT_SAME_LEVEL); addNodeForSourceElementWithEmbellishments(record, root); stack.push(root); SourceTextNode contentRoot = new SourceTextNode( SourceTextNode.FormatStyle.CHILDREN_AT_SAME_LEVEL); root.addChild(contentRoot); stack.push(contentRoot); super.visit_Expr_Record(record, options); int firstExtension = 0; if (record.getBaseRecordExpr() != null) { contentRoot.getNthChild(0).suffixText(" |"); firstExtension = 1; } for (int i = firstExtension, n = contentRoot.getNChildren() - 1; i < n; i++) { contentRoot.getNthChild(i).suffixText(","); } parenthesizeExpression(contentRoot, "{", "}"); stack.pop(); stack.pop(); return null; } @Override public Void visit_Expr_Record_FieldModification_Extension( Expr.Record.FieldModification.Extension fieldExtension, Options options) { SourceTextNode root = new SourceTextNode(getFieldNameString(fieldExtension.getFieldName()) + " =", SourceTextNode.FormatStyle.CHILDREN_AT_SAME_LEVEL); addNodeForSourceElementWithEmbellishments(fieldExtension, root); stack.push(root); super.visit_Expr_Record_FieldModification_Extension(fieldExtension, options); stack.pop(); return null; } @Override public Void visit_Expr_Record_FieldModification_Update( Expr.Record.FieldModification.Update fieldValueUpdate, Options options) { SourceTextNode root = new SourceTextNode(getFieldNameString(fieldValueUpdate.getFieldName()) + " :=", SourceTextNode.FormatStyle.CHILDREN_AT_SAME_LEVEL); addNodeForSourceElementWithEmbellishments(fieldValueUpdate, root); stack.push(root); super.visit_Expr_Record_FieldModification_Update(fieldValueUpdate, options); stack.pop(); return null; } @Override public Void visit_Expr_SelectDataConsField( Expr.SelectDataConsField field, Options options) { SourceTextNode root = new SourceTextNode( SourceTextNode.FormatStyle.CHILDREN_AT_SAME_LEVEL); addNodeForSourceElementWithEmbellishments(field, root); stack.push(root); super.visit_Expr_SelectDataConsField(field, options); stack.pop(); if (field.getDataConsValuedExpr().precedenceLevel() < field .precedenceLevel()) { // parenthesize if not necessary. We're using the fact that . is // left associative here to put < instead of <=. parenthesizeExpression(root.getNthChild(0)); } // We need to put the dot after the expression for the data // instance. // i.e. the first dot in expression.DataConstructor.field // root.getNthChild(0).suffixText("."); // root.getNthChild(0).consolidateTextRight(); // Now put in the .field part root.getNthChild(1).prefixText("."); root.getNthChild(1).suffixText("."); root.getNthChild(1).suffixText( getFieldNameString(field.getFieldName())); return null; } @Override public Void visit_Expr_SelectRecordField(Expr.SelectRecordField field, Options options) { SourceTextNode root = new SourceTextNode( SourceTextNode.FormatStyle.CHILDREN_AT_SAME_LEVEL); addNodeForSourceElementWithEmbellishments(field, root); stack.push(root); super.visit_Expr_SelectRecordField(field, options); stack.pop(); // do not parenthesize if not necessary. We're using the fact that . // is left associative here to put < instead of <=. if (field.getRecordValuedExpr().precedenceLevel() < field .precedenceLevel()) { parenthesizeExpression(root.getNthChild(0)); } root.suffixText("."); root.suffixText(getFieldNameString(field.getFieldName())); return null; } /** * this wraps part of a caldoc comment with a trailing star * it emulates the old behaviour of formatting caldoc parts for * insertion by the renamer - ultimately the renamer could be changed * to reformat the entire comment. * @param element the element to format * @param options the options to use */ private void visitCalDocPart(SourceElement element, Options options) { StringBuilder commentBuffer = new StringBuilder(); SourceModelCALDocFormatter form = new SourceModelCALDocFormatter(commentBuffer); element.accept(form, options); SourceTextNode root = new SourceTextNode( SourceTextNode.FormatStyle.CHILDREN_AT_SAME_LEVEL); //root.setForcedBreak(); addNodeForSourceElementWithEmbellishments(element, root); String[] lines = commentBuffer.toString().split(EOL); for(String line : lines) { root.addChild(SourceTextNode.makeAtmoic(line + EOL + " * ")); } } @Override public Void visit_CALDoc_TaggedBlock_See_Function( CALDoc.TaggedBlock.See.Function function, Options options) { visitCalDocPart(function, options); return null; } @Override public Void visit_CALDoc_TaggedBlock_See_Module( CALDoc.TaggedBlock.See.Module module, Options options) { visitCalDocPart(module, options); return null; } @Override public Void visit_CALDoc_TaggedBlock_See_TypeCons( CALDoc.TaggedBlock.See.TypeCons typeCons, Options options) { visitCalDocPart(typeCons, options); return null; } @Override public Void visit_CALDoc_TaggedBlock_See_DataCons( CALDoc.TaggedBlock.See.DataCons dataCons, Options options) { visitCalDocPart(dataCons, options); return null; } @Override public Void visit_CALDoc_TaggedBlock_See_TypeClass( CALDoc.TaggedBlock.See.TypeClass typeClass, Options options) { visitCalDocPart(typeClass, options); return null; } @Override public Void visit_CALDoc_TaggedBlock_See_WithoutContext( CALDoc.TaggedBlock.See.WithoutContext seeBlock, Options options) { visitCalDocPart(seeBlock, options); return null; } @Override public Void visit_ModuleDefn(ModuleDefn defn, Options options) { SourceModel.verifyArg(defn, "defn"); if (defn.getCALDocComment() != null) { formatCALDocComment(defn.getCALDocComment()); } SourceTextNode root = new SourceTextNode( SourceTextNode.FormatStyle.CHILDREN_AT_SAME_LEVEL); root.setForcedBreak(); addNodeForSourceElementWithEmbellishments(defn, root); stack.push(root); defn.getModuleName().accept(this, options); stack.pop(); root.getNthChild(0).prefixText("module "); root.getNthChild(0).suffixText(";"); SourceTextNode topLevelRoot = new SourceTextNode( SourceTextNode.FormatStyle.CHILDREN_AT_SAME_LEVEL); topLevelRoot.setForcedBreak(); root.addChild(topLevelRoot); stack.push(topLevelRoot); final int nImportedModules = defn.getNImportedModules(); for (int i = 0; i < nImportedModules; i++) { defn.getNthImportedModule(i).accept(this, options); } final int nFriendModules = defn.getNFriendModules(); for (int i = 0; i < nFriendModules; i++) { defn.getNthFriendModule(i).accept(this, options); } final int nTopLevelDefns = defn.getNTopLevelDefns(); for (int i = 0; i < nTopLevelDefns; i++) { defn.getNthTopLevelDefn(i).accept(this, options); } //add all trailing embellishments SourceTextNode trailing = new SourceTextNode( SourceTextNode.FormatStyle.CHILDREN_AT_SAME_LEVEL); addNodeForSourceElementWithEmbellishments(new SourceRange(new SourcePosition(Integer.MAX_VALUE,1), new SourcePosition(Integer.MAX_VALUE,2)), trailing); stack.pop(); if (defn.getCALDocComment() != null) { stack.pop(); } return null; } @Override public Void visit_Expr_ExprTypeSignature( Expr.ExprTypeSignature signature, Options options) { SourceTextNode root = new SourceTextNode( SourceTextNode.FormatStyle.FIRST_CHILD_AT_LEVEL); addNodeForSourceElementWithEmbellishments(signature, root); stack.push(root); super.visit_Expr_ExprTypeSignature(signature, options); stack.pop(); if (signature.getExpr().precedenceLevel() <= signature .precedenceLevel()) { // parenthesize parenthesizeExpression(root.getNthChild(0)); } root.getNthChild(1).prefixText(":: "); return null; } @Override public Void visit_Friend(SourceModel.Friend friendDeclaration, Options options) { SourceModel.verifyArg(friendDeclaration, "friendDeclaration"); SourceTextNode root = new SourceTextNode( SourceTextNode.FormatStyle.CHILDREN_AT_SAME_LEVEL); root.setForcedBreak(); addNodeForSourceElementWithEmbellishments(friendDeclaration, root); stack.push(root); friendDeclaration.getFriendModuleName().accept(this, options); stack.pop(); root.getNthChild(0).prefixText("friend "); root.getNthChild(0).suffixText(";"); return null; } @Override public Void visit_FunctionDefn_Foreign(FunctionDefn.Foreign defn, Options options) { SourceModel.verifyArg(defn, "foreign"); if (defn.getCALDocComment() != null) { formatCALDocComment(defn.getCALDocComment()); } SourceTextNode root = new SourceTextNode( SourceTextNode.FormatStyle.FIRST_CHILD_AT_LEVEL); addNodeForSourceElementWithEmbellishments(defn, root); // e.g. foreign unsafe import jvm "method Color.getBlue" private // getBlueFromColour :: Colour -> Int; SourceTextNode header = SourceTextNode.makeAtmoic("foreign unsafe import jvm " + StringEncoder.encodeString(defn.getExternalName())); root.addChild(header); SourceTextNode body = new SourceTextNode( SourceTextNode.FormatStyle.CHILDREN_IN_ONE_LEVEL); root.addChild(body); body.setThisText(defn.getName() + " ::"); stack.push(body); defn.getDeclaredType().accept(this, options); stack.pop(); if (defn.isScopeExplicitlySpecified()) { body.prefixText(defn.getScope().toString()+' '); } //body.addChild(SourceTextNode.makeSemicolon()); body.suffixText(";"); if (defn.getCALDocComment() != null) { stack.pop(); } return null; } @Override public Void visit_FunctionDefn_Primitive( FunctionDefn.Primitive primitive, Options options) { SourceModel.verifyArg(primitive, "primitive"); if (primitive.getCALDocComment() != null) { formatCALDocComment(primitive.getCALDocComment()); } SourceTextNode root = new SourceTextNode( SourceTextNode.FormatStyle.FIRST_CHILD_AT_LEVEL); addNodeForSourceElementWithEmbellishments(primitive, root); root.setThisText(primitive.getName() + " ::"); if (primitive.isScopeExplicitlySpecified()) { root.prefixText(primitive.getScope().toString()+' '); } root.prefixText("primitive "); stack.push(root); primitive.getDeclaredType().accept(this, options); stack.pop(); root.addChild(SourceTextNode.makeSemicolon()); if (primitive.getCALDocComment() != null) { stack.pop(); } return null; } @Override public Void visit_Import(Import importStmt, Options options) { SourceModel.verifyArg(importStmt, "importStmt"); SourceTextNode root = new SourceTextNode( SourceTextNode.FormatStyle.FIRST_CHILD_AT_LEVEL); addNodeForSourceElementWithEmbellishments(importStmt, root); stack.push(root); importStmt.getImportedModuleName().accept(this, options); stack.pop(); root.getNthChild(0).prefixText("import "); Import.UsingItem usingItems[] = importStmt.getUsingItems(); if (usingItems.length > 0) { root.getNthChild(0).suffixText(" using"); SourceTextNode usingRoot = new SourceTextNode( SourceTextNode.FormatStyle.CHILDREN_AT_SAME_LEVEL); root.setForcedBreak(); usingRoot.setForcedBreak(); root.addChild(usingRoot); class UsingItem { String moduleName; String itemType; List<String> itemNames = new ArrayList<String>(); } List<UsingItem> processedUsingItems = new ArrayList<UsingItem>(); if (options.groupImportUsingClauses) { List<SourceModel.Import.UsingItem> dataConstructors = new ArrayList<SourceModel.Import.UsingItem>(); List<SourceModel.Import.UsingItem> functions = new ArrayList<SourceModel.Import.UsingItem>(); List<SourceModel.Import.UsingItem> typeClasses = new ArrayList<SourceModel.Import.UsingItem>(); List<SourceModel.Import.UsingItem> typeConstructors = new ArrayList<SourceModel.Import.UsingItem>(); for (org.openquark.cal.compiler.SourceModel.Import.UsingItem element : usingItems) { if (element instanceof Import.UsingItem.DataConstructor) { dataConstructors.add(element); } else if (element instanceof Import.UsingItem.Function) { functions.add(element); } else if (element instanceof Import.UsingItem.TypeClass) { typeClasses.add(element); } else if (element instanceof Import.UsingItem.TypeConstructor) { typeConstructors.add(element); } else { throw new NullPointerException( "Unknown using item type."); } } if (typeConstructors.size() > 0) { UsingItem ui = new UsingItem(); ui.moduleName = importStmt.getImportedModuleName() .toString(); processedUsingItems.add(ui); for (int i = 0, n = typeConstructors.size(); i < n; ++i) { Import.UsingItem iui = typeConstructors.get(i); ui.itemType = iui.getUsingItemCategoryName(); String[] names = iui.getUsingNames(); for (int j = 0, nNames = names.length; j < nNames; ++j) { ui.itemNames.add(names[j]); } } } if (dataConstructors.size() > 0) { UsingItem ui = new UsingItem(); ui.moduleName = importStmt.getImportedModuleName() .toString(); processedUsingItems.add(ui); for (int i = 0, n = dataConstructors.size(); i < n; ++i) { Import.UsingItem iui = dataConstructors.get(i); ui.itemType = iui.getUsingItemCategoryName(); String[] names = iui.getUsingNames(); for (int j = 0, nNames = names.length; j < nNames; ++j) { ui.itemNames.add(names[j]); } } } if (functions.size() > 0) { UsingItem ui = new UsingItem(); ui.moduleName = importStmt.getImportedModuleName() .toString(); processedUsingItems.add(ui); for (int i = 0, n = functions.size(); i < n; ++i) { Import.UsingItem iui = functions.get(i); ui.itemType = iui.getUsingItemCategoryName(); String[] names = iui.getUsingNames(); for (int j = 0, nNames = names.length; j < nNames; ++j) { ui.itemNames.add(names[j]); } } } if (typeClasses.size() > 0) { UsingItem ui = new UsingItem(); ui.moduleName = importStmt.getImportedModuleName() .toString(); processedUsingItems.add(ui); for (int i = 0, n = typeClasses.size(); i < n; ++i) { Import.UsingItem iui = typeClasses.get(i); ui.itemType = iui.getUsingItemCategoryName(); String[] names = iui.getUsingNames(); for (int j = 0, nNames = names.length; j < nNames; ++j) { ui.itemNames.add(names[j]); } } } } else { for (org.openquark.cal.compiler.SourceModel.Import.UsingItem iui : usingItems) { UsingItem ui = new UsingItem(); ui.moduleName = importStmt.getImportedModuleName() .toString(); processedUsingItems.add(ui); ui.itemType = iui.getUsingItemCategoryName(); String[] names = iui.getUsingNames(); for (int j = 0, nNames = names.length; j < nNames; ++j) { ui.itemNames.add(names[j]); } } } for (int i = 0, n = processedUsingItems.size(); i < n; ++i) { UsingItem ui = processedUsingItems.get(i); final String itemCategory = ui.itemType; SourceTextNode category = new SourceTextNode(SourceTextNode.FormatStyle.CONCAT_CHILDREN_TO_LINE_END_AFTER_NEWLINE); usingRoot.addChild(category); category.setThisText(itemCategory + " ="); category.separator=","; for (int j = 0, nNames = ui.itemNames.size(); j < nNames; j++) { category.addChild(new SourceTextNode(ui.itemNames.get(j), SourceTextNode.FormatStyle.ATOMIC)); } category.suffixText(";"); } root.addChild(SourceTextNode.makeSemicolon()); } else { root.suffixText(";"); } return null; } @Override public Void visit_InstanceDefn(InstanceDefn defn, Options options) { SourceModel.verifyArg(defn, "defn"); if (defn.getCALDocComment() != null) { formatCALDocComment(defn.getCALDocComment()); } SourceTextNode root = new SourceTextNode( SourceTextNode.FormatStyle.FIRST_CHILD_AT_LEVEL); root.setForcedBreak(); addNodeForSourceElementWithEmbellishments(defn.getSourceRangeOfName(), root); SourceTextNode header = new SourceTextNode( SourceTextNode.FormatStyle.CHILDREN_AT_SAME_LEVEL); stack.push(root); root.addChild(header); header.setThisText("instance"); stack.push(header); final int nConstraints = defn.getNConstraints(); if (nConstraints > 0 || defn.getParenthesizeConstraints()) { SourceTextNode constraintRoot = new SourceTextNode( SourceTextNode.FormatStyle.FIRST_CHILD_AT_LEVEL); addNodeForSourceElementWithEmbellishments(defn, constraintRoot); stack.push(constraintRoot); for (int i = 0; i < nConstraints; i++) { defn.getNthConstraint(i).accept(this, options); } stack.pop(); if (nConstraints > 1) { for (int i = 0; i < constraintRoot.getNChildren() - 1; ++i) { constraintRoot.getNthChild(i).suffixText(","); } } if (nConstraints > 1 || defn.getParenthesizeConstraints()) { parenthesizeExpression(constraintRoot); } constraintRoot.suffixText(" =>"); } defn.getTypeClassName().accept(this, options); defn.getInstanceTypeCons().accept(this, options); header.addChild(SourceTextNode.makeAtmoic("where")); stack.pop(); final int nInstanceMethods = defn.getNInstanceMethods(); for (int i = 0; i < nInstanceMethods; i++) { InstanceMethod method = defn.getNthInstanceMethod(i); method.accept(this, options); } root.addChild(SourceTextNode.makeSemicolon()); stack.pop(); if (defn.getCALDocComment() != null) { stack.pop(); } return null; } @Override public Void visit_InstanceDefn_InstanceTypeCons_Function( InstanceDefn.InstanceTypeCons.Function function, Options options) { SourceModel.verifyArg(function, "function"); SourceTextNode root = new SourceTextNode( SourceTextNode.FormatStyle.ATOMIC); addNodeForSourceElementWithEmbellishments(function, root); root.setThisText("(" + getTypeVarNameString(function.getDomainTypeVar()) + " -> " + getTypeVarNameString(function.getCodomainTypeVar()) + ")"); return null; } @Override public Void visit_InstanceDefn_InstanceTypeCons_List( InstanceDefn.InstanceTypeCons.List list, Options options) { SourceModel.verifyArg(list, "list"); SourceTextNode root = SourceTextNode.makeAtmoic("[" + getTypeVarNameString(list.getElemTypeVar()) + "]"); addNodeForSourceElementWithEmbellishments(list, root); return null; } @Override public Void visit_InstanceDefn_InstanceTypeCons_Record( InstanceDefn.InstanceTypeCons.Record record, Options options) { SourceModel.verifyArg(record, "record"); SourceTextNode root = new SourceTextNode( SourceTextNode.FormatStyle.ATOMIC); addNodeForSourceElementWithEmbellishments(record, root); root.setThisText("{" + getTypeVarNameString(record.getElemTypeVar()) + "}"); return null; } @Override public Void visit_InstanceDefn_InstanceTypeCons_TypeCons( InstanceDefn.InstanceTypeCons.TypeCons cons, Options options) { SourceModel.verifyArg(cons, "cons"); SourceTextNode root = new SourceTextNode( SourceTextNode.FormatStyle.CHILDREN_AT_SAME_LEVEL); addNodeForSourceElementWithEmbellishments(cons, root); stack.push(root); Name.TypeVar typeVars[] = cons.getTypeVars(); final int nTypeVars = typeVars.length; if (nTypeVars == 0 && !cons.getParenthesized()) { cons.getTypeConsName().accept(this, options); } else { cons.getTypeConsName().accept(this, options); for (int i = 0; i < nTypeVars; ++i) { root.suffixText(" " + getTypeVarNameString(typeVars[i])); } parenthesizeExpression(root); } stack.pop(); return null; } @Override public Void visit_InstanceDefn_InstanceTypeCons_Unit( InstanceDefn.InstanceTypeCons.Unit unit, Options options) { SourceModel.verifyArg(unit, "unit"); SourceTextNode root = SourceTextNode.makeAtmoic("()"); addNodeForSourceElementWithEmbellishments(unit, root); return null; } @Override public Void visit_InstanceDefn_InstanceMethod( InstanceDefn.InstanceMethod method, Options options) { SourceModel.verifyArg(method, "method"); if (method.getCALDocComment() != null) { formatCALDocComment(method.getCALDocComment()); } SourceTextNode root = new SourceTextNode( SourceTextNode.FormatStyle.CHILDREN_AT_SAME_LEVEL); addNodeForSourceElementWithEmbellishments(method, root); root.setThisText(method.getClassMethodName() + " ="); stack.push(root); method.getResolvingFunctionName().accept(this, options); stack.pop(); root.addChild(SourceTextNode.makeAtmoic(";")); if (method.getCALDocComment() != null) { stack.pop(); } return null; } @Override public Void visit_TypeClassDefn(TypeClassDefn defn, Options options) { SourceModel.verifyArg(defn, "defn"); if (defn.getCALDocComment() != null) { formatCALDocComment(defn.getCALDocComment()); } SourceTextNode root = new SourceTextNode( SourceTextNode.FormatStyle.FIRST_CHILD_AT_LEVEL); root.setForcedBreak(); addNodeForSourceElementWithEmbellishments(defn, root); SourceTextNode header = new SourceTextNode( SourceTextNode.FormatStyle.CHILDREN_AT_SAME_LEVEL); stack.push(root); root.addChild(header); header.setThisText("class"); if (defn.isScopeExplicitlySpecified()) { header.prefixText(defn.getScope().toString() + " "); } stack.push(header); final int nConstraints = defn.getNParentClassConstraints(); if (nConstraints > 0 || defn.getParenthesizeConstraints()) { SourceTextNode constraintRoot = new SourceTextNode( SourceTextNode.FormatStyle.FIRST_CHILD_AT_LEVEL); addNodeForSourceElementWithEmbellishments(defn, constraintRoot); stack.push(constraintRoot); for (int i = 0; i < nConstraints; i++) { defn.getNthParentClassConstraint(i).accept(this, options); } stack.pop(); if (nConstraints > 1) { for (int i = 0; i < constraintRoot.getNChildren() - 1; ++i) { constraintRoot.getNthChild(i).suffixText(","); } } if (nConstraints > 1 || defn.getParenthesizeConstraints()) { parenthesizeExpression(constraintRoot); } constraintRoot.suffixText(" =>"); } header.addChild(SourceTextNode.makeAtmoic(defn.getTypeClassName() + " " + getTypeVarNameString(defn.getTypeVar()) + " where")); stack.pop(); final int nClassMethodDefns = defn.getNClassMethodDefns(); for (int i = 0; i < nClassMethodDefns; i++) { ClassMethodDefn method = defn.getNthClassMethodDefn(i); method.accept(this, options); } root.addChild(SourceTextNode.makeSemicolon()); stack.pop(); if (defn.getCALDocComment() != null) { stack.pop(); } return null; } @Override public Void visit_TypeClassDefn_ClassMethodDefn( TypeClassDefn.ClassMethodDefn defn, Options options) { SourceModel.verifyArg(defn, "defn"); if (defn.getCALDocComment() != null) { formatCALDocComment(defn.getCALDocComment()); } SourceTextNode root = new SourceTextNode( SourceTextNode.FormatStyle.FIRST_CHILD_AT_LEVEL); root.setForcedBreak(); addNodeForSourceElementWithEmbellishments(defn, root); stack.push(root); SourceTextNode header = new SourceTextNode( SourceTextNode.FormatStyle.CHILDREN_AT_SAME_LEVEL); root.addChild(header); stack.push(header); header.setThisText(defn.getMethodName() + " ::"); if (defn.isScopeExplicitlySpecified()) { header.prefixText(defn.getScope().toString() + " "); } defn.getTypeSignature().accept(this, options); stack.pop(); if (defn.getDefaultClassMethodName() != null) { SourceTextNode defaultNode = new SourceTextNode( SourceTextNode.FormatStyle.CHILDREN_AT_SAME_LEVEL); root.addChild(defaultNode); defaultNode.setThisText("default "); stack.push(defaultNode); defn.getDefaultClassMethodName().accept(this, options); stack.pop(); } root.suffixText(";"); stack.pop(); if (defn.getCALDocComment() != null) { stack.pop(); } return null; } @Override public Void visit_TypeConstructorDefn_ForeignType( TypeConstructorDefn.ForeignType type, Options options) { SourceModel.verifyArg(type, "type"); if (type.getCALDocComment() != null) { formatCALDocComment(type.getCALDocComment()); } SourceTextNode root = new SourceTextNode( SourceTextNode.FormatStyle.CHILDREN_IN_ONE_LEVEL); addNodeForSourceElementWithEmbellishments(type, root); //root.setForcedBreak(); root.setThisText("data foreign unsafe import jvm "); if (type.isImplementationScopeExplicitlySpecified()) { root.suffixText(type.getImplementationScope()+ " "); } root.suffixText(StringEncoder.encodeString(type.getExternalName())); SourceTextNode body = SourceTextNode.makeAtmoic(type.getTypeConsName()); if (type.isScopeExplicitlySpecified()) { body.prefixText(type.getScope()+ " "); } root.addChild(body); if (type.getNDerivingClauseTypeClassNames() > 0) { SourceTextNode deriving = new SourceTextNode( "deriving", SourceTextNode.FormatStyle.CONCAT_CHILDREN_TO_LINE_END_INDENT_SECOND_LINE); deriving.separator =","; body.addChild(deriving); stack.push(deriving); for (int i = 0, nDerivingClauseTypeClassNames = type .getNDerivingClauseTypeClassNames(); i < nDerivingClauseTypeClassNames; i++) { type.getDerivingClauseTypeClassName(i).accept(this, options); } stack.pop(); } body.addChild(SourceTextNode.makeSemicolon()); if (type.getCALDocComment() != null) { stack.pop(); } return null; } @Override public Void visit_Name_DataCons(Name.DataCons cons, Options options) { SourceTextNode node = new SourceTextNode( (cons.getModuleName() != null ? "." : "") + cons.getUnqualifiedName(), SourceTextNode.FormatStyle.ATOMIC); addNodeForSourceElementWithEmbellishments(cons, node); stack.push(node); super.visit_Name_DataCons(cons, options); node.consolidateTextLeft(); stack.pop(); return null; } @Override public Void visit_Name_Function(Name.Function function, Options options) { SourceTextNode node = new SourceTextNode( (function.getModuleName() != null ? "." : "") + function.getUnqualifiedName(), SourceTextNode.FormatStyle.ATOMIC); addNodeForSourceElementWithEmbellishments(function, node); stack.push(node); super.visit_Name_Function(function, options); node.consolidateTextLeft(); stack.pop(); return null; } @Override public Void visit_Name_Module(Name.Module moduleName, Options options) { SourceTextNode node = new SourceTextNode((moduleName.getQualifier() .getNComponents() > 0 ? "." : "") + moduleName.getUnqualifiedModuleName(), SourceTextNode.FormatStyle.ATOMIC); addNodeForSourceElementWithEmbellishments(moduleName, node); stack.push(node); super.visit_Name_Module(moduleName, options); node.consolidateTextLeft(); stack.pop(); return null; } @Override public Void visit_Name_Module_Qualifier( Name.Module.Qualifier qualifier, Options options) { StringBuilder sb = new StringBuilder(); for (int i = 0, n = qualifier.getNComponents(); i < n; i++) { if (i > 0) { sb.append('.'); } sb.append(qualifier.getNthComponents(i)); } SourceTextNode node = new SourceTextNode(sb.toString(), SourceTextNode.FormatStyle.ATOMIC); addNodeForSourceElementWithEmbellishments(qualifier, node); stack.push(node); super.visit_Name_Module_Qualifier(qualifier, options); node.consolidateTextLeft(); stack.pop(); return null; } @Override public Void visit_Name_TypeClass(Name.TypeClass typeClass, Options options) { SourceTextNode node = new SourceTextNode( (typeClass.getModuleName() != null ? "." : "") + typeClass.getUnqualifiedName(), SourceTextNode.FormatStyle.ATOMIC); addNodeForSourceElementWithEmbellishments(typeClass, node); stack.push(node); super.visit_Name_TypeClass(typeClass, options); node.consolidateTextLeft(); stack.pop(); return null; } @Override public Void visit_Name_TypeCons(Name.TypeCons cons, Options options) { SourceTextNode node = new SourceTextNode( (cons.getModuleName() != null ? "." : "") + cons.getUnqualifiedName(), SourceTextNode.FormatStyle.ATOMIC); addNodeForSourceElementWithEmbellishments(cons, node); stack.push(node); super.visit_Name_TypeCons(cons, options); node.consolidateTextLeft(); stack.pop(); return null; } @Override public Void visit_Name_WithoutContextCons(Name.WithoutContextCons cons, Options options) { SourceTextNode node = new SourceTextNode( (cons.getModuleName() != null ? "." : "") + cons.getUnqualifiedName(), SourceTextNode.FormatStyle.ATOMIC); addNodeForSourceElementWithEmbellishments(cons, node); stack.push(node); super.visit_Name_WithoutContextCons(cons, options); node.consolidateTextLeft(); stack.pop(); return null; } @Override public Void visit_Pattern_Var(Pattern.Var var, Options options) { SourceTextNode node = new SourceTextNode(var.getName(), SourceTextNode.FormatStyle.ATOMIC); addNodeForSourceElementWithEmbellishments(var, node); return null; } @Override public Void visit_Pattern_Wildcard(Pattern.Wildcard wildcard, Options options) { SourceTextNode node = new SourceTextNode("_", SourceTextNode.FormatStyle.ATOMIC); addNodeForSourceElementWithEmbellishments(wildcard, node); return null; } @Override public Void visit_FunctionTypeDeclaraction( FunctionTypeDeclaration declaration, Options options) { if (declaration.getCALDocComment() != null) { formatCALDocComment(declaration.getCALDocComment()); } SourceModel.verifyArg(declaration, "declaration"); SourceTextNode root; root = new SourceTextNode(declaration.getFunctionName() + " ::", SourceTextNode.FormatStyle.CHILDREN_IN_ONE_LEVEL); addNodeForSourceElementWithEmbellishments(declaration, root); stack.push(root); declaration.getTypeSignature().accept(this, options); stack.pop(); root.suffixText(";"); if (declaration.getCALDocComment() != null) { stack.pop(); } return null; } /** * this adds a SourceText node representing a CalDoc comment * @param comment the comment to add */ private void formatCALDocComment(SourceModel.CALDoc.Comment comment) { SourceTextNode comment_declarationRoot = new SourceTextNode( SourceTextNode.FormatStyle.CHILDREN_AT_SAME_LEVEL); addNodeForSourceElementWithEmbellishments(comment, comment_declarationRoot); stack.push(comment_declarationRoot); comment_declarationRoot.addCalDoc(new CALDocTextNode(comment)); } @Override public Void visit_FunctionDefn_Algebraic( FunctionDefn.Algebraic algebraic, Options options) { if (algebraic.getCALDocComment() != null) { formatCALDocComment(algebraic.getCALDocComment()); } SourceTextNode root = new SourceTextNode( SourceTextNode.FormatStyle.FIRST_CHILD_AT_LEVEL); addNodeForSourceElementWithEmbellishments(algebraic .getSourceRangeExcludingCaldoc(), root); stack.push(root); SourceTextNode nameParamRoot = new SourceTextNode( algebraic.getName(), SourceTextNode.FormatStyle.CONCAT_CHILDREN_TO_LINE_END_INDENT_SECOND_LINE); if (algebraic.isScopeExplicitlySpecified()) { nameParamRoot.prefixText(algebraic.getScope().toString() + " "); } root.addChild(nameParamRoot); stack.push(nameParamRoot); final int nParameters = algebraic.getNParameters(); for (int i = 0; i < nParameters; i++) { algebraic.getNthParameter(i).accept(this, options); } stack.pop(); nameParamRoot.addChild(new SourceTextNode("=", SourceTextNode.FormatStyle.ATOMIC)); SourceTextNode defExprRoot = new SourceTextNode( SourceTextNode.FormatStyle.CHILDREN_AT_SAME_LEVEL); root.addChild(defExprRoot); stack.push(defExprRoot); algebraic.getDefiningExpr().accept(this, options); stack.pop(); stack.pop(); if (algebraic.getCALDocComment() != null) { stack.pop(); } defExprRoot.addChild(SourceTextNode.makeSemicolon()); return null; } @Override public Void visit_LocalDefn_Function_Definition( LocalDefn.Function.Definition function, Options options) { if (function.getCALDocComment() != null) { formatCALDocComment(function.getCALDocComment()); } SourceTextNode root = new SourceTextNode( SourceTextNode.FormatStyle.FIRST_CHILD_AT_LEVEL); addNodeForSourceElementWithEmbellishments(function, root); stack.push(root); SourceTextNode nameParamRoot = new SourceTextNode( function.getName(), SourceTextNode.FormatStyle.CONCAT_CHILDREN_TO_LINE_END_INDENT_SECOND_LINE); root.addChild(nameParamRoot); stack.push(nameParamRoot); final int nParameters = function.getNParameters(); for (int i = 0; i < nParameters; i++) { function.getNthParameter(i).accept(this, options); } stack.pop(); nameParamRoot.suffixText(" ="); SourceTextNode defExprRoot = new SourceTextNode( SourceTextNode.FormatStyle.CHILDREN_AT_SAME_LEVEL); root.addChild(defExprRoot); stack.push(defExprRoot); function.getDefiningExpr().accept(this, options); stack.pop(); stack.pop(); if (function.getCALDocComment() != null) { stack.pop(); } defExprRoot.addChild(SourceTextNode.makeSemicolon()); return null; } @Override public Void visit_LocalDefn_Function_TypeDeclaration( LocalDefn.Function.TypeDeclaration declaration, Options options) { if (declaration.getCALDocComment() != null) { formatCALDocComment(declaration.getCALDocComment()); } SourceTextNode root; root = new SourceTextNode(declaration.getName() + " ::", SourceTextNode.FormatStyle.CHILDREN_IN_ONE_LEVEL); addNodeForSourceElementWithEmbellishments(declaration, root); stack.push(root); declaration.getDeclaredType().accept(this, options); stack.pop(); root.suffixText(";"); if (declaration.getCALDocComment() != null) { stack.pop(); } return null; } @Override public Void visit_LocalDefn_PatternMatch_UnpackDataCons( LocalDefn.PatternMatch.UnpackDataCons unpackDataCons, Options options) { SourceTextNode rootNode = new SourceTextNode( SourceTextNode.FormatStyle.FIRST_CHILD_AT_LEVEL); addNodeForSourceElementWithEmbellishments(unpackDataCons, rootNode); stack.push(rootNode); SourceTextNode dcRoot = new SourceTextNode( SourceTextNode.FormatStyle.FIRST_CHILD_AT_LEVEL); rootNode.addChild(dcRoot); stack.push(dcRoot); unpackDataCons.getDataConsName().accept(this, options); unpackDataCons.getArgBindings().accept(this, options); stack.pop(); dcRoot.suffixText(" ="); SourceTextNode defExprRoot = new SourceTextNode( SourceTextNode.FormatStyle.CHILDREN_AT_SAME_LEVEL); rootNode.addChild(defExprRoot); stack.push(defExprRoot); unpackDataCons.getDefiningExpr().accept(this, options); stack.pop(); defExprRoot.addChild(SourceTextNode.makeSemicolon()); stack.pop(); return null; } @Override public Void visit_LocalDefn_PatternMatch_UnpackTuple( LocalDefn.PatternMatch.UnpackTuple unpackTuple, Options options) { SourceTextNode rootNode = new SourceTextNode( SourceTextNode.FormatStyle.FIRST_CHILD_AT_LEVEL); addNodeForSourceElementWithEmbellishments(unpackTuple, rootNode); stack.push(rootNode); SourceTextNode tupleRoot = new SourceTextNode( SourceTextNode.FormatStyle.CHILDREN_AT_SAME_LEVEL); rootNode.addChild(tupleRoot); stack.push(tupleRoot); for (int i = 0, nPatterns = unpackTuple.getNPatterns(); i < nPatterns; i++) { unpackTuple.getNthPattern(i).accept(this, options); } stack.pop(); for (int i = 0, n = tupleRoot.getNChildren() - 1; i < n; ++i) { tupleRoot.getNthChild(i).suffixText(","); } parenthesizeExpression(tupleRoot); tupleRoot.suffixText(" ="); SourceTextNode defExprRoot = new SourceTextNode( SourceTextNode.FormatStyle.CHILDREN_AT_SAME_LEVEL); rootNode.addChild(defExprRoot); stack.push(defExprRoot); unpackTuple.getDefiningExpr().accept(this, options); stack.pop(); defExprRoot.addChild(SourceTextNode.makeSemicolon()); stack.pop(); return null; } @Override public Void visit_LocalDefn_PatternMatch_UnpackListCons( LocalDefn.PatternMatch.UnpackListCons unpackListCons, Options options) { // Root node for the case alt SourceTextNode root = new SourceTextNode( SourceTextNode.FormatStyle.FIRST_CHILD_AT_LEVEL); addNodeForSourceElementWithEmbellishments(unpackListCons, root); stack.push(root); // Root node for the list left hand side. i.e. x : xs = SourceTextNode listRoot = new SourceTextNode( SourceTextNode.FormatStyle.ATOMIC); root.addChild(listRoot); stack.push(listRoot); unpackListCons.getHeadPattern().accept(this, options); unpackListCons.getTailPattern().accept(this, options); stack.pop(); listRoot.getNthChild(0).suffixText(" :"); listRoot.getNthChild(1).suffixText(" ="); // Root for the expression. SourceTextNode defExprRoot = new SourceTextNode( SourceTextNode.FormatStyle.CHILDREN_AT_SAME_LEVEL); root.addChild(defExprRoot); stack.push(defExprRoot); unpackListCons.getDefiningExpr().accept(this, options); defExprRoot.addChild(SourceTextNode.makeSemicolon()); stack.pop(); stack.pop(); return null; } @Override public Void visit_LocalDefn_PatternMatch_UnpackRecord( LocalDefn.PatternMatch.UnpackRecord unpackRecord, Options options) { // Root node for the case alt SourceTextNode root = new SourceTextNode( SourceTextNode.FormatStyle.FIRST_CHILD_AT_LEVEL); addNodeForSourceElementWithEmbellishments(unpackRecord, root); stack.push(root); // Root for the record. i.e. {s | x = a, y = b} = SourceTextNode recordRoot = new SourceTextNode( SourceTextNode.FormatStyle.CHILDREN_AT_SAME_LEVEL); root.addChild(recordRoot); stack.push(recordRoot); if (unpackRecord.getBaseRecordPattern() != null) { unpackRecord.getBaseRecordPattern().accept(this, options); recordRoot.suffixText(" |"); } final int nFieldPatterns = unpackRecord.getNFieldPatterns(); for (int i = 0; i < nFieldPatterns; i++) { unpackRecord.getNthFieldPattern(i).accept(this, options); if (i < nFieldPatterns - 1) { recordRoot.getNthChild(recordRoot.getNChildren() - 1) .suffixText(","); } } stack.pop(); parenthesizeExpression(recordRoot, "{", "}"); recordRoot.suffixText(" ="); // Root node for the defining expr. SourceTextNode defExprRoot = new SourceTextNode( SourceTextNode.FormatStyle.CHILDREN_AT_SAME_LEVEL); root.addChild(defExprRoot); stack.push(defExprRoot); unpackRecord.getDefiningExpr().accept(this, options); defExprRoot.addChild(SourceTextNode.makeSemicolon()); stack.pop(); stack.pop(); return null; } @Override public Void visit_Constraint_Lacks(Constraint.Lacks lacks, Options options) { addNodeForSourceElementWithEmbellishments(lacks, new SourceTextNode(getTypeVarNameString(lacks.getTypeVarName()) + "\\" + getFieldNameString(lacks.getLacksField()), SourceTextNode.FormatStyle.ATOMIC)); return null; } @Override public Void visit_Constraint_TypeClass(Constraint.TypeClass typeClass, Options options) { SourceTextNode root = new SourceTextNode(" " + getTypeVarNameString(typeClass.getTypeVarName()), SourceTextNode.FormatStyle.ATOMIC); addNodeForSourceElementWithEmbellishments(typeClass, root); stack.push(root); super.visit_Constraint_TypeClass(typeClass, options); stack.pop(); root.consolidateTextLeft(); return null; } @Override public Void visit_TypeSignature(TypeSignature signature, Options options) { SourceModel.verifyArg(signature, "signature"); final int nConstraints = signature.getNConstraints(); if (nConstraints > 0 || signature.getConstraintsHaveParen()) { SourceTextNode constraintRoot = new SourceTextNode( SourceTextNode.FormatStyle.FIRST_CHILD_AT_LEVEL); addNodeForSourceElementWithEmbellishments(signature, constraintRoot); stack.push(constraintRoot); for (int i = 0; i < nConstraints; i++) { signature.getNthConstraint(i).accept(this, options); } stack.pop(); if (nConstraints > 1) { for (int i = 0; i < constraintRoot.getNChildren() - 1; ++i) { constraintRoot.getNthChild(i).suffixText(","); } } if (nConstraints > 1 || signature.getConstraintsHaveParen()) { parenthesizeExpression(constraintRoot); } constraintRoot.suffixText(" =>"); } SourceTextNode typeExprRoot = new SourceTextNode( SourceTextNode.FormatStyle.CHILDREN_AT_SAME_LEVEL); addNodeForSourceElementWithEmbellishments(signature .getTypeExprDefn(), typeExprRoot); stack.push(typeExprRoot); signature.getTypeExprDefn().accept(this, options); stack.pop(); if (signature.getTypeExprDefn() instanceof TypeExprDefn.Function) { SourceTextNode root = (SourceTextNode) stack.peek(); SourceTextNode functionRoot = root.getNthChild(root .getNChildren() - 1); root.removeChild(root.getNChildren() - 1); for (int i = 0, n = functionRoot.getNChildren(); i < n; ++i) { root.addChild(functionRoot.getNthChild(i)); } } return null; } @Override public Void visit_TypeExprDefn_Parenthesized( TypeExprDefn.Parenthesized parenthesized, Options options) { SourceTextNode node = new SourceTextNode( SourceTextNode.FormatStyle.CHILDREN_AT_SAME_LEVEL); addNodeForSourceElementWithEmbellishments(parenthesized, node); stack.push(node); parenthesized.getTypeExprDefn().accept(this, options); parenthesizeExpression(node.getNthChild(0)); stack.pop(); return null; } @Override public Void visit_TypeExprDefn_Application( TypeExprDefn.Application application, Options options) { SourceTextNode root = new SourceTextNode( SourceTextNode.FormatStyle.CHILDREN_AT_SAME_LEVEL); addNodeForSourceElementWithEmbellishments(application, root); stack.push(root); super.visit_TypeExprDefn_Application(application, options); stack.pop(); for (int i = 0, n = application.getNTypeExpressions(); i < n; ++i) { if (!application.getNthTypeExpression(i) .neverNeedsParentheses()) { parenthesizeExpression(root.getNthChild(i)); } } return null; } @Override public Void visit_TypeExprDefn_Function(TypeExprDefn.Function function, Options options) { SourceTextNode root = new SourceTextNode( SourceTextNode.FormatStyle.CHILDREN_AT_SAME_LEVEL); addNodeForSourceElementWithEmbellishments(function, root); stack.push(root); super.visit_TypeExprDefn_Function(function, options); stack.pop(); // we never need to parenthesize the type on the right hand side of // a "->". // This is because "->" is the lowest precedence operator in the // type grammar. // We only parenthesize the lhs if it is a "->". if (function.getDomain() instanceof Function) { parenthesizeExpression(root.getNthChild(0)); } root.getNthChild(1).prefixText("-> "); if (function.getCodomain() instanceof TypeExprDefn.Function) { SourceTextNode co = root.getNthChild(1); root.removeChild(1); for (int i = 0, n = co.getNChildren(); i < n; ++i) { root.addChild(co.getNthChild(i)); } } return null; } @Override public Void visit_TypeExprDefn_List(TypeExprDefn.List list, Options options) { SourceModel.verifyArg(list, "list"); SourceTextNode root = new SourceTextNode( SourceTextNode.FormatStyle.FIRST_CHILD_AT_LEVEL); addNodeForSourceElementWithEmbellishments(list, root); stack.push(root); list.getElement().accept(this, options); stack.pop(); parenthesizeExpression(root, "[", "]"); return null; } @Override public Void visit_TypeExprDefn_Record(TypeExprDefn.Record record, Options options) { SourceTextNode root = new SourceTextNode( SourceTextNode.FormatStyle.CHILDREN_AT_SAME_LEVEL); addNodeForSourceElementWithEmbellishments(record, root); stack.push(root); super.visit_TypeExprDefn_Record(record, options); stack.pop(); if (root.getNChildren() == 0) { root.setThisText("{}"); return null; } int firstExtension = 0; if (record.getBaseRecordVar() != null && (root.getNChildren() > 1)) { root.getNthChild(0).suffixText(" |"); firstExtension = 1; } for (int i = firstExtension, n = root.getNChildren() - 1; i < n; i++) { root.getNthChild(i).suffixText(","); } parenthesizeExpression(root, "{", "}"); return null; } @Override public Void visit_TypeExprDefn_Record_FieldTypePair( TypeExprDefn.Record.FieldTypePair pair, Options options) { SourceModel.verifyArg(pair, "pair"); SourceTextNode root = new SourceTextNode(getFieldNameString(pair.getFieldName()) + " ::", SourceTextNode.FormatStyle.CHILDREN_IN_ONE_LEVEL); addNodeForSourceElementWithEmbellishments(pair, root); stack.push(root); super.visit_TypeExprDefn_Record_FieldTypePair(pair, options); stack.pop(); return null; } @Override public Void visit_TypeExprDefn_Tuple(TypeExprDefn.Tuple tuple, Options options) { SourceTextNode root = new SourceTextNode( SourceTextNode.FormatStyle.CHILDREN_AT_SAME_LEVEL); addNodeForSourceElementWithEmbellishments(tuple, root); stack.push(root); super.visit_TypeExprDefn_Tuple(tuple, options); stack.pop(); for (int i = 0, n = root.getNChildren() - 1; i < n; ++i) { root.getNthChild(i).suffixText(","); } parenthesizeExpression(root); return null; } @Override public Void visit_TypeExprDefn_TypeCons(TypeExprDefn.TypeCons cons, Options options) { SourceModel.verifyArg(cons, "cons"); cons.getTypeConsName().accept(this, options); return null; } @Override public Void visit_TypeExprDefn_TypeVar(TypeExprDefn.TypeVar var, Options options) { addNodeForSourceElementWithEmbellishments(var, new SourceTextNode( getTypeVarNameString(var.getTypeVarName()), SourceTextNode.FormatStyle.ATOMIC)); return null; } @Override public Void visit_TypeExprDefn_Unit(TypeExprDefn.Unit unit, Options options) { addNodeForSourceElementWithEmbellishments(unit, new SourceTextNode( "()", SourceTextNode.FormatStyle.ATOMIC)); return null; } @Override public Void visit_Parameter(Parameter parameter, Options options) { addNodeForSourceElementWithEmbellishments(parameter, new SourceTextNode((parameter.isStrict() ? "!" : "") + parameter.getName(), SourceTextNode.FormatStyle.ATOMIC)); return null; } @Override public Void visit_TypeConstructorDefn_AlgebraicType_DataConsDefn( TypeConstructorDefn.AlgebraicType.DataConsDefn defn, Options options) { SourceModel.verifyArg(defn, "defn"); if (defn.getCALDocComment() != null) { formatCALDocComment(defn.getCALDocComment()); } SourceTextNode root = new SourceTextNode( defn.getDataConsName(), SourceTextNode.FormatStyle.CHILDREN_IN_ONE_LEVEL); if (defn.getNTypeArgs() > 1) { root.setForcedBreak(); } addNodeForSourceElementWithEmbellishments(defn, root); stack.push(root); if (defn.isScopeExplicitlySpecified()) { root.prefixText(defn.getScope().toString() + " "); } for (int i = 0, nParams = defn.getNTypeArgs(); i < nParams; ++i) { defn.getNthTypeArg(i).accept(this, options); } stack.pop(); if (defn.getCALDocComment() != null) { stack.pop(); } return null; } @Override public Void visit_TypeConstructorDefn_AlgebraicType_DataConsDefn_TypeArgument( TypeConstructorDefn.AlgebraicType.DataConsDefn.TypeArgument argument, Options options) { SourceModel.verifyArg(argument, "argument"); StringBuilder sb = new StringBuilder(); sb.append(getFieldNameString(argument.getFieldName())).append(" ::"); SourceTextNode root = new SourceTextNode(sb.toString(), SourceTextNode.FormatStyle.CHILDREN_IN_ONE_LEVEL); addNodeForSourceElementWithEmbellishments(argument, root); stack.push(root); argument.getTypeExprDefn().accept(this, options); if (!argument.getTypeExprDefn().neverNeedsParentheses()) { parenthesizeExpression(root.getNthChild(0)); } if (argument.isStrict()) { root.getNthChild(0).prefixText("!"); } stack.pop(); return null; } @Override public Void visit_TypeConstructorDefn_AlgebraicType( TypeConstructorDefn.AlgebraicType type, Options options) { if (type.getCALDocComment() != null) { formatCALDocComment(type.getCALDocComment()); } StringBuilder text = new StringBuilder("data "); if (type.isScopeExplicitlySpecified()) { text.append(type.getScope().toString()).append(" "); } text.append(type.getTypeConsName()); SourceModel.verifyArg(type, "type"); SourceTextNode root = new SourceTextNode(text.toString(), SourceTextNode.FormatStyle.CHILDREN_IN_ONE_LEVEL); addNodeForSourceElementWithEmbellishments(type, root); stack.push(root); Name.TypeVar typeParameters[] = type.getTypeParameters(); for (int i = 0, nParams = typeParameters.length; i < nParams; ++i) { root.suffixText(' ' + getTypeVarNameString(typeParameters[i])); } root.suffixText(" ="); SourceTextNode constructors = new SourceTextNode( SourceTextNode.FormatStyle.CHILDREN_AT_SAME_LEVEL); constructors.setForcedBreak(); constructors.separator = " |"; root.addChild(constructors); stack.push(constructors); int nDataCons = type.getNDataConstructors(); for (int i = 0; i < nDataCons; ++i) { type.getNthDataConstructor(i).accept(this, options); } stack.pop(); final int nDerivingTypeClassNames = type .getNDerivingClauseTypeClassNames(); if (nDerivingTypeClassNames > 0) { SourceTextNode deriving = new SourceTextNode("deriving", SourceTextNode.FormatStyle.CHILDREN_IN_ONE_LEVEL); addNodeForSourceElementWithEmbellishments(type, deriving); deriving.separator = ","; stack.push(deriving); for (int i = 0; i < nDerivingTypeClassNames; ++i) { type.getDerivingClauseTypeClassName(i).accept(this, options); } stack.pop(); } root.addChild(SourceTextNode.makeSemicolon()); stack.pop(); if (type.getCALDocComment() != null) { stack.pop(); } return null; } /** * Returns the name of a SourceModel.Name.Field as a string. */ // todo-jowong refactor this so that this visitor can properly have a visit_Name_Field method @Deprecated private static String getFieldNameString(final SourceModel.Name.Field fieldName) { return fieldName.getName().getCalSourceForm(); } /** * Returns the name of a SourceModel.Name.TypeVar as a string. */ // todo-jowong refactor this so that this visitor can properly have a visit_Name_TypeVar method @Deprecated private static String getTypeVarNameString(final SourceModel.Name.TypeVar typeVarName) { return typeVarName.getName(); } } /** * this node is used to represent a CalDoc comment * it can be associated with a SourceTextNode and is formatted when * the source text node is formatted. The actual formatting is deferred * to the CalDoc source formatter. * * @author mbyne */ private static final class CALDocTextNode { /** the comment that is to be formatted*/ final private CALDoc.Comment comment; CALDocTextNode(CALDoc.Comment comment) { this.comment = comment; } /** * Format the caldoc text node to * text. * * @param sb - * the StringBuilder to put the formatted source in. * @param indentLevel * @param offset - * offset from the current indent * @param options */ public void toFormattedText(StringBuilder sb, int indentLevel, int offset, Options options) { StringBuilder commentBuffer = new StringBuilder(); SourceModelCALDocFormatter form = new SourceModelCALDocFormatter(commentBuffer); comment.accept(form, options.withRestrictedLineLength( options.maxLineLength - indentLevel * options.indentString.length() - 3)); form.decorate(options); String[] lines = commentBuffer.toString().split(EOL); for(String line : lines) { emitIndentedText(sb, indentLevel, line, options); } } } /** * A SourceTextNode is a tree structure which can be converted to formated * text. Nodes in the tree contain text, a formatting style and children. * * @author Magnus Byne */ private static final class SourceTextNode { /** makes a source text node that is a semicolon */ public static final SourceTextNode makeSemicolon() { return new SourceTextNode(";", SourceTextNode.FormatStyle.ATOMIC); } /** makes an atomic source text node with text*/ public static final SourceTextNode makeAtmoic(String text) { return new SourceTextNode(text, SourceTextNode.FormatStyle.ATOMIC); } private boolean forcedBreak = false; public void setForcedBreak() { forcedBreak = true; } /** The text associated with this node. */ private String myText = ""; /** caldoc may optionally be associated with the node */ private CALDocTextNode caldoc = null; /** The style of formatting for this node. */ private FormatStyle formatStyle; private String separator = ""; /** Child nodes. */ protected List<SourceTextNode> children = new ArrayList<SourceTextNode>(); public int getNChildren() { return children.size(); } public SourceTextNode getNthChild(int index) { return children.get(index); } public void removeChild(int i) { children.remove(i); } public void addCalDoc(CALDocTextNode caldoc) { this.caldoc= caldoc; } /** * Create an ExpressionTextNode * * @param formatStyle */ public SourceTextNode(FormatStyle formatStyle) { if (formatStyle == null) { throw new NullPointerException( "Invalid null value for format type."); } this.formatStyle = formatStyle; } /** * Create an SourceTextNode * * @param myText * @param formatStyle */ public SourceTextNode(String myText, FormatStyle formatStyle) { if (formatStyle == null) { throw new NullPointerException( "Invalid null value for formatStyle."); } this.myText = myText; this.formatStyle = formatStyle; } /** gets the text for this node - not including children */ public String getThisText() { return myText; } public void setThisText(String newText) { myText = newText; } public SourceTextNode getNodeWithoutComment() { if (formatStyle == FormatStyle.COMMENTS_FOLLOWED_BY_CODE) { return getNthChild(1); } else { return this; } } /** the length of this node including all children */ public int getTotalTextLength() { int totalLength = getThisText().length(); if (totalLength > 0) { totalLength++; } for (Iterator<SourceTextNode> it = children.iterator(); it .hasNext();) { totalLength += it.next().getTotalTextLength(); if (it.hasNext()) { totalLength += separator.length(); } } return totalLength; } /** * get the maximum nesting on this node - this is used a measure of * complexity to see if it should be formatter on a single line or split */ public int getMaximumNesting() { int max = 0; for (SourceTextNode sourceTextNode : children) { int d = sourceTextNode.getMaximumNesting(); if (d > max) { max = d; } } if (formatStyle == FormatStyle.INNER_CHILDREN_IN_ONE_LEVEL) { max++; } return max; } public void addChild(SourceTextNode node) { children.add(node); } /** * Prefix the supplied text to the text of this node, if there is any. * Otherwise prefix it to the leftmost child node with text. Text is not * prefixed to embellishment nodes. * * @param prefixText */ public boolean prefixText(String prefixText) { if (myText.length() > 0 && formatStyle != FormatStyle.EMBELLISHMENT) { myText = prefixText + myText; return true; } else if (formatStyle == FormatStyle.INNER_CHILDREN_IN_ONE_LEVEL) { // for parenthesized expressions we typically want to make sure // the brackets // are aligned - therefore we cannot simply prefix to the // opening parenthesis // however we must remove a trailing space that is inserted // between nodes by default myText = prefixText + myText; if (myText.charAt(myText.length() - 1) == ' ') { myText = myText.substring(0, myText.length() - 1); } return true; } else { int i = 0; while (i < getNChildren()) { if (getNthChild(i).prefixText(prefixText)) { return true; } i++; } return false; } } /** * Suffix the given text to this nodes text if there are no children. * Otherwise suffix to the rightmost child (excluding comment nodes). * * @param suffixText */ public void suffixText(String suffixText) { if (getNChildren() == 0) { myText = myText + suffixText; } else { if (!suffixText.equals(EOL) && formatStyle == FormatStyle.CODE_FOLLOWED_BY_COMMENT) { children.get(0).suffixText(suffixText); } else { children.get(children.size() - 1).suffixText(suffixText); } } } /** * Format the sourceTextNode Tree (ie this node and all children) to * text. * * @param sb - * the StringBuilder to put the formatted source in. * @param indentLevel * @param offset - * offset from the current indent * @param options */ public void toFormattedText(StringBuilder sb, int indentLevel, int offset, Options options) { if (caldoc != null) { caldoc.toFormattedText(sb, indentLevel, offset, options); } // Update the offset if necessary. if (offset == 0) { offset = sb.length() - sb.lastIndexOf(EOL) - EOL.length(); if (offset < 0) { offset = 0; } } // Find starting position on current line. int startPos = offset + (indentLevel * options.tabWidth); // If the expression fits on the remainder of the current line // we can simply append the text. if (getTotalTextLength() + startPos <= options.maxLineLength && !hasForcedLineBreak() && getMaximumNesting() <= options.maxNestingDepthOnOneLine) { // If we're at the beginning of a line we need to indent. if (offset == 0) { emitIndent(sb, indentLevel, options); } appendExpressionText(sb); return; } // We need to break up the expression. // The expression is broken up based on the format type if (getFormatType().equals(FormatStyle.ATOMIC)) { if (offset == 0) { emitIndent(sb, indentLevel, options); } appendExpressionText(sb); } else if (getFormatType().equals(FormatStyle.APPLICATION)) { if (SHOW_DEBUG_LABELS) { emitIndentedText(sb, indentLevel, "APPLICATION", options); } if (getThisText().length() > 0) { if (offset == 0) { emitIndentedText(sb, indentLevel, getThisText(), options); } else { sb.append(getThisText()); emitEOL(sb); offset = 0; } } // Format first child at the same indent level. getNthChild(0) .toFormattedText(sb, indentLevel, offset, options); emitEOL(sb); // format other children (the arguments) in one level for (int i = 1, n = getNChildren(); i < n; ++i) { getNthChild(i).toFormattedText(sb, indentLevel + 1, 0, options); if (i < n - 1) { emitEOL(sb); } } } else if (getFormatType().equals( FormatStyle.CODE_FOLLOWED_BY_COMMENT)) { if (SHOW_DEBUG_LABELS) { emitIndentedText(sb, indentLevel, "CODE_AND_COMMENT", options); } assert (getNChildren() == 2); if (offset != 0) { emitEOL(sb); offset = 0; } // swap the children so that the comment precedes the code getNthChild(1).toFormattedText(sb, indentLevel, 0, options); emitEOL(sb); getNthChild(0).toFormattedText(sb, indentLevel, 0, options); } else if (getFormatType().equals(FormatStyle.NEW_LINE)) { if (SHOW_DEBUG_LABELS) { emitIndentedText(sb, indentLevel, "NEWLINE", options); } emitEOL(sb); } else if (getFormatType().equals(FormatStyle.CONCAT_FIRST_CHILD)) { if (SHOW_DEBUG_LABELS) { emitIndentedText(sb, indentLevel, "CONCAT_FIRST_CHILD", options); } // See if the first child will fit on the line. if (getThisText().length() > 0) { if (offset == 0) { emitIndent(sb, indentLevel, options); } sb.append(getThisText()); } int lastLineEnd = sb.lastIndexOf(EOL); if (lastLineEnd < 0) { lastLineEnd = 0; } int linePos = sb.length() - lastLineEnd; int startChild = 0; if (linePos + getNthChild(0).getTotalTextLength() <= options .getMaxColumns()) { sb.append(' '); getNthChild(0).appendExpressionText(sb); emitEOL(sb); offset = 0; startChild = 1; } for (int i = startChild, n = getNChildren(); i < n; ++i) { getNthChild(i).toFormattedText(sb, indentLevel, 0, options); if (i < n - 1) { emitEOL(sb); } } } else if ( getFormatType().equals( FormatStyle.CHILDREN_AT_SAME_LEVEL) || getFormatType().equals( FormatStyle.COMMENTS_FOLLOWED_BY_CODE)) { if (SHOW_DEBUG_LABELS) { emitIndentedText(sb, indentLevel, "CHILDREN_AT_SAME_LEVEL_FORCE_BREAK", options); } if (offset != 0) { emitEOL(sb); } if (getThisText().length() > 0) { if (offset == 0) { emitIndent(sb, indentLevel, options); } sb.append(getThisText()); emitEOL(sb); offset = 0; } for (int i = 0, n = getNChildren(); i < n; ++i) { // this is to avoid writing out a blank line if the last // line was blank if (getNthChild(i).getTotalTextLength() > 0) { if ((i < n - 1)) { getNthChild(i).suffixText(separator); } getNthChild(i).toFormattedText(sb, indentLevel, i == 0 ? offset : 0, options); if (i < n - 1) { emitEOL(sb); } } else if (sb.lastIndexOf(EOL + EOL) != sb.length() - EOL.length() * 2) { if (i < n - 1) { emitEOL(sb); } } } } else if (getFormatType() .equals(FormatStyle.CHILDREN_IN_ONE_LEVEL)) { if (SHOW_DEBUG_LABELS) { emitIndentedText(sb, indentLevel, "CHILDREN_IN_ONE_LEVEL", options); } if (getThisText().length() > 0) { if (offset == 0) { emitIndentedText(sb, indentLevel, getThisText(), options); } else { sb.append(getThisText()); emitEOL(sb); offset = 0; } } // Format each child on a new line. for (int i = 0, n = getNChildren(); i < n; ++i) { if (i < n - 1) { getNthChild(i).suffixText(separator); } getNthChild(i).toFormattedText(sb, indentLevel + 1, 0, options); if (i < n - 1) { emitEOL(sb); } } } else if (getFormatType().equals( FormatStyle.INNER_CHILDREN_IN_ONE_LEVEL)) { if (SHOW_DEBUG_LABELS) { emitIndentedText(sb, indentLevel, "INNER_CHILDREN_IN_ONE_LEVEL", options); } if (getThisText().length() > 0) { if (offset == 0) { emitIndentedText(sb, indentLevel, getThisText(), options); } else { sb.append(getThisText()); emitEOL(sb); offset = 0; } } // Format each child on a new line. for (int i = 0, n = getNChildren(); i < n; ++i) { getNthChild(i).toFormattedText( sb, (i > 0 && i < (n - 1)) ? indentLevel + 1 : indentLevel, 0, options); if (i < n - 1) { emitEOL(sb); } } } else if (getFormatType().equals(FormatStyle.FIRST_CHILD_AT_LEVEL)) { if (SHOW_DEBUG_LABELS) { emitIndentedText(sb, indentLevel, "FIRST_CHILD_AT_LEVEL", options); } if (getThisText().length() > 0) { if (offset == 0) { emitIndentedText(sb, indentLevel, getThisText(), options); } else { sb.append(getThisText()); emitEOL(sb); offset = 0; } } // Format first child at the same indent level. getNthChild(0) .toFormattedText(sb, indentLevel, offset, options); // Format other children on new lines. for (int i = 1, n = getNChildren(); i < n; ++i) { emitEOL(sb); getNthChild(i).toFormattedText(sb, indentLevel + 1, 0, options); } } else if (getFormatType().equals(FormatStyle.ALTERNATE_CHILDREN)) { if (SHOW_DEBUG_LABELS) { emitIndentedText(sb, indentLevel, "ALTERNATE_CHILDREN", options); } if (getThisText().length() > 0) { if (offset == 0) { emitIndentedText(sb, indentLevel, getThisText(), options); } else { sb.append(getThisText()); emitEOL(sb); offset = 0; } } // Format each child on a new line. for (int i = 0, n = getNChildren(); i < n; ++i) { getNthChild(i).toFormattedText(sb, ((i % 2) != 0) ? indentLevel + 1 : indentLevel, 0, options); if (i < n - 1) { emitEOL(sb); } } } else if (getFormatType().equals( FormatStyle.CONCAT_CHILDREN_TO_LINE_END_AFTER_NEWLINE)) { if (SHOW_DEBUG_LABELS) { emitIndentedText(sb, indentLevel, "CONCAT_CHILDREN_TO_LINE_END_AFTER_NEWLINE", options); } if (getThisText().length() > 0) { if (offset == 0) { emitIndent(sb, indentLevel, options); } sb.append(getThisText()).append(' '); } indentLevel ++; StringBuilder lineBuffer = new StringBuilder(); emitIndent(lineBuffer, indentLevel, options); int linePos = indentLevel * options.getTabWidth(); String sep = separator + ' '; for (int i = 0, n = getNChildren(); i < n; ++i) { SourceTextNode child = getNthChild(i); int childTextLength = child.getTotalTextLength()-1; if (childTextLength + linePos + ( i< n-1 ? sep.length() : 0) > options.maxLineLength) { emitEOL(lineBuffer); emitIndent(lineBuffer, indentLevel, options); linePos = indentLevel * options.getTabWidth(); } child.appendExpressionText(lineBuffer); if (i < n - 1) { lineBuffer.append(sep); linePos += sep.length(); } linePos += childTextLength; } sb.append(EOL); sb.append(lineBuffer); indentLevel--; } else if (getFormatType().equals( FormatStyle.CONCAT_CHILDREN_TO_LINE_END_INDENT_SECOND_LINE)) { if (SHOW_DEBUG_LABELS) { emitIndentedText(sb, indentLevel, "CONCAT_CHILDREN_TO_LINE_END_INDENT_SECOND_LINE", options); } // This is used for laying out something like a function // declaration where the function // and argument names won't fit on a single line. // ex. myfunction a b c .... // d e f int lineStartPos = 0; int secondLineExtraIndent = 0; if (getThisText().length() > 0) { if (offset == 0) { emitIndent(sb, indentLevel, options); } sb.append(getThisText()).append(' '); int lastNewline = sb.lastIndexOf(EOL); if (lastNewline < 0) { lastNewline = 0; } lineStartPos = sb.length() - lastNewline; secondLineExtraIndent = getThisText().length() + 1; } else { lineStartPos = indentLevel * options.tabWidth; } StringBuilder sbTemp = new StringBuilder(); for (int i = 0; i < secondLineExtraIndent; ++i) { sbTemp.append(' '); } String extraIndentString = sbTemp.toString(); StringBuilder lineBuffer = new StringBuilder(); int linePos = lineStartPos; for (int i = 0, n = getNChildren(); i < n; ++i) { SourceTextNode child = getNthChild(i); int childTextLength = child.getTotalTextLength(); if (childTextLength + linePos > options.maxLineLength) { emitEOL(lineBuffer); emitIndent(lineBuffer, indentLevel, options); lineBuffer.append(extraIndentString); lineStartPos = lineBuffer.length() - lineBuffer.lastIndexOf(EOL); linePos = lineStartPos; } child.appendExpressionText(lineBuffer); if (child.hasForcedLineBreak()) { emitEOL(lineBuffer); emitIndent(lineBuffer, indentLevel, options); lineBuffer.append(extraIndentString); lineStartPos = lineBuffer.length() - lineBuffer.lastIndexOf(EOL); linePos = lineStartPos; } else if (i < n - 1) { lineBuffer.append(separator).append(' '); } linePos += childTextLength; } sb.append(lineBuffer); } else if (getFormatType().equals(FormatStyle.EMBELLISHMENT)) { if (SHOW_DEBUG_LABELS) { emitIndentedText(sb, indentLevel, "EMBELLISHMENT", options); } // the comment must be split into multiple lines List<String> lines; if (myText.startsWith("//")) { lines = SourceEmbellishment.SingleLineComment.format( this.myText, options.maxLineLength - indentLevel); } else { lines = SourceEmbellishment.MultiLineComment.format( this.myText, options.maxLineLength - indentLevel); } for (int i = 0; i < lines.size(); i++) { emitIndent(sb, indentLevel, options); sb.append(lines.get(i)); if (i < lines.size() - 1) { emitEOL(sb); } } } else { if (SHOW_DEBUG_LABELS) { emitIndentedText(sb, indentLevel, "DEFAULT", options); } // Default behavior is to place this nodes text on the current // line and then // format each child starting on a new line with the same // indent. if (getThisText().length() > 0) { if (offset == 0) { emitIndent(sb, indentLevel, options); } sb.append(getThisText()); // emitLine(sb); offset = 0; } for (int i = 0, n = getNChildren(); i < n; ++i) { SourceTextNode child = getNthChild(i); child.toFormattedText(sb, indentLevel, offset, options); sb.append(separator); if (!sb.toString().endsWith(EOL)) { sb.append(EOL); } } } } /** * Build up the concatenation of the text contained in this node and all * its children. * * @param sb */ private void appendExpressionText(StringBuilder sb) { StringBuilder sb2 = new StringBuilder(); appendExpressionText2(sb2); sb.append(sb2.toString()); } private void appendExpressionText2(StringBuilder sb) { if (getThisText().length() > 0) { if (sb.length() > 0 && !getThisText().startsWith(";") && !getThisText().startsWith(")") && !getThisText().startsWith("}") && !getThisText().startsWith("]") && !getThisText().startsWith(".")) { char lastChar = sb.charAt(sb.length() - 1); if (lastChar != '(' && lastChar != '{' && lastChar != '!' && lastChar != '[') { sb.append(" "); } } sb.append(getThisText()); } for (int i = 0, n = getNChildren(); i < n; ++i) { SourceTextNode child = getNthChild(i); child.appendExpressionText2(sb); if (i < (n - 1)) { sb.append(separator); } } } private FormatStyle getFormatType() { return formatStyle; } public boolean startsWithBracket() { if (formatStyle == FormatStyle.INNER_CHILDREN_IN_ONE_LEVEL) { return true; } if (getNChildren() > 0) { return getNthChild(0).startsWithBracket(); } return false; } public SourceTextNode consolidateTextLeft() { for (int i = getNChildren() - 1; i >= 0; i--) { prefixText(getNthChild(i).consolidateTextLeft().getThisText()); } children = new ArrayList<SourceTextNode>(); return this; } public SourceTextNode consolidateTextRight() { if (myText.length() == 0) { myText = " "; } for (int i = 0, n = getNChildren(); i < n; ++i) { suffixText(getNthChild(i).consolidateTextRight().getThisText()); } children = new ArrayList<SourceTextNode>(); return this; } private boolean hasForcedLineBreak() { if (forcedBreak || getFormatType().equals(FormatStyle.NEW_LINE) || getFormatType().equals( FormatStyle.COMMENTS_FOLLOWED_BY_CODE) || caldoc != null) { return true; } for (int i = 0, n = getNChildren(); i < n; ++i) { if (getNthChild(i).hasForcedLineBreak()) { return true; } } return false; } public String toString() { StringBuilder sb = new StringBuilder(); appendExpressionText(sb); return sb.toString(); } /** * A class used to indicate the type of formatting associated with an * ExpressionTextNode. * * @author rcypher */ public static final class FormatStyle { /** The text of the sub-tree cannot be broken apart. */ public static final FormatStyle ATOMIC = new FormatStyle("ATOMIC"); /** * The text is an embellishment - this style stops code from being prefixed * or suffixed */ public static final FormatStyle EMBELLISHMENT = new FormatStyle( "EMBELLISHMENT"); /** * The text of the sub-tree can be broken between nodes. The * children have the same indent level as the root. */ public static final FormatStyle CHILDREN_AT_SAME_LEVEL = new FormatStyle( "CHILDREN_AT_SAME_LEVEL"); /** * The text of the sub-tree can be broken between nodes. The * children should indent one more level than the root. */ public static final FormatStyle CHILDREN_IN_ONE_LEVEL = new FormatStyle( "CHILDREN_IN_ONE_LEVEL"); /** * The first and last child will be at the same level the inner * children will be indented one level. The sub tree may be * formatted on a single line if it will fit. This is used for * parenthesized expressions. */ public static final FormatStyle INNER_CHILDREN_IN_ONE_LEVEL = new FormatStyle( "INNER_CHILDREN_IN_ONE_LEVEL"); /** * The text of the sub-tree can be broken between nodes. The first * child should have the same indent level as the root. Other * children should be indented an additional level. */ public static final FormatStyle FIRST_CHILD_AT_LEVEL = new FormatStyle( "FIRST_CHILD_AT_LEVEL"); /** * Force a line break. */ public static final FormatStyle NEW_LINE = new FormatStyle( "NEW_LINE"); /** * The indenting of the children will alternate. Odd numbered * children will be indented one level and even numbered children * will be at the same level as the root. If all children fit on a * single line that is acceptable. */ public static final FormatStyle ALTERNATE_CHILDREN = new FormatStyle( "ALTERNATE_CHILDREN"); /** * If the source doesn't fit on the current line start the children * on a new line and concat to line end. */ public static final FormatStyle CONCAT_CHILDREN_TO_LINE_END_AFTER_NEWLINE = new FormatStyle( "CONCAT_CHILDREN_TO_LINE_END_AFTER_NEWLINE"); /** * If the source doesn't fit on the current line fit the root text * and as many children on each line as possible. Indent starting on * the second line. */ public static final FormatStyle CONCAT_CHILDREN_TO_LINE_END_INDENT_SECOND_LINE = new FormatStyle( "CONCAT_CHILDREN_TO_LINE_END_INDENT_SECOND_LINE"); /** Try to put the first child after the root if possible. */ public static final FormatStyle CONCAT_FIRST_CHILD = new FormatStyle( "CONCAT_FIRST_CHILD"); /** * this format is used for applications - it is very similar to * CHILDREN_IN_ONE_LEVEL except that is has special conditions for * paren */ public static final FormatStyle APPLICATION = new FormatStyle( "APPLICATION"); /** * This style is used when code is followed by a comment on the same * line When SourceTextNode of this style has to be broken across * lines, the comment is placed BEFORE the code This is unusual as * it thereby reorders lexemes. */ public static final FormatStyle CODE_FOLLOWED_BY_COMMENT = new FormatStyle( "CODE_AND_COMMENT"); /** * This style is used when comments preceed some code. The comments * are always rendered on separate lines before the code at the same * indent level. */ public static final FormatStyle COMMENTS_FOLLOWED_BY_CODE = new FormatStyle( "COMMENTS_AND_CODE"); /** String describing this instance of FormatStyle. */ private final String description; private FormatStyle(String description) { this.description = description; } public String toString() { return description; } } } }