@@ -10,7 +10,43 @@ class Rule(object): | |||||
self.alias = alias | self.alias = alias | ||||
self.options = options | self.options = options | ||||
def __repr__(self): | |||||
def __str__(self): | |||||
return '<%s : %s>' % (self.origin, ' '.join(map(str,self.expansion))) | 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) | 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: | class Lexer: | ||||
def __init__(self, tokens, ignore=()): | def __init__(self, tokens, ignore=()): | ||||
assert all(isinstance(t, TokenDef) for t in tokens), tokens | assert all(isinstance(t, TokenDef) for t in tokens), tokens | ||||
self.ignore = ignore | |||||
tokens = list(tokens) | tokens = list(tokens) | ||||
# Sanitization | # Sanitization | ||||
@@ -156,7 +132,7 @@ class Lexer: | |||||
# Init | # Init | ||||
self.newline_types = [t.name for t in tokens if _regexp_has_newline(t.pattern.to_regexp())] | 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)) | 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] | 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: | class _Lex: | ||||
"Built to serve both Lexer and ContextualLexer" | "Built to serve both Lexer and ContextualLexer" | ||||
def __init__(self, lexer): | def __init__(self, lexer): | ||||
@@ -235,4 +235,4 @@ class _Lex: | |||||
if line_ctr.char_pos < len(stream): | if line_ctr.char_pos < len(stream): | ||||
raise UnexpectedInput(stream, line_ctr.char_pos, line_ctr.line, line_ctr.column) | raise UnexpectedInput(stream, line_ctr.char_pos, line_ctr.line, line_ctr.column) | ||||
break | break | ||||
###} |
@@ -12,6 +12,7 @@ from .parse_tree_builder import ParseTreeBuilder | |||||
from .parser_frontends import LALR | from .parser_frontends import LALR | ||||
from .parsers.lalr_parser import UnexpectedToken | from .parsers.lalr_parser import UnexpectedToken | ||||
from .common import is_terminal, GrammarError, LexerConf, ParserConf, PatternStr, PatternRE, TokenDef | from .common import is_terminal, GrammarError, LexerConf, ParserConf, PatternStr, PatternRE, TokenDef | ||||
from .grammar import RuleOptions | |||||
from .tree import Tree as T, Transformer, InlineTransformer, Visitor | 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 = {} | _imported_grammars = {} | ||||
def import_grammar(grammar_path): | def import_grammar(grammar_path): | ||||
if grammar_path not in _imported_grammars: | if grammar_path not in _imported_grammars: | ||||
@@ -15,13 +15,15 @@ from ..common import GrammarError, is_terminal | |||||
from .grammar_analysis import GrammarAnalyzer | from .grammar_analysis import GrammarAnalyzer | ||||
class Action: | class Action: | ||||
def __init__(self, name): | |||||
self.name = name | |||||
def __str__(self): | def __str__(self): | ||||
return self.__name__ | |||||
return self.name | |||||
def __repr__(self): | def __repr__(self): | ||||
return str(self) | return str(self) | ||||
class Shift(Action): pass | |||||
class Reduce(Action): pass | |||||
Shift = Action('Shift') | |||||
Reduce = Action('Reduce') | |||||
class ParseTable: | class ParseTable: | ||||
def __init__(self, states, start_state, end_state): | def __init__(self, states, start_state, end_state): | ||||
@@ -7,10 +7,6 @@ from ..common import ParseError, UnexpectedToken | |||||
from .lalr_analysis import LALR_Analyzer, Shift | from .lalr_analysis import LALR_Analyzer, Shift | ||||
class FinalReduce: | |||||
def __init__(self, value): | |||||
self.value = value | |||||
class Parser: | class Parser: | ||||
def __init__(self, parser_conf): | def __init__(self, parser_conf): | ||||
assert all(r.options is None or r.options.priority is None | 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) | callbacks = {rule: getattr(parser_conf.callback, rule.alias or rule.origin, None) | ||||
for rule in analysis.rules} | for rule in analysis.rules} | ||||
self.parser_conf = parser_conf | |||||
self.parser = _Parser(analysis.parse_table, callbacks) | self.parser = _Parser(analysis.parse_table, callbacks) | ||||
self.parse = self.parser.parse | self.parse = self.parser.parse | ||||