Example #1
0
def prettyNode(node, opts, rslt, enableBreaks=False, enableVerbose=False):
    global indent
    global result
    global pretty
    global verbose
    global breaks
    global afterLine
    global afterBreak
    global afterDoc
    global afterDivider
    global afterArea
    global options

    result = rslt

    options = opts
    opts.prettypIndentString = eval("'" + opts.prettypIndentString + "'")
    opts.prettypCommentsInlinePadding = eval(
        "'" + opts.prettypCommentsInlinePadding + "'")
    # allow for escapes like "\t"
    # split trailing comment cols into an array
    if (opts.prettypCommentsTrailingCommentCols and isinstance(
            opts.prettypCommentsTrailingCommentCols, basestring)):
        opts.prettypCommentsTrailingCommentCols = [
            int(column.strip())
            for column in opts.prettypCommentsTrailingCommentCols.split(",")
        ]
        opts.prettypCommentsTrailingCommentCols.sort(
        )  # make sure they are ascending!
    # or make sure it's a list of int's
    elif (isinstance(opts.prettypCommentsTrailingCommentCols, list) and reduce(
            lambda y, z: y and z,
        [isinstance(x, int)
         for x in opts.prettypCommentsTrailingCommentCols], True)):
        opts.prettypCommentsTrailingCommentCols.sort(
        )  # make sure they are ascending!
    # or pass
    else:
        #raise TypeError, "Unsuitable type for option --pretty-print-comments-trailing-commentCols"
        pass

    if opts.prettypCommentsBlockAdd:
        Comment.fill(node)

    indent = 0
    result = [u""]
    pretty = opts.prettyPrint
    verbose = enableVerbose
    breaks = enableBreaks
    afterLine = False
    afterBreak = False
    afterDoc = False
    afterDivider = False
    afterArea = False

    return _prettyNode(node, opts, result)
Example #2
0
    def serializeNode(node, opts, rslt, enableBreaks=False, enableVerbose=False):

        global indent
        global result
        global pretty
        global verbose
        global breaks
        global afterLine
        global afterBreak
        global afterDoc
        global afterDivider
        global afterArea
        global options

        result = rslt

        options = opts
        opts.prettypIndentString          = eval("'" + opts.prettypIndentString + "'")
        opts.prettypCommentsInlinePadding = eval("'" + opts.prettypCommentsInlinePadding + "'")
                                                                  # allow for escapes like "\t"
        # split trailing comment cols into an array
        if (opts.prettypCommentsTrailingCommentCols and
            isinstance(opts.prettypCommentsTrailingCommentCols, basestring)):
            opts.prettypCommentsTrailingCommentCols = [int(column.strip()) for column in opts.prettypCommentsTrailingCommentCols.split(",")]
            opts.prettypCommentsTrailingCommentCols.sort() # make sure they are ascending!
        # or make sure it's a list of int's
        elif (isinstance(opts.prettypCommentsTrailingCommentCols, list) and
            reduce(lambda y,z: y and z,
                   [isinstance(x,int) for x in opts.prettypCommentsTrailingCommentCols],
                   True)):
            opts.prettypCommentsTrailingCommentCols.sort() # make sure they are ascending!
        # or pass
        else:
            #raise TypeError, "Unsuitable type for option --pretty-print-comments-trailing-commentCols"
            pass

        if opts.prettypCommentsBlockAdd:
            Comment.fill(node)

        indent       = 0
        result       = [u""]
        pretty       = opts.prettyPrint
        verbose      = enableVerbose
        breaks       = enableBreaks
        afterLine    = False
        afterBreak   = False
        afterDoc     = False
        afterDivider = False
        afterArea    = False

        return [ Packer.symbol_base.emit(node) ]  # caller expects []
Example #3
0
    def process_comments(self, node):
        hint = None
        if node.comments:
            commentsArray = Comment.parseNode(node, process_txt=False, want_errors=True)
            if any(commentsArray):
                hint = Hint()
                # fill hint from commentAttributes
                for commentAttributes in commentsArray:
                    for entry in commentAttributes:
                        # errors treated later
                        if 'error' in entry:
                            continue
                        # add interesting entries to tree
                        cat = entry['category']
                        if cat not in ('ignore', 'lint', 'require', 'use', 'asset', 'cldr'):
                            continue
                        else:
                            functor = entry.get('functor') # will be None for non-functor keys like @ignore, @require, ...
                            hint.add_entries((cat,functor), entry['arguments'])  # hint.hints['lint']['ignoreUndefined']{'foo','bar'}
                                                                         # hint.hints['ignore'][None]{'foo','bar'}

                # loop again for error logging (here, so you can ignore error entries in the same comment)
                for commentAttributes in commentsArray:
                    for entry in commentAttributes:
                        if 'error' in entry:
                            if self._key_is_ignored(entry['category'], hint):
                                continue
                            else:
                                msg = "%s (%s): %s" % (entry['filename'], entry['lineno'], entry['message'])
                                msg += (": %s" % entry['text']) if 'text' in entry and entry['text'] else ''
                                context.console.warn(msg)

        return hint
Example #4
0
 def process_comments(self, node):
     hint = None
     if node.comments:
         commentsArray = Comment.parseNode(
             node, process_txt=False)  #, want_errors=True)
         if any(commentsArray):
             hint = Hint()
             # fill hint from commentAttributes
             for commentAttributes in commentsArray:
                 for entry in commentAttributes:
                     cat = entry['category']
                     if cat not in ('ignore', 'lint', 'require', 'use',
                                    'asset', 'cldr'):
                         continue
                     # the next is currently not used (Comment.parseNode doesn't return error commentAttributes)
                     # but would be suitable for error reporting with file and line number
                     elif hasattr(entry, 'error'):
                         filename = node.getRoot().get('file', '<Unknown>')
                         lineno = node.get('line')
                         msg = "%s (%s): %s: %s" % (filename, lineno,
                                                    entry['message'],
                                                    entry['text'])
                         context.console.warn(msg)
                     else:
                         functor = entry.get(
                             'functor'
                         )  # will be None for non-functor keys like @ignore, @require, ...
                         hint.add_entries(
                             (cat, functor), entry['arguments']
                         )  # hint.hints['lint']['ignoreUndefined']{'foo','bar'}
                         # hint.hints['ignore'][None]{'foo','bar'}
     return hint
