@@ -10,7 +10,43 @@ class Rule(object): | |||
self.alias = alias | |||
self.options = options | |||
def __repr__(self): | |||
def __str__(self): | |||
return '<%s : %s>' % (self.origin, ' '.join(map(str,self.expansion))) | |||
def __repr__(self): | |||
return 'Rule(%r, %r, %r, %r)' % (self.origin, self.expansion, self.alias, self.options) | |||
class RuleOptions: | |||
def __init__(self, keep_all_tokens=False, expand1=False, create_token=None, filter_out=False, priority=None): | |||
self.keep_all_tokens = keep_all_tokens | |||
self.expand1 = expand1 | |||
self.create_token = create_token # used for scanless postprocessing | |||
self.priority = priority | |||
self.filter_out = filter_out # remove this rule from the tree | |||
# used for "token"-rules in scanless | |||
@classmethod | |||
def from_rule(cls, name, *x): | |||
if len(x) > 1: | |||
priority, expansions = x | |||
priority = int(priority) | |||
else: | |||
expansions ,= x | |||
priority = None | |||
keep_all_tokens = name.startswith('!') | |||
name = name.lstrip('!') | |||
expand1 = name.startswith('?') | |||
name = name.lstrip('?') | |||
return name, expansions, cls(keep_all_tokens, expand1, priority=priority) | |||
def __repr__(self): | |||
return 'RuleOptions(%r, %r, %r, %r, %r)' % ( | |||
self.keep_all_tokens, | |||
self.expand1, | |||
self.create_token, | |||
self.priority, | |||
self.filter_out | |||
) |
@@ -111,35 +111,11 @@ def build_mres(tokens, match_whole=False): | |||
return _build_mres(tokens, len(tokens), match_whole) | |||
class LineCounter: | |||
def __init__(self): | |||
self.newline_char = '\n' | |||
self.char_pos = 0 | |||
self.line = 1 | |||
self.column = 0 | |||
self.line_start_pos = 0 | |||
def feed(self, token, test_newline=True): | |||
"""Consume a token and calculat the new line & column. | |||
As an optional optimization, set test_newline=False is token doesn't contain a newline. | |||
""" | |||
if test_newline: | |||
newlines = token.count(self.newline_char) | |||
if newlines: | |||
self.line += newlines | |||
self.line_start_pos = self.char_pos + token.rindex(self.newline_char) + 1 | |||
self.char_pos += len(token) | |||
self.column = self.char_pos - self.line_start_pos | |||
class Lexer: | |||
def __init__(self, tokens, ignore=()): | |||
assert all(isinstance(t, TokenDef) for t in tokens), tokens | |||
self.ignore = ignore | |||
tokens = list(tokens) | |||
# Sanitization | |||
@@ -156,7 +132,7 @@ class Lexer: | |||
# Init | |||
self.newline_types = [t.name for t in tokens if _regexp_has_newline(t.pattern.to_regexp())] | |||
self.ignore_types = [t for t in ignore] | |||
self.ignore_types = list(ignore) | |||
tokens.sort(key=lambda x:(-x.priority, -x.pattern.max_width, -len(x.pattern.value), x.name)) | |||
@@ -206,6 +182,30 @@ class ContextualLexer: | |||
l.lexer = self.lexers[self.parser_state] | |||
###{lexer | |||
class LineCounter: | |||
def __init__(self): | |||
self.newline_char = '\n' | |||
self.char_pos = 0 | |||
self.line = 1 | |||
self.column = 0 | |||
self.line_start_pos = 0 | |||
def feed(self, token, test_newline=True): | |||
"""Consume a token and calculate the new line & column. | |||
As an optional optimization, set test_newline=False is token doesn't contain a newline. | |||
""" | |||
if test_newline: | |||
newlines = token.count(self.newline_char) | |||
if newlines: | |||
self.line += newlines | |||
self.line_start_pos = self.char_pos + token.rindex(self.newline_char) + 1 | |||
self.char_pos += len(token) | |||
self.column = self.char_pos - self.line_start_pos | |||
class _Lex: | |||
"Built to serve both Lexer and ContextualLexer" | |||
def __init__(self, lexer): | |||
@@ -235,4 +235,4 @@ class _Lex: | |||
if line_ctr.char_pos < len(stream): | |||
raise UnexpectedInput(stream, line_ctr.char_pos, line_ctr.line, line_ctr.column) | |||
break | |||
###} |
@@ -12,6 +12,7 @@ from .parse_tree_builder import ParseTreeBuilder | |||
from .parser_frontends import LALR | |||
from .parsers.lalr_parser import UnexpectedToken | |||
from .common import is_terminal, GrammarError, LexerConf, ParserConf, PatternStr, PatternRE, TokenDef | |||
from .grammar import RuleOptions | |||
from .tree import Tree as T, Transformer, InlineTransformer, Visitor | |||
@@ -494,33 +495,6 @@ class Grammar: | |||
class RuleOptions: | |||
def __init__(self, keep_all_tokens=False, expand1=False, create_token=None, filter_out=False, priority=None): | |||
self.keep_all_tokens = keep_all_tokens | |||
self.expand1 = expand1 | |||
self.create_token = create_token # used for scanless postprocessing | |||
self.priority = priority | |||
self.filter_out = filter_out # remove this rule from the tree | |||
# used for "token"-rules in scanless | |||
@classmethod | |||
def from_rule(cls, name, *x): | |||
if len(x) > 1: | |||
priority, expansions = x | |||
priority = int(priority) | |||
else: | |||
expansions ,= x | |||
priority = None | |||
keep_all_tokens = name.startswith('!') | |||
name = name.lstrip('!') | |||
expand1 = name.startswith('?') | |||
name = name.lstrip('?') | |||
return name, expansions, cls(keep_all_tokens, expand1, priority=priority) | |||
_imported_grammars = {} | |||
def import_grammar(grammar_path): | |||
if grammar_path not in _imported_grammars: | |||
@@ -15,13 +15,15 @@ from ..common import GrammarError, is_terminal | |||
from .grammar_analysis import GrammarAnalyzer | |||
class Action: | |||
def __init__(self, name): | |||
self.name = name | |||
def __str__(self): | |||
return self.__name__ | |||
return self.name | |||
def __repr__(self): | |||
return str(self) | |||
class Shift(Action): pass | |||
class Reduce(Action): pass | |||
Shift = Action('Shift') | |||
Reduce = Action('Reduce') | |||
class ParseTable: | |||
def __init__(self, states, start_state, end_state): | |||
@@ -7,10 +7,6 @@ from ..common import ParseError, UnexpectedToken | |||
from .lalr_analysis import LALR_Analyzer, Shift | |||
class FinalReduce: | |||
def __init__(self, value): | |||
self.value = value | |||
class Parser: | |||
def __init__(self, parser_conf): | |||
assert all(r.options is None or r.options.priority is None | |||
@@ -20,6 +16,7 @@ class Parser: | |||
callbacks = {rule: getattr(parser_conf.callback, rule.alias or rule.origin, None) | |||
for rule in analysis.rules} | |||
self.parser_conf = parser_conf | |||
self.parser = _Parser(analysis.parse_table, callbacks) | |||
self.parse = self.parser.parse | |||