diff --git a/lark/parse_tree_builder.py b/lark/parse_tree_builder.py index 977c371..550bc17 100644 --- a/lark/parse_tree_builder.py +++ b/lark/parse_tree_builder.py @@ -2,6 +2,7 @@ from .exceptions import GrammarError from .lexer import Token from .tree import Tree from .visitors import InlineTransformer # XXX Deprecated +from .visitors import Transformer_InPlace ###{standalone from functools import partial, wraps @@ -193,6 +194,15 @@ def ptb_inline_args(func): return func(*children) return f +def inplace_transformer(func): + @wraps(func) + def f(children): + # function name in a Transformer is a rule name. + tree = Tree(func.__name__, children) + func(tree) + return tree + return f + class ParseTreeBuilder: def __init__(self, rules, tree_class, propagate_positions=False, keep_all_tokens=False, ambiguous=False, maybe_placeholders=False): self.tree_class = tree_class @@ -231,6 +241,8 @@ class ParseTreeBuilder: # XXX InlineTransformer is deprecated! if getattr(f, 'inline', False) or isinstance(transformer, InlineTransformer): f = ptb_inline_args(f) + elif hasattr(f, 'whole_tree') or isinstance(transformer, Transformer_InPlace): + f = inplace_transformer(f) except AttributeError: f = partial(self.tree_class, user_callback_name) diff --git a/tests/test_parser.py b/tests/test_parser.py index ce8b7d6..0fddf14 100644 --- a/tests/test_parser.py +++ b/tests/test_parser.py @@ -20,7 +20,7 @@ logging.basicConfig(level=logging.INFO) from lark.lark import Lark from lark.exceptions import GrammarError, ParseError, UnexpectedToken, UnexpectedInput, UnexpectedCharacters from lark.tree import Tree -from lark.visitors import Transformer +from lark.visitors import Transformer, Transformer_InPlace, v_args from lark.grammar import Rule from lark.lexer import TerminalDef @@ -150,6 +150,31 @@ class TestParsers(unittest.TestCase): r = g.parse("xx") self.assertEqual( r.children, [""] ) + def test_embedded_transformer_inplace(self): + class T1(Transformer_InPlace): + def a(self, tree): + assert isinstance(tree, Tree) + tree.children.append("tested") + + @v_args(tree=True) + class T2(Transformer): + def a(self, tree): + assert isinstance(tree, Tree) + tree.children.append("tested") + + class T3(Transformer): + @v_args(tree=True) + def a(self, tree): + assert isinstance(tree, Tree) + tree.children.append("tested") + + for t in [T1(), T2(), T3()]: + g = Lark("""start: a + a : "x" + """, parser='lalr', transformer=t) + r = g.parse("x") + first, = r.children + self.assertEqual(first.children, ["tested"]) def test_alias(self): Lark("""start: ["a"] "b" ["c"] "e" ["f"] ["g"] ["h"] "x" -> d """)