Example #5
0
def get_at_hints(node, at_hints=None):
    if at_hints is None:
        at_hints = defaultdict(dict)
    commentsArray = Comment.parseNode(
        node)  # searches comment "around" this node
    for commentAttributes in commentsArray:
        for entry in commentAttributes:
            # {'arguments': ['a', 'b'],
            #  'category': u'lint',
            #  'functor': u'ignoreReferenceField',
            #  'text': u'<p>ignoreReferenceField(a,b)</p>'
            # }
            cat = entry['category']
            if cat == 'lint':
                functor = entry['functor']
                if functor not in at_hints[cat]:
                    at_hints[cat][functor] = set()
                at_hints[cat][functor].update(entry['arguments'])
            elif cat == "ignore":
                if cat not in at_hints:
                    at_hints[cat] = set()
                at_hints[cat].update(entry['arguments'])
    # include @hints of parent scopes
    scope = scopes.find_enclosing(node)
    if scope:
        if 0: print "debug:", file_name, node, scope.node
        at_hints = get_at_hints(scope.node, at_hints)
    return at_hints
Example #6
0
def get_at_hints(node, at_hints=None):
    if at_hints is None:
        at_hints = defaultdict(dict)
    commentsArray = Comment.parseNode(node, process_txt=False)  # searches comment "around" this node
    for commentAttributes in commentsArray:
        for entry in commentAttributes:
             # {'arguments': ['a', 'b'],
             #  'category': u'lint',
             #  'functor': u'ignoreReferenceField',
             #  'text': u'<p>ignoreReferenceField(a,b)</p>'
             # }
            cat = entry['category']
            if cat=='lint':
                functor = entry['functor']
                if functor not in at_hints[cat]:
                    at_hints[cat][functor] = set()
                at_hints[cat][functor].update(entry['arguments']) 
            elif cat=="ignore":
                if cat not in at_hints:
                    at_hints[cat] = set()
                at_hints[cat].update(entry['arguments'])
    # include @hints of parent scopes
    scope = scopes.find_enclosing(node)
    if scope:
        at_hints = get_at_hints(scope.node, at_hints)
    return at_hints
Example #7
0
def toPretty(self, optns, state):
    r = self.get("value")
    r = Comment.Text(r).indent(indentString(optns, state))
    r += '\n'  # 'inline' needs terminating newline anyway
    r += indentString(
        optns,
        state)  # to pass on the indentation that was set ahead of the comment
    return r
Example #8
0
def format(self, optns, state):
    r = self.get("value")
    r = Comment.Text(r).indent(indentString(optns, state))
    if self.get('end',
                False) == True:  # 'inline' needs terminating newline anyway
        r += '\n'
    r += indentString(
        optns,
        state)  # to pass on the indentation that was set ahead of the comment
    return r
Example #9
0
 def _shouldPrintVariableWarning(self, node, docCommand, variableName):
     comments = Comment.findComment(node)
     if comments is None:
         return True
     
     lintAttribs = [x for x in comments if x["category"] == "lint"]
     
     unused_re = re.compile("<p>\s*%s\s*\(\s*((?:[\w\$]+)\s*(?:,\s*(?:[\w\$]+)\s*)*)\)" % docCommand)
     for attrib in lintAttribs:
         match = unused_re.match(attrib["text"])
         if match:
             variables = [var.strip() for var in match.group(1).split(",")]
             return not variableName in variables            
     return True
Example #10
0
    def process_comments(self, node):
        hint = None
        if node.comments:
            commentsArray = Comment.parseNode(node,
                                              process_txt=False,
                                              want_errors=True)
            if any(commentsArray):
                hint = Hint()
                # fill hint from commentAttributes
                for commentAttributes in commentsArray:
                    for entry in commentAttributes:
                        # errors treated later
                        if 'error' in entry:
                            continue
                        # add interesting entries to tree
                        cat = entry['category']
                        if cat not in ('ignore', 'lint', 'require', 'use',
                                       'asset', 'cldr'):
                            continue
                        else:
                            functor = entry.get(
                                'functor'
                            )  # will be None for non-functor keys like @ignore, @require, ...
                            hint.add_entries(
                                (cat, functor), entry['arguments']
                            )  # hint.hints['lint']['ignoreUndefined']{'foo','bar'}
                            # hint.hints['ignore'][None]{'foo','bar'}

                # loop again for error logging (here, so you can ignore error entries in the same comment)
                #
                # TODO: separation of concerns -  it's a kludge to be outputting warnings here; they should
                # be returned to the caller of the module, together with the genuine result. the caller
                # should decide how to handle warnings. if he handles them warnings should be transformed
                # into a generic format and passed to a dedicated handler, e.g. the Log module. this handler
                # might in turn consult the hint tree, to check for ignore hints.
                for commentAttributes in commentsArray:
                    for entry in commentAttributes:
                        if 'error' in entry:
                            if self._key_is_ignored(entry['category'], hint):
                                continue
                            else:
                                msg = "%s (%s): %s" % (entry['filename'],
                                                       entry['lineno'],
                                                       entry['message'])
                                msg += (
                                    ": %s" % entry['text']
                                ) if 'text' in entry and entry['text'] else ''
                                context.console.warn(msg)

        return hint
Example #11
0
    def _shouldPrintVariableWarning(self, node, docCommand, variableName):
        comments = Comment.findComment(node)
        if comments is None:
            return True

        lintAttribs = [x for x in comments if x["category"] == "lint"]

        unused_re = re.compile(
            "<p>\s*%s\s*\(\s*((?:[\w\$]+)\s*(?:,\s*(?:[\w\$]+)\s*)*)\)" %
            docCommand)
        for attrib in lintAttribs:
            match = unused_re.match(attrib["text"])
            if match:
                variables = [var.strip() for var in match.group(1).split(",")]
                return not variableName in variables
        return True
Example #12
0
 def process_comments(self, node):
     hint = None
     if node.comments:
         commentsArray = Comment.parseNode(node, process_txt=False)
         if any(commentsArray):
             hint = Hint()
             # fill hint from commentAttributes
             for commentAttributes in commentsArray:
                 for entry in commentAttributes:
                     cat = entry['category']
                     if cat not in ('ignore', 'lint', 'require', 'use'):
                         continue
                     functor = entry.get('functor') # will be None for non-functor keys like @ignore, @require, ...
                     hint.add_entries((cat,functor), entry['arguments'])  # hint.hints['lint']['ignoreUndefined']{'foo','bar'}
                                                                  # hint.hints['ignore'][None]{'foo','bar'}
     return hint
