Browse Source

ast_utils: Refactor and improve interface

gm/2021-09-23T00Z/github.com--lark-parser-lark/v0.12.0
Erez Sh 3 years ago
parent
commit
9638ad8edb
2 changed files with 11 additions and 21 deletions
  1. +2
    -1
      examples/advanced/create_ast.py
  2. +9
    -20
      lark/ast_utils.py

+ 2
- 1
examples/advanced/create_ast.py View File

@@ -31,7 +31,8 @@ class _Statement(_Ast):
pass

@dataclass
class Value(_Ast):
class Value(_Ast, ast_utils.WithMeta):
meta: object
value: object

@dataclass


+ 9
- 20
lark/ast_utils.py View File

@@ -20,23 +20,16 @@ class AsList(object):
"""

class WithMeta(object):
"""Abstract class

Subclasses will be instanciated the Meta instance of the tree. (see ``v_args`` for more detail)
"""
pass

def camel_to_snake(name):
return re.sub(r'(?<!^)(?=[A-Z])', '_', name).lower()

def _call(func, _data, children, _meta):
return func(*children)
def _call_with_meta(func, _data, children, meta):
return func(meta, children)
def _call_with_meta_inline(func, _data, children, meta):
return func(meta, *children)

inline = v_args(wrapper=_call)
with_meta = v_args(wrapper=_call_with_meta)
with_meta_inline = v_args(wrapper=_call_with_meta_inline)

def create_transformer(ast_module, transformer=None):
def create_transformer(ast_module, transformer=None, decorator_factory=v_args):
"""Collects `Ast` subclasses from the given module, and creates a Lark transformer that builds the AST.

For each class, we create a corresponding rule in the transformer, with a matching name.
@@ -47,20 +40,16 @@ def create_transformer(ast_module, transformer=None):
Parameters:
ast_module: A Python module containing all the subclasses of ``ast_utils.Ast``
transformer (Optional[Transformer]): An initial transformer. Its attributes may be overwritten.
decorator_factory (Callable): An optional callable accepting two booleans, inline, and meta,
and returning a decorator for the methods of ``transformer``. (default: ``v_args``).
"""
t = transformer or Transformer()

for name, obj in inspect.getmembers(ast_module):
if not name.startswith('_') and inspect.isclass(obj):
if issubclass(obj, Ast):
if not issubclass(obj, AsList):
if issubclass(obj, WithMeta):
obj = with_meta_inline(obj).__get__(t)
else:
obj = inline(obj).__get__(t)
elif issubclass(obj, WithMeta):
obj = with_meta(obj).__get__(t)

wrapper = decorator_factory(inline=not issubclass(obj, AsList), meta=issubclass(obj, WithMeta))
obj = wrapper(obj).__get__(t)
setattr(t, camel_to_snake(name), obj)

return t

Loading…
Cancel
Save