This repo contains code to mirror other repos. It also contains the code that is getting mirrored.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

65 lines
2.1 KiB

  1. """
  2. Module of utilities for transforming a lark.Tree into a custom Abstract Syntax Tree
  3. """
  4. import inspect, re
  5. from lark import Transformer, v_args
  6. class Ast(object):
  7. """Abstract class
  8. Subclasses will be collected by `create_transformer()`
  9. """
  10. pass
  11. class AsList(object):
  12. """Abstract class
  13. Subclasses will be instanciated with the parse results as a single list, instead of as arguments.
  14. """
  15. class WithMeta(object):
  16. pass
  17. def camel_to_snake(name):
  18. return re.sub(r'(?<!^)(?=[A-Z])', '_', name).lower()
  19. def _call(func, _data, children, _meta):
  20. return func(*children)
  21. def _call_with_meta(func, _data, children, meta):
  22. return func(meta, children)
  23. def _call_with_meta_inline(func, _data, children, meta):
  24. return func(meta, *children)
  25. inline = v_args(wrapper=_call)
  26. with_meta = v_args(wrapper=_call_with_meta)
  27. with_meta_inline = v_args(wrapper=_call_with_meta_inline)
  28. def create_transformer(ast_module, transformer=None):
  29. """Collects `Ast` subclasses from the given module, and creates a Lark transformer that builds the AST.
  30. For each class, we create a corresponding rule in the transformer, with a matching name.
  31. CamelCase names will be converted into snake_case. Example: "CodeBlock" -> "code_block".
  32. Classes starting with an underscore (`_`) will be skipped.
  33. Parameters:
  34. ast_module: A Python module containing all the subclasses of ``ast_utils.Ast``
  35. transformer (Optional[Transformer]): An initial transformer. Its attributes may be overwritten.
  36. """
  37. t = transformer or Transformer()
  38. for name, obj in inspect.getmembers(ast_module):
  39. if not name.startswith('_') and inspect.isclass(obj):
  40. if issubclass(obj, Ast):
  41. if not issubclass(obj, AsList):
  42. obj = with_meta_inline(obj).__get__(t)
  43. else:
  44. obj = inline(obj).__get__(t)
  45. elif issubclass(obj, WithMeta):
  46. obj = with_meta(obj).__get__(t)
  47. setattr(t, camel_to_snake(name), obj)
  48. return t