@@ -49,19 +49,21 @@ class NonTerminal(Symbol): | |||
class RuleOptions(Serialize): | |||
__serialize_fields__ = 'keep_all_tokens', 'expand1', 'priority', 'empty_indices' | |||
__serialize_fields__ = 'keep_all_tokens', 'expand1', 'priority', 'template_source', 'empty_indices' | |||
def __init__(self, keep_all_tokens=False, expand1=False, priority=None, empty_indices=()): | |||
def __init__(self, keep_all_tokens=False, expand1=False, priority=None, template_source=None, empty_indices=()): | |||
self.keep_all_tokens = keep_all_tokens | |||
self.expand1 = expand1 | |||
self.priority = priority | |||
self.template_source = template_source | |||
self.empty_indices = empty_indices | |||
def __repr__(self): | |||
return 'RuleOptions(%r, %r, %r)' % ( | |||
return 'RuleOptions(%r, %r, %r, %r)' % ( | |||
self.keep_all_tokens, | |||
self.expand1, | |||
self.priority, | |||
self.template_source | |||
) | |||
@@ -383,17 +383,6 @@ class ApplyTemplates(Transformer_InPlace): | |||
result_tree = deepcopy(tree) | |||
self.replacer.names = dict(zip(params, args)) | |||
self.replacer.transform(result_tree) | |||
if name[0] != '_': | |||
if result_tree.data == 'expansions': | |||
t = result_tree | |||
while len(t.children) == 2: | |||
if t.children[-1].data != 'alias': | |||
t.children[-1] = ST('alias', [t.children[-1], name]) | |||
t = t.children[0] | |||
if t.children[-1].data != 'alias': | |||
t.children[-1] = ST('alias', [t.children[-1], name]) | |||
elif result_tree.data != 'alias': | |||
result_tree = ST('alias', [result_tree, name]) | |||
self.rule_defs.append((result_name, [], result_tree, deepcopy(options))) | |||
return NonTerminal(result_name) | |||
@@ -736,7 +725,8 @@ def options_from_rule(name, params, *x): | |||
expand1 = name.startswith('?') | |||
name = name.lstrip('?') | |||
return name, params, expansions, RuleOptions(keep_all_tokens, expand1, priority=priority) | |||
return name, params, expansions, RuleOptions(keep_all_tokens, expand1, priority=priority, | |||
template_source=(name if params else None)) | |||
def symbols_from_strcase(expansion): | |||
@@ -227,9 +227,10 @@ class ParseTreeBuilder: | |||
options = rule.options | |||
keep_all_tokens = self.always_keep_all_tokens or options.keep_all_tokens | |||
expand_single_child = options.expand1 | |||
from_template = options.template_source is not None | |||
wrapper_chain = list(filter(None, [ | |||
(expand_single_child and not rule.alias) and ExpandSingleChild, | |||
(expand_single_child and not (rule.alias and not from_template)) and ExpandSingleChild, | |||
maybe_create_child_filter(rule.expansion, keep_all_tokens, self.ambiguous, options.empty_indices if self.maybe_placeholders else None), | |||
self.propagate_positions and PropagatePositions, | |||
self.ambiguous and maybe_create_ambiguous_expander(self.tree_class, rule.expansion, keep_all_tokens), | |||
@@ -243,7 +244,7 @@ class ParseTreeBuilder: | |||
for rule, wrapper_chain in self.rule_builders: | |||
user_callback_name = rule.alias or rule.origin.name | |||
user_callback_name = rule.alias or rule.options.template_source or rule.origin.name | |||
try: | |||
f = getattr(transformer, user_callback_name) | |||
# XXX InlineTransformer is deprecated! | |||
@@ -863,6 +863,38 @@ def _make_parser_test(LEXER, PARSER): | |||
x = g.parse("[1]") | |||
self.assertSequenceEqual(x.children, [Tree('sep', ['1'])]) | |||
def test_templates_alias(self): | |||
g = _Lark(r""" | |||
start: expr{"C"} | |||
expr{t}: "A" t | |||
| "B" t -> b | |||
""") | |||
x = g.parse("AC") | |||
self.assertSequenceEqual(x.children, [Tree('expr', [])]) | |||
x = g.parse("BC") | |||
self.assertSequenceEqual(x.children, [Tree('b', [])]) | |||
def test_templates_modifiers(self): | |||
g = _Lark(r""" | |||
start: expr{"B"} | |||
!expr{t}: "A" t | |||
""") | |||
x = g.parse("AB") | |||
self.assertSequenceEqual(x.children, [Tree('expr', ["A", "B"])]) | |||
g = _Lark(r""" | |||
start: _expr{"B"} | |||
!_expr{t}: "A" t | |||
""") | |||
x = g.parse("AB") | |||
self.assertSequenceEqual(x.children, ["A", "B"]) | |||
g = _Lark(r""" | |||
start: expr{b} | |||
b: "B" | |||
?expr{t}: "A" t | |||
""") | |||
x = g.parse("AB") | |||
self.assertSequenceEqual(x.children, [Tree('b',[])]) | |||
def test_g_regex_flags(self): | |||
g = _Lark(""" | |||
start: "a" /b+/ C | |||