示例#1
0
    def parse_aux(self, curr_node, braceCount=0):
        init_indentation = curr_node.indentation
        tok_count = 0
        tok_lim = 1000
        cmdStart = True
        curr_globals = {}
        while 1:
            tok = self.tokenizer.get_next_token()
            if tok['style'] == shared_lexer.EOF_STYLE:
                break
            # style, text, start_column, start_line, end_column, end_line = tok
            style, text = tok['style'], tok['text']
            if style == self.classifier.style_word and \
               (cmdStart or tok['start_column'] == self.tokenizer.get_curr_indentation()):
                cmdStart = False
                if text in ["namespace", "proc"]:
                    curr_indent = self.tokenizer.get_curr_indentation()
                    if text == "namespace":
                        tok1 = self.tokenizer.get_next_token()
                        if not (self.classifier.is_identifier(tok1, True)
                                and tok1['text'] == "eval"):
                            continue
                    node_class, node_parser = self.get_parsing_objects(text)
                    if node_class is None:
                        sys.stderr.write(
                            "Couldn't get parsing objects for type %s\n" %
                            text)
                        break

                    # Get the comments before further parsing.
                    comment_lines = remove_hashes(
                        self.tokenizer.curr_comment())
                    nm_token = self.get_fully_qualified_name()
                    fqname = nm_token[0]
                    if not fqname:
                        break
                    # Handle only local names for now
                    if fqname.startswith("::") and text == "namespace":
                        fqname = fqname[2:]

                    new_node = node_class(fqname, tok['start_line'])
                    new_node.doc_lines = comment_lines
                    new_node.indentation = curr_indent
                    self.block_stack.append(new_node)
                    curr_node.append_node(new_node)

                    # Push new containers on the symbol table
                    self.containers[VAR_KIND_LOCAL].append(new_node.local_vars)

                    node_parser(new_node)  # Has self bound to it
                    self.block_stack.pop()
                    self.containers[VAR_KIND_LOCAL].pop()

                    # Clear any comment that's hanging around
                    self.tokenizer.clear_comments()

                elif text == "package":
                    tok1 = self.tokenizer.get_next_token()
                    if self.classifier.is_identifier(tok1, True):
                        if tok1['text'] == "require":
                            tok2 = self.tokenizer.get_next_token()
                            if self.classifier.is_identifier(
                                    tok2, True) and tok2['text'] != "Tcl":
                                curr_node.imports.append(
                                    Name_LineNum(tok2['text'],
                                                 tok['start_line']))
                elif text == "global":
                    # XXX: all tokens following 'global' should be declared vars
                    tok = self.tokenizer.get_next_token()
                    if self.classifier.is_identifier(tok, True):
                        curr_globals[tok['text']] = None
                elif text == "set":
                    # XXX: Needs to handle lappend, append, incr, variable
                    # XXX: possibly dict set, array set, upvar, lassign,
                    # XXX: foreach, regsub (non-inline)
                    tok = self.tokenizer.get_next_token()
                    if self.classifier.is_identifier(tok, True):
                        if curr_globals.has_key(tok['text']):
                            pass
                        else:
                            self.parse_assignment(
                                tok['text'], tok['start_line'],
                                isinstance(curr_node, MethodNode))
                elif text == "lassign":
                    tok = self.tokenizer.get_next_token()
                    if self.classifier.is_operator(tok, "{"):
                        start_line = tok['start_line']
                        isLocal = isinstance(curr_node, MethodNode)
                        if isLocal:
                            collectionA = self.containers[VAR_KIND_LOCAL]
                        else:
                            collectionA = self.containers[VAR_KIND_GLOBAL]
                        vars = self._parse_name_list()
                        for v in vars:
                            update_collection(collectionA[-1], v, start_line)
            elif self.classifier.is_any_operator(tok):
                cmdStart = False
                if text == "{":
                    braceCount += 1
                elif text == "}":
                    braceCount -= 1
                    if braceCount <= 0:
                        break
                elif text in (";", "["):
                    cmdStart = True
                elif text == "\\":
                    # Skip the next token, whatever it is - bug 74850
                    tok = self.tokenizer.get_next_token()
            else:
                cmdStart = False
            # Sanity check to make sure we haven't gone too far.
            tok_count += 1
            if tok_count > tok_lim and tok['start_column'] < init_indentation:
                break
        # end while
        curr_node.set_line_end_num(self.tokenizer.curr_line_no())
        return tok['style'] != shared_lexer.EOF_STYLE
