Added Lexer state change

This commit is contained in:
David Beazley 2017-09-01 06:31:51 -05:00
parent 636197b9fd
commit d8903d8301

View File

@ -32,7 +32,7 @@
# ----------------------------------------------------------------------------- # -----------------------------------------------------------------------------
__version__ = '0.1' __version__ = '0.1'
__all__ = ['Lexer'] __all__ = ['Lexer', 'LexerStateChange']
import re import re
from collections import OrderedDict from collections import OrderedDict
@ -62,6 +62,14 @@ class LexerBuildError(Exception):
''' '''
pass pass
class LexerStateChange(Exception):
'''
Exception raised to force a lexing state change
'''
def __init__(self, newstate, tok=None):
self.newstate = newstate
self.tok = tok
class Token(object): class Token(object):
''' '''
Representation of a single token. Representation of a single token.
@ -192,6 +200,7 @@ class Lexer(metaclass=LexerMeta):
raise LexerBuildError('literals must be specified as strings') raise LexerBuildError('literals must be specified as strings')
def tokenize(self, text, lineno=1, index=0): def tokenize(self, text, lineno=1, index=0):
while True:
# Local copies of frequently used values # Local copies of frequently used values
_ignored_tokens = self._ignored_tokens _ignored_tokens = self._ignored_tokens
_master_re = self._master_re _master_re = self._master_re
@ -207,7 +216,7 @@ class Lexer(metaclass=LexerMeta):
index += 1 index += 1
continue continue
except IndexError: except IndexError:
break return
tok = Token() tok = Token()
tok.lineno = lineno tok.lineno = lineno
@ -246,6 +255,11 @@ class Lexer(metaclass=LexerMeta):
index = self.index index = self.index
lineno = self.lineno lineno = self.lineno
except LexerStateChange as e:
self.__class__ = e.newstate
if e.tok:
yield e.tok
# Set the final state of the lexer before exiting (even if exception) # Set the final state of the lexer before exiting (even if exception)
finally: finally:
self.text = text self.text = text