Example #1
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 #2
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 #3
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 #4
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