def match(self, lexer: Lexer, debug: int = 0, partial=True):

        if debug:
            print(' ' * (debug - 1) +
                  f'### Group {self.name}.match(), calling super\'s match()')

        tree = Ast(self.name, lexer.current_position(), grammars=[])
        if lexer.current_token is None\
            or lexer.current_token.spelling == '_EOF':
            if self.repeat[0] == 0:
                return tree
            return None

        lexer.anchor()
        repetition = 0
        if self.repeat[1] == -1:
            # can repeat for infinite times: grammar* | grammar+ | grammar{a,}
            while True:
                nodes = super().match(lexer, debug)
                if nodes is None:
                    break
                tree.extend(nodes)
                repetition += 1
                if lexer.current_token is None:
                    break
        else:
            # repeat for limited times: grammar{a, b} | grammar{a} | [grammar]
            while True:
                if repetition >= self.repeat[1]:
                    break
                nodes = super().match(lexer, debug)
                if nodes is None:
                    break
                tree.extend(nodes)
                repetition += 1
                if lexer.current_token is None:
                    break

        if repetition < self.repeat[0]:
            # if actual repetition is smaller than minimum times

            if debug:
                print(
                    ' ' * (debug - 1) +
                    f'--- Group {self.name}.match() FAILED in minimal repetition)'
                )

            lexer.backward()

            if debug:
                print(
                    f'<<< lexer backwarded, current token: {lexer.current_token}'
                )

            return None

        if debug:
            print(' ' * (debug - 1) + f'+++ Group {self.name}.match() SUCCESS')
        lexer.release_anchor()
        return tree
Exemple #2
0
    def build_ast(self, tree: Ast, lexer: Lexer, production_list: list,
                  recursive_productions: list = None, debug: int = 0):
        """
        build ast tree on the given instance (parameter `tree`)

        return True: SUCCESS, tree is appended with nodes
        return False: FAILED, and tree is untouched
        return None: Epsilon
        """
        if debug:
            print(' ' * (debug - 1) + f'### {self.name}.build_ast()')

        for grammar in production_list:
            nodes = grammar.match(lexer,
                                  debug + 4) if debug else grammar.match(lexer)

            # this grammar not matched:
            # 1. abandon whole production_list and skipped loop
            # 2. lexer setup rollback flag
            if nodes is None:

                if debug:
                    print(' ' * (
                        debug - 1) + f'--- {self.name}.build_ast() with grammar <{grammar}> FAILED')

                tree.empty()
                lexer.backward()

                if debug:
                    print(
                        f'<<< lexer backwarded, current token: {lexer.current_token}')

                return False

            if nodes == '_E':
                # Epsilon
                if debug:
                    print(' ' * (debug - 1) + f'+++ Epsilon match')
                    tree.append(Ast('Epsilon', lexer.current_token.position,
                                    grammar='_e'))
                return None

            if isinstance(grammar, Group):
                # grammar is a Group
                if not self.ignore_set:
                    tree.extend(nodes)
                else:
                    for node in nodes:
                        if node.name not in self.ignore_set:
                            tree.append(node)
            else:
                # grammar is a Token, only one production hence nodes is
                # actually a `node`
                if not self.ignore_set or nodes.name not in self.ignore_set:
                    tree.append(nodes)

        # all grammar in current production_list matched, operation SUCCESS
        if debug:
            print(' ' * (debug - 1) + f'+++ {self.name}.build_ast() SUCCESS')

        return True