Example #13
0
def get_at_hints(node):
    commentAttributes = Comment.parseNode(node)  # searches comment "around" this node
    at_hints = {}
    for entry in commentAttributes:
        cat = entry['category']
        if cat not in at_hints:
            at_hints[cat] = {}
        if cat=='lint':
             # {'arguments': ['a', 'b'],
             #  'category': u'lint',
             #  'functor': u'ignoreReferenceField',
             #  'text': u'<p>ignoreReferenceField(a,b)</p>'
             # }
            functor = entry['functor']
            if functor not in at_hints['lint']:
                at_hints['lint'][functor] = set()
            at_hints['lint'][functor].update(entry['arguments'])
    return at_hints
Example #14
0
def get_at_hints(node):
    commentAttributes = Comment.parseNode(
        node)  # searches comment "around" this node
    at_hints = {}
    for entry in commentAttributes:
        cat = entry['category']
        if cat not in at_hints:
            at_hints[cat] = {}
        if cat == 'lint':
            # {'arguments': ['a', 'b'],
            #  'category': u'lint',
            #  'functor': u'ignoreReferenceField',
            #  'text': u'<p>ignoreReferenceField(a,b)</p>'
            # }
            functor = entry['functor']
            if functor not in at_hints['lint']:
                at_hints['lint'][functor] = set()
            at_hints['lint'][functor].update(entry['arguments'])
    return at_hints
Example #15
0
    def visit(self, node):

        if node.comments:
            commentsArray = Comment.parseNode(node)
            if any(commentsArray):
                hint = Hint()
                # maintain hint tree
                self.curr_hint.children.append(hint)
                hint.parent = self.curr_hint
                # fill hint from commentAttributes
                hint = self.commentAttributes_to_hint(commentsArray, hint)
                # get main node from node
                main_node = treeutil.findCommentedRoot(node)
                # cross-link hint and node
                main_node.hint = hint
                hint.node = main_node # node?!
                # scope nested hints
                self.curr_hint = hint
        for cld in node.children:
            self.visit(cld)
Example #16
0
def createBlockComment(txt):
    l = "*****************************************************************************"

    s = ""
    s += "/*\n"
    s += "%s\n" % l
    s += "   %s\n" % txt.upper()
    s += "%s\n" % l
    s += "*/"

    bef = tree.Node("commentsBefore")
    com = tree.Node("comment")

    bef.addChild(com)

    com.set("multiline", True)
    com.set("connection", "before")
    com.set("text", s)
    com.set("detail", Comment.Comment(s).getFormat())

    return bef
Example #17
0
    def process_comments(self, node):
        hint = None
        if node.comments:
            commentsArray = Comment.parseNode(node, process_txt=False, want_errors=True)
            if any(commentsArray):
                hint = Hint()
                # fill hint from commentAttributes
                for commentAttributes in commentsArray:
                    for entry in commentAttributes:
                        # errors treated later
                        if 'error' in entry:
                            continue
                        # add interesting entries to tree
                        cat = entry['category']
                        if cat not in ('ignore', 'lint', 'require', 'use', 'asset', 'cldr'):
                            continue
                        else:
                            functor = entry.get('functor') # will be None for non-functor keys like @ignore, @require, ...
                            hint.add_entries((cat,functor), entry['arguments'])  # hint.hints['lint']['ignoreUndefined']{'foo','bar'}
                                                                         # hint.hints['ignore'][None]{'foo','bar'}

                # loop again for error logging (here, so you can ignore error entries in the same comment)
                #
                # TODO: separation of concerns -  it's a kludge to be outputting warnings here; they should
                # be returned to the caller of the module, together with the genuine result. the caller
                # should decide how to handle warnings. if he handles them warnings should be transformed
                # into a generic format and passed to a dedicated handler, e.g. the Log module. this handler
                # might in turn consult the hint tree, to check for ignore hints.
                for commentAttributes in commentsArray:
                    for entry in commentAttributes:
                        if 'error' in entry:
                            if self._key_is_ignored(entry['category'], hint):
                                continue
                            else:
                                msg = "%s (%s): %s" % (entry['filename'], entry['lineno'], entry['message'])
                                msg += (": %s" % entry['text']) if 'text' in entry and entry['text'] else ''
                                context.console.warn(msg)

        return hint
Example #18
0
 def commentsPretty(self, commentsA, optns, state):
     comments = []
     for i, comment in enumerate(commentsA):
         commentStr = comment.get("value")
         commentStr = Comment.Text(commentStr).indent(
             indentString(optns, state))
         if comment.get(
                 'end', False
         ) == True:  # 'inline' needs terminating newline anyway
             commentStr += self.nl(optns, state)
         commentStr += state.indentStr(
             optns
         )  # to pass on the indentation that was set ahead of the comment
         comments.append(commentStr)
         # handle additional line breaks between comments
         if i > 0:
             pass
             #curr_start = comment.get("line")
             #prev_start = commentsA[i-1].get("line")
             #prev_lines = comments[i-1].count('\n')
             #addtl_lb = curr_start - prev_start + prev_lines
             #comments[i-1] += addtl_lb * '\n'
     return u''.join(comments)
Example #19
0
 def process_comments(self, node):
     hint = None
     if node.comments:
         commentsArray = Comment.parseNode(node, process_txt=False) #, want_errors=True)
         if any(commentsArray):
             hint = Hint()
             # fill hint from commentAttributes
             for commentAttributes in commentsArray:
                 for entry in commentAttributes:
                     cat = entry['category']
                     if cat not in ('ignore', 'lint', 'require', 'use', 'asset', 'cldr'):
                         continue
                     # the next is currently not used (Comment.parseNode doesn't return error commentAttributes)
                     # but would be suitable for error reporting with file and line number
                     elif hasattr(entry, 'error'):
                         filename = node.getRoot().get('file', '<Unknown>')
                         lineno = node.get('line')
                         msg = "%s (%s): %s: %s" % (filename, lineno, entry['message'], entry['text'])
                         context.console.warn(msg)
                     else:
                         functor = entry.get('functor') # will be None for non-functor keys like @ignore, @require, ...
                         hint.add_entries((cat,functor), entry['arguments'])  # hint.hints['lint']['ignoreUndefined']{'foo','bar'}
                                                                      # hint.hints['ignore'][None]{'foo','bar'}
     return hint
