@@ -8,9 +8,9 @@ class LexerConf: | |||||
self.callbacks = callbacks or {} | self.callbacks = callbacks or {} | ||||
class ParserConf: | class ParserConf: | ||||
def __init__(self, rules, callback, start): | |||||
def __init__(self, rules, callbacks, start): | |||||
self.rules = rules | self.rules = rules | ||||
self.callback = callback | |||||
self.callbacks = callbacks | |||||
self.start = start | self.start = start | ||||
@@ -132,7 +132,7 @@ class Lark: | |||||
raise NotImplementedError("Not available yet") | raise NotImplementedError("Not available yet") | ||||
assert not self.options.profile, "Feature temporarily disabled" | assert not self.options.profile, "Feature temporarily disabled" | ||||
self.profiler = Profiler() if self.options.profile else None | |||||
# self.profiler = Profiler() if self.options.profile else None | |||||
if self.options.lexer == 'auto': | if self.options.lexer == 'auto': | ||||
if self.options.parser == 'lalr': | if self.options.parser == 'lalr': | ||||
@@ -192,8 +192,6 @@ class Lark: | |||||
elif lexer: | elif lexer: | ||||
self.lexer = self._build_lexer() | self.lexer = self._build_lexer() | ||||
if self.profiler: self.profiler.enter_section('outside_lark') | |||||
if __init__.__doc__: | if __init__.__doc__: | ||||
__init__.__doc__ += "\nOPTIONS:" + LarkOptions.OPTIONS_DOC | __init__.__doc__ += "\nOPTIONS:" + LarkOptions.OPTIONS_DOC | ||||
@@ -204,13 +202,9 @@ class Lark: | |||||
self.parser_class = get_frontend(self.options.parser, self.options.lexer) | self.parser_class = get_frontend(self.options.parser, self.options.lexer) | ||||
self._parse_tree_builder = ParseTreeBuilder(self.rules, self.options.tree_class, self.options.propagate_positions, self.options.keep_all_tokens, self.options.parser!='lalr' and self.options.ambiguity=='explicit', self.options.maybe_placeholders) | self._parse_tree_builder = ParseTreeBuilder(self.rules, self.options.tree_class, self.options.propagate_positions, self.options.keep_all_tokens, self.options.parser!='lalr' and self.options.ambiguity=='explicit', self.options.maybe_placeholders) | ||||
callback = self._parse_tree_builder.create_callback(self.options.transformer) | |||||
if self.profiler: | |||||
for f in dir(callback): | |||||
if not (f.startswith('__') and f.endswith('__')): | |||||
setattr(callback, f, self.profiler.make_wrapper('transformer', getattr(callback, f))) | |||||
callbacks = self._parse_tree_builder.create_callback(self.options.transformer) | |||||
parser_conf = ParserConf(self.rules, callback, self.options.start) | |||||
parser_conf = ParserConf(self.rules, callbacks, self.options.start) | |||||
return self.parser_class(self.lexer_conf, parser_conf, options=self.options) | return self.parser_class(self.lexer_conf, parser_conf, options=self.options) | ||||
@@ -187,10 +187,6 @@ def maybe_create_ambiguous_expander(tree_class, expansion, keep_all_tokens): | |||||
if to_expand: | if to_expand: | ||||
return partial(AmbiguousExpander, to_expand, tree_class) | return partial(AmbiguousExpander, to_expand, tree_class) | ||||
class Callback(object): | |||||
pass | |||||
def ptb_inline_args(func): | def ptb_inline_args(func): | ||||
@wraps(func) | @wraps(func) | ||||
def f(children): | def f(children): | ||||
@@ -207,8 +203,6 @@ class ParseTreeBuilder: | |||||
self.rule_builders = list(self._init_builders(rules)) | self.rule_builders = list(self._init_builders(rules)) | ||||
self.user_aliases = {} | |||||
def _init_builders(self, rules): | def _init_builders(self, rules): | ||||
for rule in rules: | for rule in rules: | ||||
options = rule.options | options = rule.options | ||||
@@ -226,12 +220,9 @@ class ParseTreeBuilder: | |||||
def create_callback(self, transformer=None): | def create_callback(self, transformer=None): | ||||
callback = Callback() | |||||
callbacks = {} | |||||
i = 0 | |||||
for rule, wrapper_chain in self.rule_builders: | for rule, wrapper_chain in self.rule_builders: | ||||
internal_callback_name = '_cb%d_%s' % (i, rule.origin) | |||||
i += 1 | |||||
user_callback_name = rule.alias or rule.origin.name | user_callback_name = rule.alias or rule.origin.name | ||||
try: | try: | ||||
@@ -243,16 +234,14 @@ class ParseTreeBuilder: | |||||
except AttributeError: | except AttributeError: | ||||
f = partial(self.tree_class, user_callback_name) | f = partial(self.tree_class, user_callback_name) | ||||
self.user_aliases[rule] = rule.alias | |||||
rule.alias = internal_callback_name | |||||
for w in wrapper_chain: | for w in wrapper_chain: | ||||
f = w(f) | f = w(f) | ||||
if hasattr(callback, internal_callback_name): | |||||
if rule in callbacks: | |||||
raise GrammarError("Rule '%s' already exists" % (rule,)) | raise GrammarError("Rule '%s' already exists" % (rule,)) | ||||
setattr(callback, internal_callback_name, f) | |||||
return callback | |||||
callbacks[rule] = f | |||||
return callbacks | |||||
###} | ###} |
@@ -123,10 +123,7 @@ class CYK(WithLexer): | |||||
self._analysis = GrammarAnalyzer(parser_conf) | self._analysis = GrammarAnalyzer(parser_conf) | ||||
self._parser = cyk.Parser(parser_conf.rules, parser_conf.start) | self._parser = cyk.Parser(parser_conf.rules, parser_conf.start) | ||||
self._postprocess = {} | |||||
for rule in parser_conf.rules: | |||||
a = rule.alias | |||||
self._postprocess[a] = a if callable(a) else (a and getattr(parser_conf.callback, a)) | |||||
self.callbacks = parser_conf.callbacks | |||||
def parse(self, text): | def parse(self, text): | ||||
tokens = list(self.lex(text)) | tokens = list(self.lex(text)) | ||||
@@ -142,11 +139,7 @@ class CYK(WithLexer): | |||||
return self._apply_callback(tree) | return self._apply_callback(tree) | ||||
def _apply_callback(self, tree): | def _apply_callback(self, tree): | ||||
children = tree.children | |||||
callback = self._postprocess[tree.rule.alias] | |||||
assert callback, tree.rule.alias | |||||
r = callback(children) | |||||
return r | |||||
return self.callbacks[tree.rule](tree.children) | |||||
def get_frontend(parser, lexer): | def get_frontend(parser, lexer): | ||||
@@ -86,7 +86,7 @@ class Parser(object): | |||||
def __init__(self, rules, start): | def __init__(self, rules, start): | ||||
super(Parser, self).__init__() | super(Parser, self).__init__() | ||||
self.orig_rules = {rule.alias: rule for rule in rules} | |||||
self.orig_rules = {rule: rule for rule in rules} | |||||
rules = [self._to_rule(rule) for rule in rules] | rules = [self._to_rule(rule) for rule in rules] | ||||
self.grammar = to_cnf(Grammar(rules)) | self.grammar = to_cnf(Grammar(rules)) | ||||
self.start = NT(start) | self.start = NT(start) | ||||
@@ -98,7 +98,7 @@ class Parser(object): | |||||
return Rule( | return Rule( | ||||
lark_rule.origin, lark_rule.expansion, | lark_rule.origin, lark_rule.expansion, | ||||
weight=lark_rule.options.priority if lark_rule.options and lark_rule.options.priority else 0, | weight=lark_rule.options.priority if lark_rule.options and lark_rule.options.priority else 0, | ||||
alias=lark_rule.alias) | |||||
alias=lark_rule) | |||||
def parse(self, tokenized): # pylint: disable=invalid-name | def parse(self, tokenized): # pylint: disable=invalid-name | ||||
"""Parses input, which is a list of tokens.""" | """Parses input, which is a list of tokens.""" | ||||
@@ -27,7 +27,7 @@ class Parser: | |||||
self.FIRST = analysis.FIRST | self.FIRST = analysis.FIRST | ||||
self.NULLABLE = analysis.NULLABLE | self.NULLABLE = analysis.NULLABLE | ||||
self.callbacks = {} | |||||
self.callbacks = parser_conf.callbacks | |||||
self.predictions = {} | self.predictions = {} | ||||
## These could be moved to the grammar analyzer. Pre-computing these is *much* faster than | ## These could be moved to the grammar analyzer. Pre-computing these is *much* faster than | ||||
@@ -37,7 +37,6 @@ class Parser: | |||||
self.forest_sum_visitor = None | self.forest_sum_visitor = None | ||||
for rule in parser_conf.rules: | for rule in parser_conf.rules: | ||||
self.callbacks[rule] = rule.alias if callable(rule.alias) else getattr(parser_conf.callback, rule.alias) | |||||
self.predictions[rule.origin] = [x.rule for x in analysis.expand_rule(rule.origin)] | self.predictions[rule.origin] = [x.rule for x in analysis.expand_rule(rule.origin)] | ||||
## Detect if any rules have priorities set. If the user specified priority = "none" then | ## Detect if any rules have priorities set. If the user specified priority = "none" then | ||||
@@ -271,7 +271,8 @@ class ForestToTreeVisitor(ForestVisitor): | |||||
according to some priority mechanism. | according to some priority mechanism. | ||||
""" | """ | ||||
__slots__ = ['forest_sum_visitor', 'callbacks', 'output_stack'] | __slots__ = ['forest_sum_visitor', 'callbacks', 'output_stack'] | ||||
def __init__(self, callbacks = None, forest_sum_visitor = None): | |||||
def __init__(self, callbacks, forest_sum_visitor = None): | |||||
assert callbacks | |||||
self.forest_sum_visitor = forest_sum_visitor | self.forest_sum_visitor = forest_sum_visitor | ||||
self.callbacks = callbacks | self.callbacks = callbacks | ||||
@@ -13,8 +13,7 @@ class Parser: | |||||
for r in parser_conf.rules), "LALR doesn't yet support prioritization" | for r in parser_conf.rules), "LALR doesn't yet support prioritization" | ||||
analysis = LALR_Analyzer(parser_conf, debug=debug) | analysis = LALR_Analyzer(parser_conf, debug=debug) | ||||
analysis.compute_lookahead() | analysis.compute_lookahead() | ||||
callbacks = {rule: getattr(parser_conf.callback, rule.alias or rule.origin, None) | |||||
for rule in parser_conf.rules} | |||||
callbacks = parser_conf.callbacks | |||||
self._parse_table = analysis.parse_table | self._parse_table = analysis.parse_table | ||||
self.parser_conf = parser_conf | self.parser_conf = parser_conf | ||||
@@ -112,7 +112,8 @@ class Reconstructor: | |||||
def _reconstruct(self, tree): | def _reconstruct(self, tree): | ||||
# TODO: ambiguity? | # TODO: ambiguity? | ||||
parser = earley.Parser(ParserConf(self.rules, None, tree.data), self._match, resolve_ambiguity=True) | |||||
callbacks = {rule: rule.alias for rule in self.rules} # TODO pass callbacks through dict, instead of alias? | |||||
parser = earley.Parser(ParserConf(self.rules, callbacks, tree.data), self._match, resolve_ambiguity=True) | |||||
unreduced_tree = parser.parse(tree.children) # find a full derivation | unreduced_tree = parser.parse(tree.children) # find a full derivation | ||||
assert unreduced_tree.data == tree.data | assert unreduced_tree.data == tree.data | ||||
res = self.write_tokens.transform(unreduced_tree) | res = self.write_tokens.transform(unreduced_tree) | ||||
@@ -186,8 +186,7 @@ class ParserAtoms: | |||||
print('parse_table.end_state = %s' % self.parse_table.end_state) | print('parse_table.end_state = %s' % self.parse_table.end_state) | ||||
print('class Lark_StandAlone:') | print('class Lark_StandAlone:') | ||||
print(' def __init__(self, transformer=None, postlex=None):') | print(' def __init__(self, transformer=None, postlex=None):') | ||||
print(' callback = parse_tree_builder.create_callback(transformer=transformer)') | |||||
print(' callbacks = {rule: getattr(callback, rule.alias or rule.origin, None) for rule in RULES.values()}') | |||||
print(' callbacks = parse_tree_builder.create_callback(transformer=transformer)') | |||||
print(' self.parser = _Parser(parse_table, callbacks)') | print(' self.parser = _Parser(parse_table, callbacks)') | ||||
print(' self.postlex = postlex') | print(' self.postlex = postlex') | ||||
print(' def parse(self, stream):') | print(' def parse(self, stream):') | ||||
@@ -199,14 +198,13 @@ class ParserAtoms: | |||||
class TreeBuilderAtoms: | class TreeBuilderAtoms: | ||||
def __init__(self, lark): | def __init__(self, lark): | ||||
self.rules = lark.rules | self.rules = lark.rules | ||||
self.ptb = lark._parse_tree_builder | |||||
def print_python(self): | def print_python(self): | ||||
# print('class InlineTransformer: pass') | # print('class InlineTransformer: pass') | ||||
print('RULES = {') | print('RULES = {') | ||||
for i, r in enumerate(self.rules): | for i, r in enumerate(self.rules): | ||||
rule_ids[r] = i | rule_ids[r] = i | ||||
print(' %d: Rule(%r, [%s], alias=%r, options=%r),' % (i, r.origin, ', '.join(s.fullrepr for s in r.expansion), self.ptb.user_aliases[r], r.options )) | |||||
print(' %d: Rule(%r, [%s], alias=%r, options=%r),' % (i, r.origin, ', '.join(s.fullrepr for s in r.expansion), r.alias, r.options )) | |||||
print('}') | print('}') | ||||
print('parse_tree_builder = ParseTreeBuilder(RULES.values(), Tree)') | print('parse_tree_builder = ParseTreeBuilder(RULES.values(), Tree)') | ||||