| @@ -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 | |||
| @@ -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) | |||
| @@ -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 | |||
| ###} | |||
| @@ -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): | |||
| @@ -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.""" | |||
| @@ -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 | |||
| @@ -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 | |||
| @@ -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 | |||
| @@ -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) | |||
| @@ -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)') | |||