Example #20
0
    def parseToken(self):
        for tok in self.scanner:

            hasNoPreviousDot = True
            try:
                hasNoPreviousDot = self.out_stream[-1]['detail'] != "DOT"
            except (IndexError):
                pass

            # some inital values (tok isinstanceof Scanner.Token())
            token = {
                "source": tok.value,
                "detail": "",
                "line": self.line,
                "column": tok.spos - self.sol + 1,
                "id": self.uniqueId
            }

            # white space
            if (tok.name == 'white'):
                #continue
                token['type'] = 'white'

            # end of file
            elif tok.name == 'eof':
                token['type'] = 'eof'

            # line break
            elif tok.name == 'nl':
                token['type'] = 'eol'
                token['source'] = '\n'
                self.line += 1  # increase line count
                self.sol = tok.spos + tok.len  # char pos of next line start

            # float
            elif tok.name == 'float':
                token['type'] = 'number'
                token['detail'] = 'float'

            # hex integer
            elif tok.name == 'hexnum':
                token['type'] = 'number'
                token['detail'] = 'int'

            # integer
            elif tok.name == 'number':
                token['type'] = 'number'
                token['detail'] = 'int'

            # string
            elif tok.value in ('"', "'"):
                # accumulate strings
                token['type'] = 'string'
                if tok.value == '"':
                    token['detail'] = 'doublequotes'
                else:
                    token['detail'] = 'singlequotes'
                try:
                    token['source'] = self.parseString(self.scanner, tok.value)
                except SyntaxException, e:
                    self.raiseSyntaxException(token, e.args[0])
                token['source'] = token['source'][:-1]
                # adapt line number -- this assumes multi-line strings are not generally out
                linecnt = len(re.findall("\n", token['source']))
                if linecnt > 0:
                    self.line += linecnt

            # identifier, operator
            elif tok.name in ("ident", "op", "mulop"):

                # JS operator symbols
                if tok.value in lang.TOKENS:
                    # division, div-assignment, regexp
                    if tok.value in ('/', '/='):
                        # get the preceding (real) token
                        for ptoken in reversed(self.out_stream):
                            if ptoken['type'] in ('eol', 'white'):
                                continue
                            else:
                                prev_token = ptoken
                                break
                        # regex literal
                        if (len(self.out_stream) == 0
                                or ((
                                    prev_token['type'] not in [
                                        'number',  # divison of number
                                        'name',  # var holding a number
                                        'string'
                                    ])  # string representing a number
                                    and (prev_token['detail'] not in [
                                        'RP',  # call returning a number
                                        'RB'
                                    ])  # <can't remember>
                                    )):
                            try:
                                regexp = self.parseRegexp(self.scanner)
                            except SyntaxException, e:
                                self.raiseSyntaxException(token, e.args[0])
                            token['type'] = 'regexp'
                            token['source'] = tok.value + regexp
                        # div, div-assign
                        else:
                            token['type'] = 'token'
                            token['detail'] = lang.TOKENS[tok.value]

                    # comment, inline
                    elif tok.value == '//':
                        # accumulate inline comments
                        if (len(self.out_stream) == 0
                                or not is_last_escaped_token(self.out_stream)):
                            #import pydb; pydb.debugger()
                            commnt = self.parseCommentI(self.scanner)
                            token['type'] = 'comment'
                            token['source'] = tok.value + commnt
                            token['begin'] = not self.hasLeadingContent(
                                self.out_stream)
                            token['end'] = True
                            token['connection'] = "before" if token[
                                'begin'] else "after"  # "^//...\n i=1;" => comment *before* code; "i=1; //..." => comment *after* code
                            token['multiline'] = False
                            token['detail'] = 'inline'
                        else:
                            print >> sys.stderr, "Inline comment out of context"

                    # comment, multiline
                    elif tok.value == '/*':
                        # accumulate multiline comments
                        if (len(self.out_stream) == 0
                                or not is_last_escaped_token(self.out_stream)):
                            token['type'] = 'comment'
                            try:
                                commnt = self.parseCommentM(self.scanner)
                            except SyntaxException, e:
                                self.raiseSyntaxException(token, e.args[0])
                            commnt = self.alignMultiLines(
                                commnt, token['column'])
                            token['source'] = tok.value + commnt
                            token['detail'] = Comment.Comment(
                                token['source']).getFormat()
                            token['begin'] = not self.hasLeadingContent(
                                self.out_stream
                            )  # first non-white token on line
                            if token['begin']:
                                token['source'] = Comment.Text(
                                    token['source']).outdent(self.column - 1)
                            # adapt line number
                            linecnt = len(re.findall("\n", token['source']))
                            if linecnt > 0:
                                self.line += linecnt
                                token['multiline'] = True
                            else:
                                token['multiline'] = False

                        else:
                            print >> sys.stderr, "Multiline comment out of context"
