in automation/tinc/main/ext/modgrammar/grammar_py2.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)