diff --git a/lark/common.py b/lark/common.py index 76155f3..9c18972 100644 --- a/lark/common.py +++ b/lark/common.py @@ -8,9 +8,9 @@ class LexerConf: self.callbacks = callbacks or {} class ParserConf: - def __init__(self, rules, callback, start): + def __init__(self, rules, callbacks, start): self.rules = rules - self.callback = callback + self.callbacks = callbacks self.start = start diff --git a/lark/lark.py b/lark/lark.py index 4445e6f..178141c 100644 --- a/lark/lark.py +++ b/lark/lark.py @@ -132,7 +132,7 @@ class Lark: raise NotImplementedError("Not available yet") 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.parser == 'lalr': @@ -192,8 +192,6 @@ class Lark: elif lexer: self.lexer = self._build_lexer() - if self.profiler: self.profiler.enter_section('outside_lark') - if __init__.__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._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) diff --git a/lark/parse_tree_builder.py b/lark/parse_tree_builder.py index 97189b6..ca12d5f 100644 --- a/lark/parse_tree_builder.py +++ b/lark/parse_tree_builder.py @@ -187,10 +187,6 @@ def maybe_create_ambiguous_expander(tree_class, expansion, keep_all_tokens): if to_expand: return partial(AmbiguousExpander, to_expand, tree_class) -class Callback(object): - pass - - def ptb_inline_args(func): @wraps(func) def f(children): @@ -207,8 +203,6 @@ class ParseTreeBuilder: self.rule_builders = list(self._init_builders(rules)) - self.user_aliases = {} - def _init_builders(self, rules): for rule in rules: options = rule.options @@ -226,12 +220,9 @@ class ParseTreeBuilder: def create_callback(self, transformer=None): - callback = Callback() + callbacks = {} - i = 0 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 try: @@ -243,16 +234,14 @@ class ParseTreeBuilder: except AttributeError: f = partial(self.tree_class, user_callback_name) - self.user_aliases[rule] = rule.alias - rule.alias = internal_callback_name - for w in wrapper_chain: f = w(f) - if hasattr(callback, internal_callback_name): + if rule in callbacks: raise GrammarError("Rule '%s' already exists" % (rule,)) - setattr(callback, internal_callback_name, f) - return callback + callbacks[rule] = f + + return callbacks ###} diff --git a/lark/parser_frontends.py b/lark/parser_frontends.py index af2a2fd..c351ddc 100644 --- a/lark/parser_frontends.py +++ b/lark/parser_frontends.py @@ -123,10 +123,7 @@ class CYK(WithLexer): self._analysis = GrammarAnalyzer(parser_conf) 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): tokens = list(self.lex(text)) @@ -142,11 +139,7 @@ class CYK(WithLexer): return self._apply_callback(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): diff --git a/lark/parsers/cyk.py b/lark/parsers/cyk.py index ee9ea8e..2121449 100644 --- a/lark/parsers/cyk.py +++ b/lark/parsers/cyk.py @@ -86,7 +86,7 @@ class Parser(object): def __init__(self, rules, start): 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] self.grammar = to_cnf(Grammar(rules)) self.start = NT(start) @@ -98,7 +98,7 @@ class Parser(object): return Rule( lark_rule.origin, lark_rule.expansion, 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 """Parses input, which is a list of tokens.""" diff --git a/lark/parsers/earley.py b/lark/parsers/earley.py index 64e2a1d..0518174 100644 --- a/lark/parsers/earley.py +++ b/lark/parsers/earley.py @@ -27,7 +27,7 @@ class Parser: self.FIRST = analysis.FIRST self.NULLABLE = analysis.NULLABLE - self.callbacks = {} + self.callbacks = parser_conf.callbacks self.predictions = {} ## 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 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)] ## Detect if any rules have priorities set. If the user specified priority = "none" then diff --git a/lark/parsers/earley_forest.py b/lark/parsers/earley_forest.py index 8d9c148..89522cd 100644 --- a/lark/parsers/earley_forest.py +++ b/lark/parsers/earley_forest.py @@ -271,7 +271,8 @@ class ForestToTreeVisitor(ForestVisitor): according to some priority mechanism. """ __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.callbacks = callbacks diff --git a/lark/parsers/lalr_parser.py b/lark/parsers/lalr_parser.py index 6178c99..c30a92e 100644 --- a/lark/parsers/lalr_parser.py +++ b/lark/parsers/lalr_parser.py @@ -13,8 +13,7 @@ class Parser: for r in parser_conf.rules), "LALR doesn't yet support prioritization" analysis = LALR_Analyzer(parser_conf, debug=debug) 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.parser_conf = parser_conf diff --git a/lark/reconstruct.py b/lark/reconstruct.py index 1fa6c7b..791eb85 100644 --- a/lark/reconstruct.py +++ b/lark/reconstruct.py @@ -112,7 +112,8 @@ class Reconstructor: def _reconstruct(self, tree): # 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 assert unreduced_tree.data == tree.data res = self.write_tokens.transform(unreduced_tree) diff --git a/lark/tools/standalone.py b/lark/tools/standalone.py index 99ee73c..3e6cc5d 100644 --- a/lark/tools/standalone.py +++ b/lark/tools/standalone.py @@ -186,8 +186,7 @@ class ParserAtoms: print('parse_table.end_state = %s' % self.parse_table.end_state) print('class Lark_StandAlone:') 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.postlex = postlex') print(' def parse(self, stream):') @@ -199,14 +198,13 @@ class ParserAtoms: class TreeBuilderAtoms: def __init__(self, lark): self.rules = lark.rules - self.ptb = lark._parse_tree_builder def print_python(self): # print('class InlineTransformer: pass') print('RULES = {') for i, r in enumerate(self.rules): 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('parse_tree_builder = ParseTreeBuilder(RULES.values(), Tree)')