Example #21
0
def parseStream(content, uniqueId=""):
    tokens = []
    line = column = 1
    sol = 0  # index of start-of-line
    scanner = Scanner.LQueue(tokens_2_obj(content, ))
    scanner.content = content
    scanner.slice = scanner_slice
    for tok in scanner:
        # some inital values (tok isinstanceof Scanner.Token())
        token = {
            "source": tok.value,
            "detail": "",
            "line": line,
            "column": tok.spos - sol + 1,
            "id": uniqueId
        }

        # white space
        if (tok.name == 'white'):
            continue

        # end of file
        elif tok.name == 'eof':
            token['type'] = 'eof'

        # line break
        elif tok.name == 'nl':
            token['type'] = 'eol'
            token['source'] = ''  # that's the way the old tokenizer does it
            line += 1  # increase line count
            sol = tok.spos + tok.len  # char pos of next line start

        # float
        elif tok.name == 'float':
            token['type'] = 'number'
            token['detail'] = 'float'

        # hex integer
        elif tok.name == 'hexnum':
            token['type'] = 'number'
            token['detail'] = 'int'

        # integer
        elif tok.name == 'number':
            token['type'] = 'number'
            token['detail'] = 'int'

        # string
        elif tok.value in ('"', "'"):
            # accumulate strings
            token['type'] = 'string'
            if tok.value == '"':
                token['detail'] = 'doublequotes'
            else:
                token['detail'] = 'singlequotes'
            try:
                token['source'] = parseString(scanner, tok.value)
            except SyntaxException, e:
                desc = e.args[0] + " starting with %r..." % (tok.value +
                                                             e.args[1])[:20]
                raiseSyntaxException(token, desc)
            token['source'] = token['source'][:-1]
            # adapt line number -- this assumes multi-line strings are not generally out
            linecnt = len(re.findall("\n", token['source']))
            if linecnt > 0:
                line += linecnt

        # identifier, operator
        elif tok.name in ("ident", "op", "mulop"):

            # JS operator symbols
            if tok.value in lang.TOKENS:
                # division, div-assignment, regexp
                if tok.value in ('/', '/='):
                    # accumulate regex literals
                    if (len(tokens) == 0
                            or ((tokens[-1]['type'] != 'number') and
                                (tokens[-1]['detail'] != 'RP') and
                                (tokens[-1]['detail'] != 'RB') and
                                (tokens[-1]['type'] != 'name'))):
                        regexp = parseRegexp(scanner)
                        token['type'] = 'regexp'
                        token['source'] = tok.value + regexp
                    else:
                        token['type'] = 'token'
                        token['detail'] = lang.TOKENS[tok.value]

                # comment, inline
                elif tok.value == '//':
                    # accumulate inline comments
                    if (len(tokens) == 0 or not is_last_escaped_token(tokens)):
                        commnt = parseCommentI(scanner)
                        token['type'] = 'comment'
                        token['source'] = tok.value + commnt
                        token['begin'] = not hasLeadingContent(tokens)
                        token['end'] = True
                        token['connection'] = "before" if token[
                            'begin'] else "after"  # "^//...\n i=1;" => comment *before* code; "i=1; //..." => comment *after* code
                        token['multiline'] = False
                        token['detail'] = 'inline'
                    else:
                        print >> sys.stderror, "Inline comment out of context"

                # comment, multiline
                elif tok.value == '/*':
                    # accumulate multiline comments
                    if (len(tokens) == 0 or not is_last_escaped_token(tokens)):
                        token['type'] = 'comment'
                        try:
                            commnt = parseCommentM(scanner)
                        except SyntaxException, e:
                            desc = e.args[0] + " starting with \"%r...\"" % (
                                tok.value + e.args[1])[:20]
                            raiseSyntaxException(token, desc)
                        commnt = alignMultiLines(commnt, token['column'])
                        token['source'] = tok.value + commnt
                        token['detail'] = Comment.Comment(
                            token['source']).getFormat()
                        token['begin'] = not hasLeadingContent(tokens)
                        if restLineIsEmpty(scanner):
                            token['end'] = True
                        else:
                            token['end'] = False
                        if token['begin']:
                            token['source'] = Comment.Text(
                                token['source']).outdent(column - 1)
                        token['source'] = Comment.Comment(
                            token['source']).correct()
                        if token['end'] and not token['begin']:
                            token['connection'] = "after"
                        else:
                            token['connection'] = "before"
                        # adapt line number
                        linecnt = len(re.findall("\n", token['source']))
                        if linecnt > 0:
                            line += linecnt
                            token['multiline'] = True
                        else:
                            token['multiline'] = False

                    else:
                        print >> sys.stderror, "Multiline comment out of context"

                # every other operator goes as is
                else:
                    token['type'] = 'token'
                    token['detail'] = lang.TOKENS[tok.value]
