Package org.openquark.cal.compiler

Source Code of org.openquark.cal.compiler.SourceModelCALDocFormatter

package org.openquark.cal.compiler;

import org.openquark.cal.compiler.SourceModel.CALDoc;
import org.openquark.cal.compiler.SourceModel.Name;
import org.openquark.cal.compiler.SourceModelCodeFormatter.Options;
import org.openquark.util.General;

/**
* this is the formatter for caldoc comments
* Comments are first formatted without decorations (ie \/**, *, *\/)
* Decorations are added as the final step.
*/
public class SourceModelCALDocFormatter extends
        SourceModelTraverser<Options, Void> {

    /**
     * System Line separator.
     */
    private static final String EOL = System.getProperty("line.separator");

    /**
     * this is the string used to separate CAL doc paragraphs
     */
    private static final String paragraphBreak = EOL + EOL;

    /**
     * this is a regex designed to match the EOL sequence in DOS, MAC or Unix strings
     * the formatting will convert all EOL in the input caldoc comment to the system
     * standard.
     */
    final private static String EOLRegex = "(\r\n)|\n|\r";
   
    /**
     * Internal state indicated whether or not the element is contained within
     * a pre-formatted context
     */
    private boolean isPreformatted = false;

    /**
     * internal flag is used to record when a CR is removed from
     * the end of a CALDoc text fragment that is output.
     * It is used to keep track of paragraph breaks that are split across
     * adjacent plain segments e.g. The CALDoc source model could contain the
     * following two segments: "end of paragraph1.\n", "\nStart of next paragraph"
     */
    private boolean newLineRemoved = false;

    /**
     * this is used to record where an atomic item
     * (one that cannot be split for word wrapping) starts.
     */
    private int atomicItemStart = 0;

    /** this is the standard indent used for items and lists */
    private final static int STANDARD_INDENT = 4;

    /** this is the standard indent used for blocks, e.g. author and arg */
    private final static int BLOCK_INDENT = 2;

    /** the string used to open a caldoc comment*/
    private final static String calDocStart = "/**";
   
    /** the string used to end a caldoc comment*/
    private final static String calDocEnd = " */";
   
    /** the string used to decorate the left hand edge of caldoc comments*/
    private final static String calDocLeft = " * ";
   
    /**
     * this is the current indent in number of spaces. This is incremented and decremented
     * when the formatter enters/leaves certain blocks.
     */
    private int indent = 0;

    /** The StringBuilder used to build up the CAL source. */
    final private StringBuilder sb;

    /**
     * Create CALDocFormatter with StringBuilder to write to.
     * @param sb the stringbuilder to write the comment to.
     */
    SourceModelCALDocFormatter(StringBuilder sb) {
        this.sb = sb;
    }
  
    /**
     * trims trailing spaces from a string buffer
     * @param sb the string buffer to trim
     */
    private void trimRight(StringBuilder sb) {

        int i = sb.length() - 1;
        while (i >= 0 && sb.charAt(i) == ' ') {
            sb.deleteCharAt(i--);
        }
    }

    /**
     * decorates a comment.
     * The comment is returned as a single line comment if it is single line
     * and fits on a single line, otherwise multi line
     * @param options the options used - provides the max line width
     */
    public void decorate(Options options) {
        trimRight(sb);
        if (sb.indexOf(EOL) == -1 && sb.length() + calDocStart.length() + calDocEnd.length() + 1< options.getMaxColumns()) {
            sb.insert(0, calDocStart + " ");
            sb.append(calDocEnd + EOL);
        } else {
            int i=0;
            sb.insert(0, calDocLeft);
            while( (i = sb.indexOf(EOL, i)) > 0) {
                i += EOL.length();
                sb.insert(i, calDocLeft);
            }
            sb.insert(0, calDocStart + EOL);
            sb.append(EOL + calDocEnd + EOL);
        }
    }
   
    /**
     * Creates a string of the specified number of spaces.
     * @param nSpaces
     * @return a String containing the specified number of spaces.
     */
    private static String space(int nSpaces) {
        StringBuilder sb = new StringBuilder(nSpaces);
        for (int i = 0; i < nSpaces; ++i) {
            sb.append(' ');
        }

        return sb.toString();
    }
       
    /**
     * Escapes the specified string for inclusion in the source representation
     * of a CALDoc comment.
     *
     * @param string
     *            the string to be escaped.
     * @return the escaped version of the specified string.
     */
    private static String caldocEscape(String string) {
        String augmentedString = EOL + string; // augment the string so that
                                                // the @-escaping can be
                                                // uniformly applied to even the
                                                // first @ after leading spaces
        String augmentedStringWithEscapedAtSigns = augmentedString.replaceAll(
                "@", "\\\\@");
        String augmentedEscapedString = augmentedStringWithEscapedAtSigns
                .replaceAll("\\{@", "\\\\{@"); // the first arg is the regular
                                                // expression '{@', the second
                                                // arg the replacement string
                                                // '\{@'
        return augmentedEscapedString.substring(EOL.length());
    }

    /**
     * Get the current offset from the start of the line.
     *
     * @param sb
     * @return the offset from the start of the last line.
     */
    private static int getOffset(StringBuilder sb) {
        int offset = sb.length() - sb.lastIndexOf(EOL) - EOL.length();
        if (offset < 0) {
            offset = 0;
        }
        return offset;
    }

  
    /**
     * Formats the specified string into a suitably indented block of text
     * for a CALDoc comment in source form.
     *
     * @param string
     *            the string to be formatted.
     * @param info
     *            the current formatting information
     * @return the formatted string.
     */
    private String formatIntoCALDocLines(String string, Options info) {

        if (isCalDocContentOnLine() && sb.charAt(sb.length() -1) == ' ' &&
               string.length() >0 &&  string.charAt(0) == ' ') {
            string = string.substring(1);
        }

        if (isPreformatted) {
            return string.replaceAll(EOLRegex, EOL +space(indent));
        } else {
           
            string = wrapCalDocLines(string, getOffset(sb), info
                    .getMaxColumns());
            return string.replaceAll("(" + EOLRegex + ")[ \t\f]*", EOL +space(indent));
        }
    }

    /**
     * Merge lines by removing each single CR and replacing with a space,
     * but preserving CRCR as this indicates paragraph break.
     *
     * @param text
     * @return the merged text
     */
    private String mergeLines(String text) {
        StringBuilder str = new StringBuilder(text);

        int i = 0;
        while (i < str.length()) {
            if (str.charAt(i) == '\n') {
                if ((i + 1 >= str.length() || str.charAt(i + 1) != '\n')) {
                    str.replace(i, i + 1, " ");

                }
                i++;
            }
            i++;
        }
        return str.toString().replaceAll(" +", " ");
    }

    /**
     * This is used to break CAlDoc text at spaces. We keep track of CR that
     * are removed as adjacent CRs that indicate a paragraph break can
     * appear across adjacent text segments.
     *
     * @param text
     *            the text to wrap
     * @param linePos
     *            the position on the current line
     * @param width
     *            the text width.
     * @return the text with single new lines replaced by spaces
     */
    private String wrapCalDocLines(String text, int linePos, int width) {

        String normalizedText = text.replaceAll("[\t ]+", " ") // compress
                                                                // multiple
                                                                // spaces
                .replaceAll(EOLRegex, "\n") // use canonical linefeeds
                .replaceAll(" ?\n ?", "\n") // trim lines
                .replaceAll("\n[\t ]*", "\n"); // strip spaces from start of comment

        if (normalizedText.length() == 0) {
            return "";
        }

        if (normalizedText.matches("(?s)\n *")) {
            if (newLineRemoved) {
                newLineRemoved = false;
                return paragraphBreak;
            } else {
                    newLineRemoved = true;
                    return "";
            }
        }


        String prefix = "";

        if (newLineRemoved) {
            prefix = " ";
        }

        if (normalizedText.matches("(?s)\n\n.*")) {
            prefix = paragraphBreak;
            linePos = 0;
            normalizedText = normalizedText.substring(2);
            newLineRemoved = false;
        }

        StringBuilder buffer = new StringBuilder(mergeLines(normalizedText));
        int index = 0;

        if (normalizedText.matches("(?s)\n[^\n].*")) {
            if (newLineRemoved) {
                prefix = paragraphBreak;
                linePos = 0;
            }
            normalizedText = normalizedText.substring(1);
        }

        if (normalizedText.matches("(?s).*[^\n]\\n *")) {
            newLineRemoved = true;
        } else {
            newLineRemoved = false;
        }

        while (buffer.length() - index > width - linePos) {

            // if the text contains a line feed before the line stop,
            // there's
            // no need to wrap.
            int nl = buffer.indexOf("\n", index);
            if (nl > 0 && nl <= index + width - linePos) {
                index = nl + 1;
                linePos = 0;
                continue;
            }

            // find space to break line at, looking back from line limit
            int space = buffer.lastIndexOf(" ", index + width - linePos);

            // if we failed to find a space looking back, we have no choice
            // but to
            // look for the first space beyond the line limit
            if (space < index) {
                space = buffer.indexOf(" ", index + width - linePos);
            }

            if (space < 0 || space == buffer.length() - 1) {
                break;
            }

            // trim trailing spaces from line
            while (space >= index && buffer.charAt(space) == ' ') {
                buffer.delete(space, space + 1);
                space--;
            }
            space++;
            buffer.insert(space, EOL);
            index = space + EOL.length();
            linePos = 0;
        }
        return prefix + buffer.toString().replaceAll(" +", " ");
    }
   
    /**
     * @param moduleName
     *            the source model element to be traversed
     * @param options
     *            unused argument
     * @return null
     */
    public Void visit_Name_Module(Name.Module moduleName, Options options) {

        SourceModel.verifyArg(moduleName, "moduleName");

        moduleName.getQualifier().accept(this, options);

        if (moduleName.getQualifier().getNComponents() > 0) {
            sb.append(".");
        }
        sb.append(moduleName.getUnqualifiedModuleName());

        return null;
    }

    /**
     * @param qualifier
     *            the source model element to be traversed
     * @param options
     *            unused argument
     * @return null
     */
    public Void visit_Name_Module_Qualifier(
            Name.Module.Qualifier qualifier, Options options) {

        SourceModel.verifyArg(qualifier, "qualifier");
        for (int i = 0, n = qualifier.getNComponents(); i < n; ++i) {
            if (i > 0) {
                sb.append(".");
            }
            sb.append(qualifier.getNthComponents(i));
        }
        return null;
    }

    /**
     * @param cons
     *            the source model element to be traversed
     * @param options
     *            unused argument
     * @return null
     */
    public Void visit_Name_DataCons(Name.DataCons cons, Options options) {

        SourceModel.verifyArg(cons, "cons");

        if (cons.getModuleName() != null) {
            cons.getModuleName().accept(this, options);
        }

        if (cons.getModuleName() != null) {
            sb.append('.');
        }

        sb.append(cons.getUnqualifiedName());

        return null;
    }

    /**
     * @param function
     *            the source model element to be traversed
     * @param options
     *            unused argument
     * @return null
     */
    public Void visit_Name_Function(Name.Function function, Options options) {

        SourceModel.verifyArg(function, "function");

        if (function.getModuleName() != null) {
            function.getModuleName().accept(this, options);
            sb.append('.');
        }

        sb.append(function.getUnqualifiedName());
        return null;
    }

    /**
     * @param typeClass
     *            the source model element to be traversed
     * @param options
     *            unused argument
     * @return null
     */
    public Void visit_Name_TypeClass(Name.TypeClass typeClass, Options options) {

        SourceModel.verifyArg(typeClass, "typeClass");

        if (typeClass.getModuleName() != null) {
            typeClass.getModuleName().accept(this, options);
            sb.append('.');
        }

        sb.append(typeClass.getUnqualifiedName());
        return null;
    }

    /**
     * @param cons
     *            the source model element to be traversed
     * @param options
     *            unused argument
     * @return null
     */
    public Void visit_Name_TypeCons(Name.TypeCons cons, Options options) {

        SourceModel.verifyArg(cons, "cons");

        if (cons.getModuleName() != null) {
            cons.getModuleName().accept(this, options);
            sb.append('.');
        }

        sb.append(cons.getUnqualifiedName());
        return null;
    }

    /**
     * @param cons
     *            the source model element to be traversed
     * @param options
     *            unused argument
     * @return null
     */
    public Void visit_Name_WithoutContextCons(Name.WithoutContextCons cons,
            Options options) {

        SourceModel.verifyArg(cons, "cons");

        if (cons.getModuleName() != null) {
            cons.getModuleName().accept(this, options);
            sb.append('.');
        }

        sb.append(cons.getUnqualifiedName());
        return null;
    }

    //TODO-MB
    /**
     * @param comment
     *            the source model element to be traversed
     * @param options
     *            unused argument
     * @return null
     */
    protected Void visit_CALDoc_Comment_Helper(CALDoc.Comment comment,
            Options options) {

        comment.getDescription().accept(this, options);

        for (int i = 0, n = comment.getNTaggedBlocks(); i < n; i++) {
            comment.getNthTaggedBlock(i).accept(this, options);
        }

        return null;
    }

    /**
     * @param segment
     *            the source model element to be traversed
     * @param options
     *            unused argument
     * @return null
     */
    public Void visit_CALDoc_TextSegment_Plain(
            CALDoc.TextSegment.Plain segment, Options options) {

        SourceModel.verifyArg(segment, "segment");

        String escapedAndNewlineNormalizedText = caldocEscape(General
                .toPlatformLineSeparators(segment.getText()));

        //TODO-MB
        String s = formatIntoCALDocLines(escapedAndNewlineNormalizedText, options);
       
        if (!isCalDocContentOnLine()) {
            s = s.replaceAll("^ +", "");
        }
       
        sb.append(s);

        return null;
    }

    /**
     * @param segment
     *            the source model element to be traversed
     * @param options
     *            unused argument
     * @return null
     */
    public Void visit_CALDoc_TextSegment_Preformatted(
            CALDoc.TextSegment.Preformatted segment, Options options) {

        SourceModel.verifyArg(segment, "segment");

        SourceModelCALDocFormatter segmentFormatter = new SourceModelCALDocFormatter(sb);
        segmentFormatter.isPreformatted = true;

        final int nSegments = segment.getNSegments();
        for (int i = 0; i < nSegments; i++) {
            segment.getNthSegment(i).accept(segmentFormatter, options);
        }

        return null;
    }

    /**
     * this is used to mark the beginning of a CAlDoc item that cannot be
     * split
     */
    private void beginAtomicCalDocItem() {
        atomicItemStart = sb.length();
    }

    /**
     * this is used to mark the end of an atomic caldoc item. If the item extends
     * past the line's end it is moved to the next line.
     *
     * @param options
     */
    private void endAtomicCalDocItem(Options options) {
        assert(atomicItemStart >= 0);
       
        if (getOffset(sb) > options.getMaxColumns() &&
                sb.indexOf(EOL, atomicItemStart) == -1) {
           
            //if we are breaking at a space, the space must be removed
            if (sb.charAt(atomicItemStart) == ' ') {
                sb.deleteCharAt(atomicItemStart);
            }
           
            sb.insert(atomicItemStart, EOL + space(indent));
        }
    }

    /**
     * Starts a new calddoc line with the appropriate left margin indent
     */
    private void emitCalDocLine() {
        sb.append(EOL).append(
                        space(indent));
    }

    /**
     * Write out an atomic piece of CAL doc text to the output buffer if the
     * text is too long to fit on the current line, a new line is started.
     *
     * Start the text on a new line if the text is too long and there is a
     * space at the beginning.
     *
     * @param text
     * @param options
     */
    private void emitCalDocText(String text, Options options) {
        if (text.length() == 0) {
            return;
        }
       
        if (getOffset(sb) + text.length() > options.getMaxColumns() &&
                isCalDocContentOnLine() &&
                (sb.charAt(sb.length()-1) == ' ' || text.charAt(text.length()-1) == ' ')) {
            emitCalDocLine();
            sb.append(text);
        }
        else {
            sb.append(text);
        }
    }

    /**
     * Write out a closing tag
     *
     * Enforces the rule that there must be a space before the atomic item.
     * @param options - formatting options
     */
    private void emitCloseTag(Options options) {
        sb.append("@}");
    }
   
    /**
     * Checks to see if there is content on the current line
     *
     * @return true if there is some content on the last caldoc line in the
     *         output buffer
     */
    private boolean isCalDocContentOnLine() {
        int start = sb.lastIndexOf(General.SYSTEM_EOL, sb.length());
        if (start < 0) {
            start = 0;
        } else {
            start += General.SYSTEM_EOL.length();
        }

        while(start < sb.length()) {
            if (sb.charAt(start++) != ' ') {
                return true;
            }
        }
       
        return false;
    }

    /**
     * Start a new CalDoc line if there is content on the current line
     */
    private void ensureOnNewLine() {
        if (isCalDocContentOnLine()) {
            emitCalDocLine();
        }
    }
   
    /**
     * @param segment
     *            the source model element to be traversed
     * @param options
     *            unused argument
     * @return null
     */
    public Void visit_CALDoc_TextSegment_InlineTag_URL(
            CALDoc.TextSegment.InlineTag.URL segment, Options options) {

        SourceModel.verifyArg(segment, "segment");

        Options info = options;

        sb.append("{@url ");

        beginAtomicCalDocItem();
        segment.getContent().accept(this, info);
        emitCloseTag(options);
        endAtomicCalDocItem(options);

        return null;
    }

    private void visit_CALDoc_TextSegment_InlineTag_Link_WithContext_Helper(
            CALDoc.TextSegment.InlineTag.Link.WithContext link, Options info) {

        emitCalDocText("{@link ", info);
        emitCalDocText(link.getContextKeyword() + " = ", info);

        beginAtomicCalDocItem();
        link.getAbstractCrossReference().accept(this, info);
        sb.append("@}");
        endAtomicCalDocItem(info);
    }

    /**
     * @param segment
     *            the source model element to be traversed
     * @param options
     *            unused argument
     * @return null
     */
    public Void visit_CALDoc_TextSegment_InlineTag_Link_Function(
            CALDoc.TextSegment.InlineTag.Link.Function segment, Options options) {

        SourceModel.verifyArg(segment, "segment");
        visit_CALDoc_TextSegment_InlineTag_Link_WithContext_Helper(segment,
                options);
        return null;
    }

    /**
     * @param segment
     *            the source model element to be traversed
     * @param options
     *            unused argument
     * @return null
     */
    public Void visit_CALDoc_TextSegment_InlineTag_Link_Module(
            CALDoc.TextSegment.InlineTag.Link.Module segment, Options options) {

        SourceModel.verifyArg(segment, "segment");

        visit_CALDoc_TextSegment_InlineTag_Link_WithContext_Helper(segment,
                options);
        return null;
    }

    /**
     * @param segment
     *            the source model element to be traversed
     * @param options
     *            unused argument
     * @return null
     */
    public Void visit_CALDoc_TextSegment_InlineTag_Link_TypeCons(
            CALDoc.TextSegment.InlineTag.Link.TypeCons segment, Options options) {

        SourceModel.verifyArg(segment, "segment");

        visit_CALDoc_TextSegment_InlineTag_Link_WithContext_Helper(segment,
                options);
        return null;
    }

    /**
     * @param segment
     *            the source model element to be traversed
     * @param options
     *            unused argument
     * @return null
     */
    public Void visit_CALDoc_TextSegment_InlineTag_Link_DataCons(
            CALDoc.TextSegment.InlineTag.Link.DataCons segment, Options options) {

        SourceModel.verifyArg(segment, "segment");

        visit_CALDoc_TextSegment_InlineTag_Link_WithContext_Helper(segment,
                options);
        return null;
    }

    /**
     * @param segment
     *            the source model element to be traversed
     * @param options
     *            unused argument
     * @return null
     */
    public Void visit_CALDoc_TextSegment_InlineTag_Link_TypeClass(
            CALDoc.TextSegment.InlineTag.Link.TypeClass segment, Options options) {

        SourceModel.verifyArg(segment, "segment");

        visit_CALDoc_TextSegment_InlineTag_Link_WithContext_Helper(segment,
                options);
        return null;
    }

    private void visit_CALDoc_TextSegment_InlineTag_Link_WithoutContext_Helper(
            CALDoc.TextSegment.InlineTag.Link.WithoutContext segment,
            Options info) {

        emitCalDocText("{@link ", info);

        beginAtomicCalDocItem();
        segment.getAbstractCrossReference().accept(this, info);
        sb.append("@}");
        endAtomicCalDocItem(info);
    }

    /**
     * @param segment
     *            the source model element to be traversed
     * @param options
     *            unused argument
     * @return null
     */
    public Void visit_CALDoc_TextSegment_InlineTag_Link_ConsNameWithoutContext(
            CALDoc.TextSegment.InlineTag.Link.ConsNameWithoutContext segment,
            Options options) {

        SourceModel.verifyArg(segment, "segment");

        visit_CALDoc_TextSegment_InlineTag_Link_WithoutContext_Helper(
                segment, options);
        return null;
    }

    /**
     * @param segment
     *            the source model element to be traversed
     * @param options
     *            unused argument
     * @return null
     */
    public Void visit_CALDoc_TextSegment_InlineTag_Link_FunctionWithoutContext(
            CALDoc.TextSegment.InlineTag.Link.FunctionWithoutContext segment,
            Options options) {

        SourceModel.verifyArg(segment, "segment");

        visit_CALDoc_TextSegment_InlineTag_Link_WithoutContext_Helper(
                segment, options);
        return null;
    }

    private void visit_CALDoc_TextSegment_InlineTag_WithTextBlockContent(
            CALDoc.TextSegment.InlineTag.InlineTagWithTextBlockContent segment,
            Options info) {

        emitCalDocText("{@" + segment.getTagName(), info);
        emitCalDocText(" ", info);
        segment.getContent().accept(this, info);

        emitCloseTag(info);
    }

    /**
     * @param segment
     *            the source model element to be traversed
     * @param options
     *            unused argument
     * @return null
     */
    public Void visit_CALDoc_TextSegment_InlineTag_TextFormatting_Emphasized(
            CALDoc.TextSegment.InlineTag.TextFormatting.Emphasized segment,
            Options options) {

        SourceModel.verifyArg(segment, "segment");

        visit_CALDoc_TextSegment_InlineTag_WithTextBlockContent(segment,
                options);
        return null;
    }

    /**
     * @param segment
     *            the source model element to be traversed
     * @param options
     *            unused argument
     * @return null
     */
    public Void visit_CALDoc_TextSegment_InlineTag_TextFormatting_StronglyEmphasized(
            CALDoc.TextSegment.InlineTag.TextFormatting.StronglyEmphasized segment,
            Options options) {

        SourceModel.verifyArg(segment, "segment");

        visit_CALDoc_TextSegment_InlineTag_WithTextBlockContent(segment,
                options);
        return null;
    }

    /**
     * @param segment
     *            the source model element to be traversed
     * @param options
     *            unused argument
     * @return null
     */
    public Void visit_CALDoc_TextSegment_InlineTag_TextFormatting_Superscript(
            CALDoc.TextSegment.InlineTag.TextFormatting.Superscript segment,
            Options options) {

        SourceModel.verifyArg(segment, "segment");

        visit_CALDoc_TextSegment_InlineTag_WithTextBlockContent(segment,
                options);
        return null;
    }

    /**
     * @param segment
     *            the source model element to be traversed
     * @param options
     *            unused argument
     * @return null
     */
    public Void visit_CALDoc_TextSegment_InlineTag_TextFormatting_Subscript(
            CALDoc.TextSegment.InlineTag.TextFormatting.Subscript segment,
            Options options) {

        SourceModel.verifyArg(segment, "segment");

        visit_CALDoc_TextSegment_InlineTag_WithTextBlockContent(segment,
                options);
        return null;
    }

    /**
     * @param segment
     *            the source model element to be traversed
     * @param options
     *            unused argument
     * @return null
     */
    public Void visit_CALDoc_TextSegment_InlineTag_Summary(
            CALDoc.TextSegment.InlineTag.Summary segment, Options options) {

        SourceModel.verifyArg(segment, "segment");

        visit_CALDoc_TextSegment_InlineTag_WithTextBlockContent(segment,
                options);
        return null;
    }

    private void visit_CALDoc_TextSegment_InlineTag_WithPreformattedContent(
            CALDoc.TextSegment.InlineTag.InlineTagWithPreformattedContent segment,
            Options info) {

        final String open = "{@" + segment.getTagName() + " ";
        final String close = "@}";
        StringBuilder codeBlock = new StringBuilder();

        SourceModelCALDocFormatter contentFormatter = new SourceModelCALDocFormatter(codeBlock);
        contentFormatter.isPreformatted = true;
       
        segment.getContent().accept(contentFormatter, info);

        // does the code item span more than one line?
        if (codeBlock.indexOf(EOL ) >= 0) {
            ensureOnNewLine();
            emitCalDocText(open, info);
            sb.append(codeBlock.toString().replaceAll("(?s)(" + EOLRegex + ") ", EOL));
            sb.append(close);
        } else {
            // no - make sure the open, text and close are one atomic item
            emitCalDocText(open + codeBlock.toString() + close, info);
        }
    }

    /**
     * @param segment
     *            the source model element to be traversed
     * @param options
     *            unused argument
     * @return null
     */
    public Void visit_CALDoc_TextSegment_InlineTag_Code(
            CALDoc.TextSegment.InlineTag.Code segment, Options options) {

        SourceModel.verifyArg(segment, "segment");

        visit_CALDoc_TextSegment_InlineTag_WithPreformattedContent(segment,
                options);
        return null;
    }

    private void visit_CALDoc_TextSegment_InlineTag_List(
            CALDoc.TextSegment.InlineTag.List list, Options info) {

        // start the ordered list on a new line if we're not already on one
        ensureOnNewLine();
        sb.append("{@").append(list.getTagName());
       
        indent += STANDARD_INDENT;               
        for (int i = 0; i < list.getNItems(); i++) {
            emitCalDocLine();
            list.getNthItem(i).accept(this, info);
        }
        indent -= STANDARD_INDENT;
       
        emitCalDocLine();
        sb.append("@}");

    }

    /**
     * @param list
     *            the source model element to be traversed
     * @param options
     *            unused argument
     * @return null
     */
    public Void visit_CALDoc_TextSegment_InlineTag_List_Unordered(
            CALDoc.TextSegment.InlineTag.List.Unordered list, Options options) {

        SourceModel.verifyArg(list, "list");

        visit_CALDoc_TextSegment_InlineTag_List(list, options);

        return null;
    }

    /**
     * @param list
     *            the source model element to be traversed
     * @param options
     *            unused argument
     * @return null
     */
    public Void visit_CALDoc_TextSegment_InlineTag_List_Ordered(
            CALDoc.TextSegment.InlineTag.List.Ordered list, Options options) {

        SourceModel.verifyArg(list, "list");

        visit_CALDoc_TextSegment_InlineTag_List(list, options);

        return null;
    }

    /**
     * @param item
     *            the source model element to be traversed
     * @param options
     *            unused argument
     * @return null
     */
    public Void visit_CALDoc_TextSegment_InlineTag_List_Item(
            CALDoc.TextSegment.InlineTag.List.Item item, Options options) {

        SourceModel.verifyArg(item, "item");

        Options info = options;

        emitCalDocText("{@item ", options);

        int itemStart = sb.length();

        indent += STANDARD_INDENT;
        item.getContent().accept(this, info);
        indent -= STANDARD_INDENT;

        // does the item span more than one line?
        if (sb.indexOf(EOL, itemStart) > 0 ) {
            ensureOnNewLine();
        }

        emitCloseTag(options);
        return null;
    }

    /**
     * @param block
     *            the source model element to be traversed
     * @param options
     *            unused argument
     * @return null
     */
    public Void visit_CALDoc_TextBlock(CALDoc.TextBlock block, Options options) {

        SourceModel.verifyArg(block, "block");

        for (int i = 0, nSegments = block.getNSegments(); i < nSegments; i++) {
            newLineRemoved = false
            block.getNthSegment(i).accept(this, options);
        }

        return null;
    }

    public void taggedBlockHelper(CALDoc.TaggedBlock taggedBlock, Options options) {
        ensureOnNewLine();
       
    }
   
    /**
     * @param authorBlock
     *            the source model element to be traversed
     * @param options
     *            unused argument
     * @return null
     */
    public Void visit_CALDoc_TaggedBlock_Author(
            CALDoc.TaggedBlock.Author authorBlock, Options options) {

        SourceModel.verifyArg(authorBlock, "authorBlock");

        ensureOnNewLine();
        sb.append(CALDoc.TaggedBlock.Author.AUTHOR_TAG ).append(" ");
        authorBlock.getTextBlock().accept(this, options);
      
       return null;
    }

    /**
     * @param deprecatedBlock
     *            the source model element to be traversed
     * @param options
     *            unused argument
     * @return null
     */
    public Void visit_CALDoc_TaggedBlock_Deprecated(
            CALDoc.TaggedBlock.Deprecated deprecatedBlock, Options options) {

        SourceModel.verifyArg(deprecatedBlock, "deprecatedBlock");

        ensureOnNewLine();
        sb.append(CALDoc.TaggedBlock.Deprecated.DEPRECATED_TAG).append(" ");
        indent += BLOCK_INDENT;
        deprecatedBlock.getTextBlock().accept(this, options);
        indent -= BLOCK_INDENT;
       
        return null;
    }

    /**
     * @param returnBlock
     *            the source model element to be traversed
     * @param options
     *            unused argument
     * @return null
     */
    public Void visit_CALDoc_TaggedBlock_Return(
            CALDoc.TaggedBlock.Return returnBlock, Options options) {

        SourceModel.verifyArg(returnBlock, "returnBlock");

        ensureOnNewLine();
        sb.append(CALDoc.TaggedBlock.Return.RETURN_TAG).append(" ");
        indent += BLOCK_INDENT;
        returnBlock.getTextBlock().accept(this, options);
        indent -= BLOCK_INDENT;
       
        return null;
    }

    /**
     * @param versionBlock
     *            the source model element to be traversed
     * @param options
     *            unused argument
     * @return null
     */
    public Void visit_CALDoc_TaggedBlock_Version(
            CALDoc.TaggedBlock.Version versionBlock, Options options) {

        SourceModel.verifyArg(versionBlock, "versionBlock");

        ensureOnNewLine();
        sb.append(CALDoc.TaggedBlock.Version.VERSION_TAG).append(" ");
        indent += BLOCK_INDENT;
        versionBlock.getTextBlock().accept(this, options);
        indent -= BLOCK_INDENT;
       
        return null;
    }

    /**
     * @param argBlock
     *            the source model element to be traversed
     * @param options
     *            unused argument
     * @return null
     */
    public Void visit_CALDoc_TaggedBlock_Arg(
            CALDoc.TaggedBlock.Arg argBlock, Options options) {

        SourceModel.verifyArg(argBlock, "argBlock");

        ensureOnNewLine();
        sb.append(CALDoc.TaggedBlock.Arg.ARG_TAG).append(' ')
                .append(argBlock.getArgName().getName().getCalSourceForm());

        indent += BLOCK_INDENT;
        argBlock.getTextBlock().accept(this, options);
        indent -= BLOCK_INDENT;

        return null;
    }

    /**
     * @param function
     *            the source model element to be traversed
     * @param options
     *            unused argument
     * @return null
     */
    public Void visit_CALDoc_TaggedBlock_See_Function(
            CALDoc.TaggedBlock.See.Function function, Options options) {

        SourceModel.verifyArg(function, "function");

        Options info = options;
        ensureOnNewLine();
        sb.append(CALDoc.TaggedBlock.See.SEE_TAG).append(
                " function = ");
        function.getNthFunctionName(0).accept(this, info);

        for (int i = 1, n = function.getNFunctionNames(); i < n; i++) {
            sb.append(", ");
            beginAtomicCalDocItem();
            function.getNthFunctionName(i).accept(this, info);
            endAtomicCalDocItem(options);
        }

        return null;
    }

    /**
     * @param module
     *            the source model element to be traversed
     * @param options
     *            unused argument
     * @return null
     */
    public Void visit_CALDoc_TaggedBlock_See_Module(
            CALDoc.TaggedBlock.See.Module module, Options options) {

        SourceModel.verifyArg(module, "module");

        Options info = options;

        ensureOnNewLine();
        sb.append(CALDoc.TaggedBlock.See.SEE_TAG).append(
                " module = ");
        module.getNthModuleName(0).accept(this, info);

        for (int i = 1, n = module.getNModuleNames(); i < n; i++) {
            sb.append(", ");
            beginAtomicCalDocItem();
            module.getNthModuleName(i).accept(this, info);
            endAtomicCalDocItem(options);
        }

        return null;
    }

    /**
     * @param typeCons
     *            the source model element to be traversed
     * @param options
     *            unused argument
     * @return null
     */
    public Void visit_CALDoc_TaggedBlock_See_TypeCons(
            CALDoc.TaggedBlock.See.TypeCons typeCons, Options options) {

        SourceModel.verifyArg(typeCons, "typeCons");

        Options info = options;

        ensureOnNewLine();
        sb.append(CALDoc.TaggedBlock.See.SEE_TAG).append(
                " typeConstructor = ");
        typeCons.getNthTypeConsName(0).accept(this, info);

        for (int i = 1, n = typeCons.getNTypeConsNames(); i < n; i++) {
            sb.append(", ");
            beginAtomicCalDocItem();
            typeCons.getNthTypeConsName(i).accept(this, info);
            endAtomicCalDocItem(options);
        }

        return null;
    }

    /**
     * @param dataCons
     *            the source model element to be traversed
     * @param options
     *            unused argument
     * @return null
     */
    public Void visit_CALDoc_TaggedBlock_See_DataCons(
            CALDoc.TaggedBlock.See.DataCons dataCons, Options options) {

        Options info = options;

        ensureOnNewLine();
        sb.append(CALDoc.TaggedBlock.See.SEE_TAG).append(
                " dataConstructor = ");
        dataCons.getNthDataConsName(0).accept(this, info);

        for (int i = 1, n = dataCons.getNDataConsNames(); i < n; i++) {
            sb.append(", ");
            beginAtomicCalDocItem();
            dataCons.getNthDataConsName(i).accept(this, info);
            endAtomicCalDocItem(options);
        }

        return null;
    }

    /**
     * @param typeClass
     *            the source model element to be traversed
     * @param options
     *            unused argument
     * @return null
     */
    public Void visit_CALDoc_TaggedBlock_See_TypeClass(
            CALDoc.TaggedBlock.See.TypeClass typeClass, Options options) {

        SourceModel.verifyArg(typeClass, "typeClass");

        Options info = options;

        ensureOnNewLine();
        sb.append(CALDoc.TaggedBlock.See.SEE_TAG).append(
                " typeClass = ");
        typeClass.getNthTypeClassName(0).accept(this, info);

        for (int i = 1, n = typeClass.getNTypeClassNames(); i < n; i++) {
            sb.append(", ");
            beginAtomicCalDocItem();
            typeClass.getNthTypeClassName(i).accept(this, info);
            endAtomicCalDocItem(options);
        }

        return null;
    }

    /**
     * @param reference
     *            the source model element to be traversed
     * @param options
     *            unused argument
     * @return null
     */
    public Void visit_CALDoc_CrossReference_Function(
            CALDoc.CrossReference.Function reference, Options options) {

        SourceModel.verifyArg(reference, "reference");

        if (reference.isChecked()) {
            reference.getName().accept(this, options);
        } else {
            sb.append('\"');
            reference.getName().accept(this, options);
            sb.append('\"');
        }

        return null;
    }

    /**
     * @param reference
     *            the source model element to be traversed
     * @param options
     *            unused argument
     * @return null
     */
    public Void visit_CALDoc_CrossReference_Module(
            CALDoc.CrossReference.Module reference, Options options) {

        SourceModel.verifyArg(reference, "reference");

        if (reference.isChecked()) {
            reference.getName().accept(this, options);
        } else {
            sb.append('\"');
            reference.getName().accept(this, options);
            sb.append('\"');
        }
        return null;
    }

    /**
     * @param reference
     *            the source model element to be traversed
     * @param options
     *            unused argument
     * @return null
     */
    public Void visit_CALDoc_CrossReference_TypeCons(
            CALDoc.CrossReference.TypeCons reference, Options options) {

        SourceModel.verifyArg(reference, "reference");

        if (reference.isChecked()) {
            reference.getName().accept(this, options);
        } else {
            sb.append('\"');
            reference.getName().accept(this, options);
            sb.append('\"');
        }
        return null;
    }

    /**
     * @param reference
     *            the source model element to be traversed
     * @param options
     *            unused argument
     * @return null
     */
    public Void visit_CALDoc_CrossReference_DataCons(
            CALDoc.CrossReference.DataCons reference, Options options) {

        SourceModel.verifyArg(reference, "reference");

        if (reference.isChecked()) {
            reference.getName().accept(this, options);
        } else {
            sb.append('\"');
            reference.getName().accept(this, options);
            sb.append('\"');
        }
        return null;
    }

    /**
     * @param reference
     *            the source model element to be traversed
     * @param options
     *            the formatting options
     * @return null
     */
    public Void visit_CALDoc_CrossReference_TypeClass(
            CALDoc.CrossReference.TypeClass reference, Options options) {

        SourceModel.verifyArg(reference, "reference");

        if (reference.isChecked()) {
            reference.getName().accept(this, options);
        } else {
            sb.append('\"');
            reference.getName().accept(this, options);
            sb.append('\"');
        }
        return null;
    }

    /**
     * @param reference
     *            the source model element to be traversed
     * @param options
     *            the formatting options
     * @return null
     */
    public Void visit_CALDoc_CrossReference_WithoutContextCons(
            CALDoc.CrossReference.WithoutContextCons reference, Options options) {

        SourceModel.verifyArg(reference, "reference");

        if (reference.isChecked()) {
            reference.getName().accept(this, options);
        } else {
            sb.append('\"');
            reference.getName().accept(this, options);
            sb.append('\"');
        }
        return null;
    }

    /**
     * @param seeBlock
     *            the source model element to be traversed
     * @param options
     *            the formatting options
     * @return null
     */
    public Void visit_CALDoc_TaggedBlock_See_WithoutContext(
            CALDoc.TaggedBlock.See.WithoutContext seeBlock, Options options) {

        SourceModel.verifyArg(seeBlock, "seeBlock");

        ensureOnNewLine();
        sb.append(CALDoc.TaggedBlock.See.SEE_TAG).append(" ");
        seeBlock.getNthReferencedName(0).accept(this, options);

        for (int i = 1, n = seeBlock.getNReferencedNames(); i < n; i++) {
            sb.append(", ");

            beginAtomicCalDocItem();
            seeBlock.getNthReferencedName(i).accept(this, options);
            endAtomicCalDocItem(options);

        }
        return null;
    }

}
TOP

Related Classes of org.openquark.cal.compiler.SourceModelCALDocFormatter

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.