Browse Source

Refactor - callbacks are now {rule: callback}, instead of a Callback object referenced by Rule.alias

tags/gm/2021-09-23T00Z/github.com--lark-parser-lark/0.7.1
Erez Shinan 5 years ago
parent
commit
bd75bf2dff
10 changed files with 22 additions and 48 deletions
  1. +2
    -2
      lark/common.py
  2. +3
    -9
      lark/lark.py
  3. +5
    -16
      lark/parse_tree_builder.py
  4. +2
    -9
      lark/parser_frontends.py
  5. +2
    -2
      lark/parsers/cyk.py
  6. +1
    -2
      lark/parsers/earley.py
  7. +2
    -1
      lark/parsers/earley_forest.py
  8. +1
    -2
      lark/parsers/lalr_parser.py
  9. +2
    -1
      lark/reconstruct.py
  10. +2
    -4
      lark/tools/standalone.py

+ 2
- 2
lark/common.py View File

@@ -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





+ 3
- 9
lark/lark.py View File

@@ -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)




+ 5
- 16
lark/parse_tree_builder.py View File

@@ -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


###} ###}

+ 2
- 9
lark/parser_frontends.py View File

@@ -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):


+ 2
- 2
lark/parsers/cyk.py View File

@@ -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."""


+ 1
- 2
lark/parsers/earley.py View File

@@ -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


+ 2
- 1
lark/parsers/earley_forest.py View File

@@ -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




+ 1
- 2
lark/parsers/lalr_parser.py View File

@@ -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


+ 2
- 1
lark/reconstruct.py View File

@@ -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)


+ 2
- 4
lark/tools/standalone.py View File

@@ -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)')




Loading…
Cancel
Save