Example #22
0
def _prettyNode(node, optns, result):

    global pretty
    global indent

    #####################################################################################################################
    # Recover styling
    #####################################################################################################################

    if pretty:
        # Recover exclicit breaks
        if node.get("breakBefore", False) and not node.isFirstChild(True):
            sep()

        # Additional explicit break before complex blocks
        if node.hasParent() and not node.isFirstChild(
                True) and node.parent.type in ["block", "file"
                                               ] and node.isComplex():
            sep()

    #####################################################################################################################
    # Insert comments before
    #####################################################################################################################

    if pretty:
        if node.getChild("commentsBefore", False) != None:
            commentCounter = 0
            commentsBefore = node.getChild("commentsBefore")
            isFirst = node.isFirstChild()
            previous = node.getPreviousSibling(False, True)

            if previous and previous.type in ["case", "default"]:
                inCase = True
            else:
                inCase = False

            inOperation = node.parent.type in [
                "first", "second", "third"
            ] and node.parent.parent.type == "operation"

            for child in commentsBefore.children:
                docComment = child.get("detail") in ["javadoc", "qtdoc"]
                headComment = child.get("detail") == "header"
                areaComment = child.get("detail") == "area"
                divComment = child.get("detail") == "divider"
                blockComment = child.get("detail") == "block"
                singleLineBlock = child.get(
                    "detail") != "inline" and child.get("multiline") == False

                if not child.isFirstChild():
                    pass

                elif inCase:
                    pass

                elif singleLineBlock:
                    if child.get("begin"):
                        sep()
                    else:
                        space()

                elif areaComment and not isFirst:
                    area()

                elif divComment and not isFirst:
                    divide()

                elif not isFirst:
                    if docComment:
                        doc()
                    else:
                        if child.get("text") in ("//", "/*"):
                            nosep(
                            )  # the blank comment provides a blank line, so don't put a separator in
                            line(
                            )  # make sure there is a new line after whatever has gone before
                        else:
                            sep()

                elif inOperation:
                    sep()

                elif not headComment:
                    line()

                # reindenting first
                text = child.get("text")

                if child.get("detail") == "qtdoc":
                    text = Comment.Comment(text).qt2javadoc()

                #write(comment.indent(text, INDENTSPACES * indent))
                write(
                    Comment.Text(text).indent(optns.prettypIndentString *
                                              indent))

                if singleLineBlock:
                    if docComment:
                        line()
                    elif child.get("end"):
                        sep()
                    else:
                        space()

                # separator after divider/head comments and after block comments which are not for documentation
                elif headComment or areaComment or divComment or blockComment:
                    sep()

                else:
                    line()
                    # the next two: bugzilla#454
                    #global result
                    #result += "\n"

    #####################################################################################################################
    # Opening...
    #####################################################################################################################

    #
    # OPEN: FINALLY
    ##################################

    if node.type == "finally":
        write("finally")

    #
    # OPEN: DELETE
    ##################################

    elif node.type == "delete":
        write("delete")
        space()

    #
    # OPEN: THROW
    ##################################

    elif node.type == "throw":
        write("throw")
        space()

    #
    # OPEN: NEW
    ##################################

    elif node.type == "instantiation":
        write("new")
        space()

    #
    # OPEN: RETURN
    ##################################

    elif node.type == "return":
        write("return")

        if node.hasChildren():
            space()

    #
    # OPEN: DEFINITION LIST
    ##################################

    elif node.type == "definitionList":
        write("var")
        space()

    #
    # OPEN: BREAK
    ##################################

    elif node.type == "break":
        write("break")

        if node.get("label", False):
            space()
            write(node.get("label", False))

    #
    # OPEN: CONTINUE
    ##################################

    elif node.type == "continue":
        write("continue")

        if node.get("label", False):
            space()
            write(node.get("label", False))

    #
    # OPEN: FUNCTION
    ##################################

    elif node.type == "function":
        write("function")

        functionName = node.get("name", False)
        if functionName != None:
            space()
            write(functionName)

    #
    # OPEN: IDENTIFIER
    ##################################

    elif node.type == "identifier":
        name = node.get("name", False)
        if name != None:
            write(name)

    #
    # OPEN: DEFINITION
    ##################################

    elif node.type == "definition":
        if node.parent.type != "definitionList":
            write("var")
            space()

        write(node.get("identifier"))

    #
    # OPEN: CONSTANT
    ##################################

    elif node.type == "constant":
        if node.get("constantType") == "string":
            if node.get("detail") == "singlequotes":
                write("'")
            else:
                write('"')

            write(node.get("value"))

            if node.get("detail") == "singlequotes":
                write("'")
            else:
                write('"')

        else:
            write(node.get("value"))

    #
    # OPEN: COMMENT
    ##################################

    elif node.type == "comment":
        if pretty:
            commentText = node.get("text")
            # insert appropriate spaces before and no newline in the case of after comments
            if node.get("connection") == "after":
                noline()
                padding = getInlineCommentPadding(optns, node.get("column"))
                if padding:
                    commentText = padding + commentText.strip()
                else:
                    space()
                ##space()

            ##write(node.get("text"))
            write(commentText)

            # new line after inline comment (for example for syntactical reasons)
            #if (node.get("detail") == "inline") or (node.get("multiline") == False):
            if (node.get("detail") == "inline") or (node.get("end") == True):
                line()
            else:
                space()

    #
    # OPEN: RIGHT
    ##################################

    elif node.type == "right":
        if node.parent.type == "accessor":
            write(".")

    #
    # OPEN: ASSIGNMENT
    ##################################

    elif node.type == "assignment":
        if node.parent.type == "definition":
            oper = node.get("operator", False)

            # be compact in for-loops
            compact = inForLoop(node)
            compileToken(oper, compact)

    #
    # OPEN: KEY
    ##################################

    elif node.type == "key":
        if node.parent.type == "accessor":
            write("[")

    #
    # OPEN: GROUP
    ##################################

    elif node.type == "group":
        write("(")

    #
    # OPEN: VOID
    ##################################

    elif node.type == "void":
        write("void")
        write("(")

    #
    # OPEN: ARRAY
    ##################################

    elif node.type == "array":
        write("[")

        if node.hasChildren(True):
            space(False)

    #
    # OPEN: PARAMS
    ##################################

    elif node.type == "params":
        noline()
        write("(")

    #
    # OPEN: CASE
    ##################################

    elif node.type == "case":
        if pretty:
            # force double new lines
            if not node.isFirstChild():
                sep()
                dec_indent()

            line()

        write("case")
        space()

    #
    # OPEN: DEFAULT
    ##################################

    elif node.type == "default":
        if pretty:
            dec_indent()

            # force double new lines
            if (node.getPreviousSibling(False)
                    and not node.getPreviousSibling(True).type == "case"):
                sep()

        write("default")
        write(":")

        if pretty:
            inc_indent()
            line()

    #
    # OPEN: TRY
    ##################################

    elif node.type == "switch":
        # Additional new line before each switch/try
        if not node.isFirstChild(True) and not node.getChild(
                "commentsBefore", False):
            prev = node.getPreviousSibling(False, True)

            # No separation after case statements
            if prev != None and prev.type in ["case", "default"]:
                pass
            else:
                sep()

        if node.get("switchType") == "catch":
            write("try")
        elif node.get("switchType") == "case":
            write("switch")

    #
    # OPEN: CATCH
    ##################################

    elif node.type == "catch":
        if pretty:
            # If this statement block or the previous try were not complex, be not complex here, too
            if not node.getChild("statement").getChild(
                    "block").isComplex() and not node.parent.getChild(
                        "statement").getChild("block").isComplex():
                noline()
                space()
            # the next two: bugzilla#454
            if node.getFirstChild(
            ).type == "commentsBefore" and not result[-1].endswith("\n"):
                line()

        write("catch")

    #
    # OPEN: MAP
    ##################################

    elif node.type == "map":
        par = node.parent

        if pretty:
            postProcessMap(node)

        if pretty:
            # No break before return statement
            if node.hasParent(
            ) and node.parent.type == "expression" and node.parent.parent.type == "return":
                pass

            elif ((node.isComplex()
                   and not (optns.prettypOpenCurlyNewlineBefore in "nN"))
                  or (optns.prettypOpenCurlyNewlineBefore in "aA")):
                line()
                if optns.prettypOpenCurlyIndentBefore:
                    inc_indent()

        write("{")

        if pretty:
            if node.isComplex():
                line()
                if not optns.prettypAlignBlockWithCurlies:
                    inc_indent()

            elif node.hasChildren(True):
                space()

    #
    # OPEN: KEYVALUE
    ##################################

    elif node.type == "keyvalue":
        keyString = node.get("key")
        keyQuote = node.get("quote", False)

        if keyQuote != None:
            # print "USE QUOTATION"
            if keyQuote == "doublequotes":
                keyString = '"' + keyString + '"'
            else:
                keyString = "'" + keyString + "'"

        elif keyString in lang.RESERVED or not KEY.match(keyString):
            print "Warning: Auto protect key: %s" % keyString
            keyString = "\"" + keyString + "\""

        if pretty and not node.isFirstChild(True) and not node.hasChild(
                "commentsBefore") and node.getChild("value").isComplex():
            sep()

        write(keyString)
        space(False)

        # Fill with spaces
        # Do this only if the parent is complex (many entries)
        # But not if the value itself is complex
        if pretty and node.parent.isComplex() and node.parent.get(
                "alignValues"):
            write(" " * (node.parent.get("maxKeyLength") - len(keyString)))

        write(":")
        space(False)

    #
    # OPEN: BLOCK
    ##################################

    elif node.type == "block":
        if pretty:
            if ((node.isComplex()
                 and not (optns.prettypOpenCurlyNewlineBefore in "nN"))
                    or (optns.prettypOpenCurlyNewlineBefore in "aA")):
                line()
                nl = True
                if optns.prettypOpenCurlyIndentBefore:
                    inc_indent()
            else:
                space()
                nl = False

        write("{")

        if pretty:
            if node.hasChildren():
                line()
                if (not nl) or (nl and not optns.prettypAlignBlockWithCurlies):
                    inc_indent()

    #
    # OPEN: LOOP
    ##################################

    elif node.type == "loop":
        # Additional new line before each loop
        if not node.isFirstChild(True) and not node.getChild(
                "commentsBefore", False):
            prev = node.getPreviousSibling(False, True)

            # No separation after case statements
            if prev != None and prev.type in ["case", "default"]:
                pass
            elif node.hasChild("elseStatement") or node.getChild(
                    "statement").hasBlockChildren():
                sep()
            else:
                line()

        loopType = node.get("loopType")

        if loopType == "IF":
            write("if")
            space(False)

        elif loopType == "WHILE":
            write("while")
            space(False)

        elif loopType == "FOR":
            write("for")
            space(False)

        elif loopType == "DO":
            write("do")
            space(False)

        elif loopType == "WITH":
            write("with")
            space(False)

        else:
            print "Warning: Unknown loop type: %s" % loopType

    #
    # OPEN: ELSE
    ##################################

    elif node.type == "elseStatement":
        if node.hasChild("commentsBefore"):
            pass

        elif pretty:
            if not node.hasChild("block") and not node.hasChild("loop"):
                pass

            elif not node.isComplex():
                noline()
                space()

        write("else")

        # This is a elseStatement without a block around (a set of {})
        if not node.hasChild("block"):
            space()

    #
    # OPEN: EXPRESSION
    ##################################

    elif node.type == "expression":
        if node.parent.type == "loop":
            loopType = node.parent.get("loopType")

            # only do-while loops
            if loopType == "DO":
                if pretty:
                    stmnt = node.parent.getChild("statement")
                    compact = stmnt.hasChild(
                        "block") and not stmnt.getChild("block").isComplex()

                    if compact:
                        noline()
                        space()

                write("while")

                if pretty:
                    space()

            # open expression block of IF/WHILE/DO-WHILE/FOR statements
            write("(")

        elif node.parent.type == "catch":
            # open expression block of CATCH statement
            write("(")

        elif node.parent.type == "switch" and node.parent.get(
                "switchType") == "case":
            # open expression block of SWITCH statement
            write("(")

    #
    # OPEN: FIRST
    ##################################

    elif node.type == "first":
        # for loop
        if node.parent.type == "loop" and node.parent.get("loopType") == "FOR":
            write("(")

        # operation
        elif node.parent.type == "operation":
            # operation (var a = -1)
            if node.parent.get("left", False) == True:
                compileToken(node.parent.get("operator"), True)

    #
    # OPEN: SECOND
    ##################################

    elif node.type == "second":
        # for loop
        if node.parent.type == "loop" and node.parent.get("loopType") == "FOR":
            if not node.parent.hasChild("first"):
                write("(;")

        # operation
        elif node.parent.type == "operation":
            if node.isComplex():
                # (?: hook operation)
                if node.parent.get("operator") == "HOOK":
                    sep()
                else:
                    line()

    #
    # OPEN: THIRD
    ##################################

    elif node.type == "third":
        # for loop
        if node.parent.type == "loop" and node.parent.get("loopType") == "FOR":
            if not node.parent.hasChild("second"):
                if node.parent.hasChild("first"):
                    write(";")
                    space(False)
                else:
                    write("(;;")

        # operation
        elif node.parent.type == "operation":
            # (?: hook operation)
            if node.parent.get("operator") == "HOOK":
                if node.isComplex():
                    sep()

    #
    # OPEN: STATEMENT
    ##################################

    elif node.type == "statement":
        # for loop
        if node.parent.type == "loop" and node.parent.get("loopType") == "FOR":
            if node.parent.get("forVariant") == "iter":
                if not node.parent.hasChild(
                        "first") and not node.parent.hasChild(
                            "second") and not node.parent.hasChild("third"):
                    write("(;;")

                elif not node.parent.hasChild(
                        "second") and not node.parent.hasChild("third"):
                    write(";")

            write(")")

            if not node.hasChild("block"):
                space(False)

    #####################################################################################################################
    # Children content
    #####################################################################################################################

    if node.hasChildren():
        for child in node.children:
            if not node.type in ["commentsBefore", "commentsAfter"]:
                _prettyNode(child, optns, result)

    #####################################################################################################################
    # Closing node
    #####################################################################################################################

    #
    # CLOSE: IDENTIFIER
    ##################################

    if node.type == "identifier":
        if node.hasParent(
        ) and node.parent.type == "variable" and not node.isLastChild(True):
            write(".")
        elif node.hasParent() and node.parent.type == "label":
            write(":")

    #
    # CLOSE: ACCESSOR
    ##################################

    elif node.type == "accessor":
        if node.hasParent(
        ) and node.parent.type == "variable" and not node.isLastChild(True):
            write(".")

    #
    # CLOSE: KEYVALUE
    ##################################

    elif node.type == "keyvalue":
        if node.hasParent(
        ) and node.parent.type == "map" and not node.isLastChild(True):
            noline()
            comma()

            if pretty:
                commentNode(node)

                if node.getChild("value").isComplex():
                    sep()
                elif node.parent.isComplex():
                    line()
                else:
                    space()

    #
    # CLOSE: DEFINITION
    ##################################

    elif node.type == "definition":
        if node.hasParent(
        ) and node.parent.type == "definitionList" and not node.isLastChild(
                True):
            comma()

            if pretty:
                commentNode(node)

                if node.hasComplexChildren():
                    line()
                else:
                    space()

    #
    # CLOSE: LEFT
    ##################################

    elif node.type == "left":
        if node.hasParent() and node.parent.type == "assignment":
            oper = node.parent.get("operator", False)

            # be compact in for-loops
            compact = inForLoop(node)
            compileToken(oper, compact)

    #
    # CLOSE: KEY
    ##################################

    elif node.type == "key":
        if node.hasParent() and node.parent.type == "accessor":
            write("]")

    #
    # CLOSE: GROUP
    ##################################

    elif node.type == "group":
        if node.getChildrenLength(True) == 1:
            #noline()  # commented out due to bug#811
            pass

        write(")")

    #
    # CLOSE: VOID
    ##################################

    elif node.type == "void":
        if node.getChildrenLength(True) == 1:
            noline()

        write(")")

    #
    # CLOSE: ARRAY
    ##################################

    elif node.type == "array":
        if node.hasChildren(True):
            space(False)

        write("]")

    #
    # CLOSE: PARAMS
    ##################################

    elif node.type == "params":
        write(")")

    #
    # CLOSE: MAP
    ##################################

    elif node.type == "map":
        if pretty:
            if node.isComplex():
                line()
                if not optns.prettypAlignBlockWithCurlies:
                    dec_indent()

            elif node.hasChildren(True):
                space()

        write("}")

        if pretty:
            #if node.isComplex() and optns.prettypOpenCurlyIndentBefore:
            #    dec_indent()
            if node.hasParent(
            ) and node.parent.type == "expression" and node.parent.parent.type == "return":
                pass

            elif ((node.isComplex()
                   and not (optns.prettypOpenCurlyNewlineBefore in "nN")
                   )  # means: opening "{" on new line
                  or (optns.prettypOpenCurlyNewlineBefore in "aA")):
                if optns.prettypOpenCurlyIndentBefore:
                    dec_indent()

    #
    # CLOSE: SWITCH
    ##################################

    elif node.type == "switch":
        if node.get("switchType") == "case":
            if pretty:
                dec_indent()
                if not options.prettypAlignBlockWithCurlies:
                    dec_indent()
                line()

            write("}")

            if pretty:
                commentNode(node)
                line()
                if optns.prettypOpenCurlyIndentBefore:
                    dec_indent()

        # Force a additinal line feed after each switch/try
        if pretty and not node.isLastChild():
            sep()

    #
    # CLOSE: CASE
    ##################################

    elif node.type == "case":
        write(":")

        if pretty:
            commentNode(node)
            inc_indent()
            line()

    #
    # CLOSE: BLOCK
    ##################################

    elif node.type == "block":
        if pretty and node.hasChildren():
            line()
            if not optns.prettypAlignBlockWithCurlies:
                dec_indent()

        write("}")

        if pretty:
            commentNode(node)

            if node.hasChildren():
                # Newline afterwards
                if node.parent.type == "body" and node.parent.parent.type == "function":

                    # But only when this isn't a function block inside a assignment
                    if node.parent.parent.parent.type in ["right", "params"]:
                        pass

                    elif node.parent.parent.parent.type == "value" and node.parent.parent.parent.parent.type == "keyvalue":
                        pass

                    else:
                        line()

                else:
                    line()

            # to get the next statement after the block aligned with the parent of the block, you have to
            # unindent after "}" if:
            # - the opening "{" was on a new line AND was indented
            #   OR
            # - the opending "{" was inline AND align-with-curlies is active
            if ((node.isComplex()
                 and not (optns.prettypOpenCurlyNewlineBefore in "nN")
                 )  # means: opening "{" on new line
                    or (optns.prettypOpenCurlyNewlineBefore in "aA")):
                if optns.prettypOpenCurlyIndentBefore:
                    dec_indent()
            else:
                if optns.prettypAlignBlockWithCurlies:
                    dec_indent()

    #
    # CLOSE: LOOP
    ##################################

    elif node.type == "loop":
        if node.get("loopType") == "DO":
            semicolon()

        if pretty:
            commentNode(node)

            # Force a additinal line feed after each loop
            if not node.isLastChild():
                if node.hasChild("elseStatement"):
                    sep()
                elif node.getChild("statement").hasBlockChildren():
                    sep()
                else:
                    line()

    #
    # CLOSE: FUNCTION
    ##################################

    elif node.type == "function":
        if pretty:
            #commentNode(node) # commented out due to bug#942

            if not node.isLastChild() and node.hasParent(
            ) and node.parent.type in ["block", "file"]:
                sep()

    #
    # CLOSE: EXPRESSION
    ##################################

    elif node.type == "expression":
        if node.parent.type == "loop":
            write(")")

            # e.g. a if-construct without a block {}
            if node.parent.getChild("statement").hasChild("block"):
                pass

            elif node.parent.getChild("statement").hasChild("emptyStatement"):
                pass

            elif node.parent.type == "loop" and node.parent.get(
                    "loopType") == "DO":
                pass

            else:
                space(False)

        elif node.parent.type == "catch":
            write(")")

        elif node.parent.type == "switch" and node.parent.get(
                "switchType") == "case":
            write(")")

            if pretty:
                commentNode(node)
                line()
                if optns.prettypOpenCurlyIndentBefore:
                    inc_indent()

            write("{")

            if pretty:
                if not options.prettypAlignBlockWithCurlies:
                    inc_indent()

    #
    # CLOSE: FIRST
    ##################################

    elif node.type == "first":
        # for loop
        if node.parent.type == "loop" and node.parent.get("loopType") == "FOR":
            if node.parent.get("forVariant") == "iter":
                write(";")

                if node.parent.hasChild("second"):
                    space(False)

        # operation
        elif node.parent.type == "operation" and node.parent.get(
                "left", False) != True:
            oper = node.parent.get("operator")

            # be compact in for loops
            compact = inForLoop(node)
            compileToken(oper, compact)

    #
    # CLOSE: SECOND
    ##################################

    elif node.type == "second":
        # for loop
        if node.parent.type == "loop" and node.parent.get("loopType") == "FOR":
            write(";")

            if node.parent.hasChild("third"):
                space(False)

        # operation
        elif node.parent.type == "operation":
            # (?: hook operation)
            if node.parent.get("operator") == "HOOK":
                #noline()  # commented out due to bug#3415
                space(False)
                write(":")
                space(False)

    #
    # CLOSE: OTHER
    ##################################

    if node.hasParent() and not node.type in [
            "comment", "commentsBefore", "commentsAfter"
    ]:

        # Add comma dividers between statements in these parents
        if node.parent.type in ["array", "params", "expressionList"]:
            if not node.isLastChild(True):
                comma()

                if pretty:
                    commentNode(node)

                    if node.isComplex():
                        line()
                    else:
                        space()

        # Semicolon handling
        elif node.type in [
                "group", "block", "assignment", "call", "operation",
                "definitionList", "return", "break", "continue", "delete",
                "accessor", "instantiation", "throw", "variable",
                "emptyStatement"
        ]:

            # Default semicolon handling
            if node.parent.type in ["block", "file"]:
                semicolon()

                if pretty:
                    commentNode(node)
                    line()

                    if node.isComplex() and not node.isLastChild():
                        sep()

            # Special handling for switch statements
            elif node.parent.type == "statement" and node.parent.parent.type == "switch" and node.parent.parent.get(
                    "switchType") == "case":
                semicolon()

                if pretty:
                    commentNode(node)
                    line()

                    if node.isComplex() and not node.isLastChild():
                        sep()

            # Special handling for loops (e.g. if) without blocks {}
            elif (node.parent.type in ["statement", "elseStatement"]
                  and not node.parent.hasChild("block")
                  and node.parent.parent.type == "loop"):
                semicolon()

                if pretty:
                    commentNode(node)
                    line()

                    if node.isComplex() and not node.isLastChild():
                        sep()

    #
    # CLOSE: OTHER
    ##################################

    if pretty:
        # Rest of the after comments (not inserted previously)
        commentNode(node)

    return result