diff --git a/lark/__init__.py b/lark/__init__.py index 814fe66a2..855c65dd7 100644 --- a/lark/__init__.py +++ b/lark/__init__.py @@ -1,6 +1,6 @@ from .utils import logger from .tree import Tree -from .visitors import Transformer, Visitor, v_args, Discard, Transformer_NonRecursive +from .visitors import Transformer, Visitor, v_args, Discard, Inline, Transformer_NonRecursive from .visitors import InlineTransformer, inline_args # XXX Deprecated from .exceptions import (ParseError, LexError, GrammarError, UnexpectedToken, UnexpectedInput, UnexpectedCharacters, LarkError) diff --git a/lark/visitors.py b/lark/visitors.py index 7e3bae4bf..62aeb2edd 100644 --- a/lark/visitors.py +++ b/lark/visitors.py @@ -15,9 +15,16 @@ class Discard(Exception): """ pass -# Transformers +class Inline(object): + """When returning an Inline instance in a transformer callback, + the node is inlined, and replaced by its children. + """ + def __init__(self, *items): + self.items = items +# Transformers + class _Decoratable: "Provides support for decorating methods with @v_args" @@ -113,11 +120,16 @@ def _transform_children(self, children): for c in children: try: if isinstance(c, Tree): - yield self._transform_tree(c) + res = self._transform_tree(c) elif self.__visit_tokens__ and isinstance(c, Token): - yield self._call_userfunc_token(c) + res = self._call_userfunc_token(c) + else: + res = c + if type(res) is Inline: + for i in res.items: + yield i else: - yield c + yield res except Discard: pass diff --git a/tests/test_trees.py b/tests/test_trees.py index 905ad5ab9..e91e10d16 100644 --- a/tests/test_trees.py +++ b/tests/test_trees.py @@ -8,7 +8,7 @@ from lark.tree import Tree from lark.lexer import Token -from lark.visitors import Visitor, Visitor_Recursive, Transformer, Interpreter, visit_children_decor, v_args, Discard +from lark.visitors import Visitor, Visitor_Recursive, Transformer, Interpreter, visit_children_decor, v_args, Discard, Inline class TestTrees(TestCase): @@ -233,6 +233,24 @@ def b(cls, args): x = MyTransformer().transform( t ) self.assertEqual(x, t2) + def test_inline(self): + class MyTransformer(Transformer): + def b(self, children): + return 'b' + + def a(self, children): + return Inline('c', 'd') + + t = Tree('root', [ + Tree('b', []), + Tree('a', []), + Tree('b', []), + ]) + t2 = Tree('root', ['b', 'c', 'd', 'b']) + + x = MyTransformer().transform( t ) + self.assertEqual(x, t2) + if __name__ == '__main__': unittest.main()