示例#2
0
    def parse_aux(self, curr_node, braceCount=0):
        init_indentation = curr_node.indentation
        tok_count = 0
        tok_lim = 1000
        cmdStart = True
        curr_globals = {}
        while 1:
            tok = self.tokenizer.get_next_token()
            if tok['style'] == shared_lexer.EOF_STYLE:
                break
            if tok['text'] == 'oo':
                # Lookahead for oo::class and oo::define.
                next_tok = self.tokenizer.get_next_token()
                if self.classifier.is_operator(next_tok, '::'):
                    next_tok = self.tokenizer.get_next_token()
                    if next_tok['text'] in ["class", "define"]:
                        tok = next_tok
                        oo_token = True
                    else:
                        self.tokenizer.put_back(next_tok)
                else:
                    self.tokenizer.put_back(next_tok)
            else:
                oo_token = False
            # style, text, start_column, start_line, end_column, end_line = tok
            style, text = tok['style'], tok['text']
            if style == self.classifier.style_word and \
               (cmdStart or tok['start_column'] == self.tokenizer.get_curr_indentation()) or \
               oo_token:
                cmdStart = False
                if text in [
                        "namespace",
                        "proc",
                        # Either oo::class or oo::define.
                        "class",
                        "define",
                        # Instance methods.
                        "method",
                        "constructor",
                        "destructor"
                ]:
                    curr_indent = self.tokenizer.get_curr_indentation()
                    if text == "namespace":
                        tok1 = self.tokenizer.get_next_token()
                        if not (self.classifier.is_identifier(tok1, True)
                                and tok1['text'] == "eval"):
                            continue
                    node_class, node_parser = self.get_parsing_objects(text)
                    if node_class is None:
                        sys.stderr.write(
                            "Couldn't get parsing objects for type %s\n" %
                            text)
                        break

                    # Get the comments before further parsing.
                    comment_lines = remove_hashes(
                        self.tokenizer.curr_comment())
                    if text == "class":
                        # Since syntax is oo::class create ClassName, skip over
                        # the "create" token such that the name is the next
                        # token.
                        tok = self.tokenizer.get_next_token()
                        if tok['text'] != "create":
                            break
                    if text not in ["constructor", "destructor"]:
                        nm_token = self.get_fully_qualified_name()
                        fqname = nm_token[0]
                    else:
                        fqname = text
                    if not fqname:
                        break
                    # Handle only local names for now
                    if fqname.startswith("::") and text == "namespace":
                        fqname = fqname[2:]

                    # Create a new node for the namespace, proc, class, method,
                    # etc.
                    # However, for oo::define, the subsequent body should be
                    # added to an existing class. Find the previously created
                    # node and use it as the "new" node.
                    existing_node_found = False
                    if text == "define":
                        for node in curr_node.children:
                            if node.name == fqname:
                                new_node = node
                                existing_node_found = True
                                break
                    if not existing_node_found:
                        # Create the new parent node.
                        new_node = node_class(fqname, tok['start_line'])
                        new_node.doc_lines = comment_lines
                        new_node.indentation = curr_indent
                        curr_node.append_node(new_node)
                        # TODO: instance method names with lowercase are public
                        # while others are private. However, "export" can make
                        # private members public.

                    # For oo::class, determine if there's a body after it.
                    class_body = False
                    if text == "class":
                        next_tok = self.tokenizer.get_next_token()
                        class_body = self.classifier.is_operator(next_tok, '{')
                        self.tokenizer.put_back(next_tok)

                    # Anything in the subsequent body belongs to the parent
                    # node. Set this up.
                    if text != "class" or class_body:
                        self.block_stack.append(new_node)

                        # Push new containers on the symbol table
                        self.containers[VAR_KIND_LOCAL].append(
                            new_node.local_vars)

                        node_parser(new_node)  # Has self bound to it
                        self.block_stack.pop()
                        self.containers[VAR_KIND_LOCAL].pop()

                    # Clear any comment that's hanging around
                    self.tokenizer.clear_comments()

                elif text == "package":
                    tok1 = self.tokenizer.get_next_token()
                    if self.classifier.is_identifier(tok1, True):
                        if tok1['text'] == "require":
                            tok2 = self.tokenizer.get_next_token()
                            if self.classifier.is_identifier(
                                    tok2, True) and tok2['text'] != "Tcl":
                                curr_node.imports.append(
                                    Name_LineNum(tok2['text'],
                                                 tok['start_line']))
                elif text == "global":
                    # XXX: all tokens following 'global' should be declared vars
                    tok = self.tokenizer.get_next_token()
                    if self.classifier.is_identifier(tok, True):
                        curr_globals[tok['text']] = None
                elif text == "set":
                    # XXX: Needs to handle lappend, append, incr, variable
                    # XXX: possibly dict set, array set, upvar, lassign,
                    # XXX: foreach, regsub (non-inline)
                    isLocal = isinstance(curr_node, MethodNode)
                    tok = self.tokenizer.get_next_token()
                    if self.classifier.is_operator(tok, '::'):
                        # Possibly a global variable. Check the next two tokens.
                        ident = self.tokenizer.get_next_token()
                        afterIdent = self.tokenizer.get_next_token()
                        if not self.classifier.is_operator(afterIdent, '::'):
                            # Valid global variable. Put back second token.
                            tok = ident
                            isLocal = False
                            self.tokenizer.put_back(afterIdent)
                        else:
                            # Not a valid global variable
                            # (e.g. "set ::foo::bar ..."). Put back both tokens.
                            self.tokenizer.put_back(afterIdent)
                            self.tokenizer.put_back(ident)
                    if self.classifier.is_identifier(tok, True):
                        if tok['text'] in curr_globals:
                            pass
                        elif len(self.block_stack) > 1 and \
                             isinstance(self.block_stack[-2], ClassNode) and \
                             tok['text'] in self.block_stack[-2].local_vars:
                            # Declared instance variable. Move along.
                            pass
                        else:
                            self.parse_assignment(tok['text'],
                                                  tok['start_line'], isLocal)
                elif text == "variable" and isinstance(curr_node, ModuleNode):
                    # "variable" declarations in namespaces are considered
                    # namespace variables.
                    tok = self.tokenizer.get_next_token()
                    if self.classifier.is_identifier(tok, True):
                        self.parse_assignment(tok['text'], tok['start_line'],
                                              True)
                elif text == "variable" and isinstance(curr_node, ClassNode):
                    # "variable" declarations in classes are considered instance
                    # variables.
                    line_num = tok['start_line']
                    tok = self.tokenizer.get_next_token()
                    while self.classifier.is_identifier(tok, True) and \
                          tok['start_line'] == line_num:
                        self.parse_assignment(tok['text'], tok['start_line'],
                                              True)
                        tok = self.tokenizer.get_next_token()
                    self.tokenizer.put_back(tok)
                elif text == "lassign":
                    tok = self.tokenizer.get_next_token()
                    if self.classifier.is_operator(tok, "{"):
                        start_line = tok['start_line']
                        isLocal = isinstance(curr_node, MethodNode)
                        if isLocal:
                            collectionA = self.containers[VAR_KIND_LOCAL]
                        else:
                            collectionA = self.containers[VAR_KIND_GLOBAL]
                        vars = self._parse_name_list()
                        for v in vars:
                            update_collection(collectionA[-1], v, start_line)
            elif self.classifier.is_any_operator(tok):
                cmdStart = False
                if text == "{":
                    braceCount += 1
                elif text == "}":
                    braceCount -= 1
                    if braceCount <= 0:
                        break
                elif text in (";", "["):
                    cmdStart = True
                elif text == "\\":
                    # Skip the next token, whatever it is - bug 74850
                    tok = self.tokenizer.get_next_token()
            else:
                cmdStart = False
            # Sanity check to make sure we haven't gone too far.
            tok_count += 1
            if tok_count > tok_lim and tok['start_column'] < init_indentation:
                break
        # end while
        curr_node.set_line_end_num(self.tokenizer.curr_line_no())
        return tok['style'] != shared_lexer.EOF_STYLE