def checkpoint(self, id): ''' Successive calls to checkpoint with the same id must consume text. If they don't, there is an error (a repeating empty loop) and the engine should abort (raise an exception). ''' raise UnsupportedOperation('checkpoint')
def run(self, stream, pos=0, search=False, fail_on_groups=True): self._initial_stream = stream # TODO - add explicit search if expression starts with constant self.group_defined = False result = self._run_from(0, stream, pos, search) if self.group_defined and fail_on_groups: raise UnsupportedOperation('groups') else: return result
def lookahead(self, next, equal, forwards, mutates, reads, length): # discard old values if self._lookaheads[0] != self._offset: self._lookaheads = (self._offset, {}) lookaheads = self._lookaheads[1] if next[1] not in lookaheads: # requires complex engine if reads: raise UnsupportedOperation('lookahead') size = None if (reads and mutates) else length(None) # invoke simple engine and cache self._push() try: if forwards: stream = self._initial_stream pos = self._offset search = False else: (text, _) = s_next(self._initial_stream, self._offset) stream = s_stream(self._initial_stream, text) if size is None: pos = 0 search = True else: pos = self._offset - size search = False if pos >= 0: result = bool(self._run_from(next[1], stream, pos, search)) == equal else: result = not equal finally: self._pop() lookaheads[next[1]] = result if lookaheads[next[1]]: return next[0] else: raise Fail
def group_reference(self, next, number): raise UnsupportedOperation('group_reference')
def group_reference(self, next, number): '''Match a previously matched group.''' raise UnsupportedOperation('group_reference')
def word(self, inverted): '''Match a word.''' raise UnsupportedOperation('word')
def digit(self, inverted): '''Match a digit.''' raise UnsupportedOperation('digit')
def end_of_line(self, multiline): '''Match the end of a line.''' raise UnsupportedOperation('end_of_line')
def dot(self, multiline): '''Match "any" character (exact details depend on regexp options).''' raise UnsupportedOperation('dot')
def match(self): '''Indicate a successful (end of) a match.''' raise UnsupportedOperation('match')
def word(self, char, flags): '''Test whether the character is a word character or not.''' raise UnsupportedOperation('word')
def space(self, char, flags): '''Test whether the character is a whitespace or not.''' raise UnsupportedOperation('space')
def digit(self, char, flags): '''Test whether the character is a digit or not.''' raise UnsupportedOperation('digit')
def repeat(self, next, begin, end, lazy): raise UnsupportedOperation('repeat')
def conditional(self, next, number): raise UnsupportedOperation('conditional')
def start_group(self, number): '''Start a numbered group.''' raise UnsupportedOperation('start_group')
def end_group(self, number): '''End a numbered group (called symmetrically with `start_group()`).''' raise UnsupportedOperation('end_group')
def split(self, next): ''' A branch (alternatives ordered by priority). For example, this is used to implement repetition. ''' raise UnsupportedOperation('split')
def no_match(self): '''Indicate a failure to match.''' raise UnsupportedOperation('no_match')
def lookahead(self, next, equal, forwards, mutates, reads, length): '''Perform a lookahead match.''' raise UnsupportedOperation('lookahead')
def start_of_line(self, multiline): '''Match the start of a line.''' raise UnsupportedOperation('start_of_line')
def repeat(self, next, begin, end, lazy): '''Perform a counted repetition.''' raise UnsupportedOperation('repeat')
def word_boundary(self, inverted): '''Match a word boundary.''' raise UnsupportedOperation('word_boundary')
def string(self, next, text): '''Literal text replacement.''' raise UnsupportedOperation('string')
def space(self, inverted): '''Match a space character.''' raise UnsupportedOperation('space')
def group_reference(self, next, number): '''Replace with matched data.''' raise UnsupportedOperation('group_reference')
def string(self, next, text): '''Match the given literal.''' raise UnsupportedOperation('string')
def character(self, charset): '''Match the given character (more exactly, a "string" of length 1).''' raise UnsupportedOperation('character')
def conditional(self, next, number): '''Condition on a previously matched group.''' raise UnsupportedOperation('conditional')
def run(self, stream, pos=0, search=False): if pos or search: raise UnsupportedOperation('Search') self._initial_stream = stream self._reset(0, stream, None) self._checkpoints = {} self._last_group = 0 # default for no group self._states = [(0, 0)] try: while self._states and self._excess < 2: known_next = set() next_states = [] while self._states: # unpack state (index, skip) = self._states.pop() try: if not skip: # process the current character index = self._program[index]() if index not in known_next: next_states.append((index, 0)) known_next.add(index) elif skip < 0: raise Match else: skip -= 1 # if we have other states if next_states or self._states: if (index, skip) not in known_next: next_states.append((index, skip)) known_next.add((index, skip)) # otherwise, we can jump directly else: self._advance(skip) next_states.append((index, 0)) except Fail: pass except Match: # no groups starting earlier? if skip >= 0: skip = self._last_group if not next_states: raise # some other, pending, earlier starting, state may # still give a match if index not in known_next: next_states.append((index, skip)) known_next.add(index) # but we can discard anything that starts later self._states = [] # move to next character self._advance() self._states = next_states self._states.reverse() # pick first matched state, if any while self._states: (index, skip) = self._states.pop() if skip < 0: raise Match # exhausted states with no match return Groups() except Match: groups = Groups(group_state=self._parser_state.groups, stream=self._initial_stream) groups.start_group(0, 0) groups.end_group(0, self._offset) groups.start_group(-skip, 0) groups.end_group(-skip, self._offset) return groups