def grammar_parse()

in automation/tinc/main/ext/modgrammar/grammar_py3.py [0:0]


    def grammar_parse(cls, text, index, sessiondata):
        """
        This method is called by the :mod:`modgrammar` parser system to actually attempt to match this grammar against a piece of text.  This method is not intended to be called directly by an application (use the :meth:`parser` method to obtain a :class:`GrammarParser` object and use that).  In advanced cases, this method can be overridden to provide custom parsing behaviors for a particular grammar type.

        NOTE: Overriding this method is very complicated and currently beyond the scope of this documentation.  This is not recommended for anyone who does not understand the :mod:`modgrammar` parser design very well.  (Someday, with luck, there will be some more documentation written on this advanced topic.)
        """

        grammar = cls.grammar
        grammar_min = cls.grammar_min
        grammar_max = cls.grammar_max
        greedy = cls.grammar_greedy
        if cls.grammar_whitespace is True:
            whitespace_re = util._whitespace_re
        else:
            whitespace_re = cls.grammar_whitespace
        objs = []
        states = []
        positions = []
        best_error = None
        pos = index
        first_pos = None

        while True:
            # Forward ho!
            while True:
                if not greedy and len(objs) >= grammar_min:
                    # If we're not "greedy", then try returning every match as soon as we
                    # get it (which will naturally return the shortest matches first)
                    yield (pos - index, cls(text.string, index, pos, objs))
                    # We need to copy objs for any further stuff, since it's now part of
                    # the object we yielded above, which our caller may be keeping for
                    # later, so if we modify it in-place we'll be screwing up the
                    # 'entities' list of that object in the process.
                    objs = list(objs)
                if len(objs) >= grammar_max:
                    break
                prews_pos = pos
                if whitespace_re:
                    while True:
                        m = whitespace_re.match(text.string, pos)
                        if m:
                            pos = m.end()
                        if pos < len(text.string) or text.eof:
                            break
                        text = yield (None, None)
                if first_pos is None:
                    first_pos = pos
                s = grammar[len(objs)].grammar_parse(text, pos, sessiondata)
                offset, obj = next(s)
                while offset is None:
                    if text.eof:
                        # Subgrammars should not be asking for more data after eof.
                        raise InternalError("{0} requested more data when at EOF".format(grammar[len(objs)]))
                    text = yield (None, None)
                    offset, obj = s.send(text)
                if offset is False:
                    best_error = util.update_best_error(best_error, obj)
                    pos = prews_pos
                    break
                objs.append(obj)
                states.append((pos, s))
                pos += offset
                # Went as far as we can forward and it didn't work.  Backtrack until we
            # find something else to follow...
            while True:
                if greedy and len(objs) >= grammar_min:
                    # If we are greedy, then return matches only after we've gone as far
                    # forward as possible, while we're backtracking (returns the longest
                    # matches first)
                    yield (pos - index, cls(text.string, index, pos, objs))
                    # We need to copy objs for any further stuff, since it's now part of
                    # the object we yielded above, which our caller may be keeping for
                    # later, so if we modify it in-place we'll be screwing up the
                    # 'entities' list of that object in the process.
                    objs = list(objs)
                if not states:
                    break
                pos, s = states[-1]
                offset, obj = next(s)
                while offset is None:
                    if text.eof:
                        # Subgrammars should not be asking for more data after eof.
                        raise InternalError("{0} requested more data when at EOF".format(grammar[len(objs) - 1]))
                    text = yield (None, None)
                    offset, obj = s.send(text)
                if offset is False:
                    best_error = util.update_best_error(best_error, obj)
                    states.pop()
                    objs.pop()
                else:
                    objs[-1] = obj
                    pos += offset
                    break
                    # Have we gone all the way back to the beginning?
                    # If so, give up.  If not, loop around and try going forward again.
            if not states:
                break
        if cls.grammar_error_override:
            # If our sub-grammars failed to match, but we've got
            # grammar_error_override set, return ourselves as the failed match
            # grammar instead.
            yield util.error_result(index, cls)
        elif ((len(cls.grammar) == 1)
              and (best_error[0] == first_pos)
              and (cls.grammar_desc != cls.grammar_name) ):
            # We're just a simple wrapper (i.e. an alias) around another single
            # grammar class, and it failed to match, and we have a custom
            # grammar_desc.  Return ourselves as the failed match grammar so the
            # ParseError will contain our grammar_desc instead.
            yield util.error_result(index, cls)
        else:
            yield util.error_result(*best_error)