mirror of https://github.com/lark-parser/lark.git
Implement embedded in-place transformers. See #378.
As discussed in issue #378, when an embedded transformer (that is, one passed to the Lark class using the transformer argument), is an inplace transformer (either a subclass of Transformer_InPlace, or with the @v_args(tree=True) decorator), the in-place transformer was not working correctly and in-fact Lark used it like a normal non-in-place transformer, expecting it to return the transformed value.
This commit is contained in:
parent
0f9dfdd623
commit
e5868415eb
|
@ -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)
|
||||
|
||||
|
|
|
@ -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, ["<c>"] )
|
||||
|
||||
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 """)
|
||||
|
|
Loading…
Reference in New Issue