Преглед на файлове

Added ast_utils + example

tags/gm/2021-09-23T00Z/github.com--lark-parser-lark/0.11.3
Erez Sh преди 3 години
родител
ревизия
e24e06bb13
променени са 2 файла, в които са добавени 156 реда и са изтрити 0 реда
  1. +105
    -0
      examples/advanced/create_ast.py
  2. +51
    -0
      lark/ast_utils.py

+ 105
- 0
examples/advanced/create_ast.py Целия файл

@@ -0,0 +1,105 @@
"""
This example demonstrates how to transform a parse-tree into an AST using `lark.ast_utils`.

This example only works with Python 3.
"""

import sys
from typing import List
from dataclasses import dataclass

from lark import Lark, ast_utils, Transformer, v_args

this_module = sys.modules[__name__]


#
# Define AST
#
class _Ast(ast_utils.Ast):
pass

class _Statement(_Ast):
pass

@dataclass
class Value(_Ast):
value: object

@dataclass
class Name(_Ast):
name: str

@dataclass
class CodeBlock(_Ast, ast_utils.AsList):
statements: List[_Statement]

@dataclass
class If(_Statement):
cond: Value
then: CodeBlock

@dataclass
class SetVar(_Statement):
name: str
value: Value

@dataclass
class Print(_Statement):
value: Value


class ToAst(Transformer):
def STRING(self, s):
# Remove quotation marks
return s[1:-1]

def DEC_NUMBER(self, n):
return int(n)

@v_args(inline=True)
def start(self, x):
return x

#
# Define Parser
#

parser = Lark("""
start: code_block

code_block: statement+

?statement: if | set_var | print

if: "if" value "{" code_block "}"
set_var: NAME "=" value ";"
print: "print" value ";"

value: name | STRING | DEC_NUMBER
name: NAME

%import python (NAME, STRING, DEC_NUMBER)
%import common.WS
%ignore WS
""",
parser="lalr",
)

transformer = ast_utils.create_transformer(this_module, ToAst())

def parse(text):
return transformer.transform(parser.parse(text))

#
# Test
#

if __name__ == '__main__':
print(parse("""
a = 1;
if a {
print "a is 1";
a = 2;
}
"""))

+ 51
- 0
lark/ast_utils.py Целия файл

@@ -0,0 +1,51 @@
"""
Module of utilities for transforming a lark.Tree into a custom Abstract Syntax Tree
"""

import inspect, re

from lark import Transformer, v_args

class Ast(object):
"""Abstract class

Subclasses will be collected by `create_transformer()`
"""
pass

class AsList(object):
"""Abstract class

Subclasses will be instanciated with the parse results as a single list, instead of as arguments.
"""

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

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

inline = v_args(wrapper=_call)

def create_transformer(ast_module, transformer=None):
"""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.
CamelCase names will be converted into snake_case. Example: "CodeBlock" -> "code_block".

Parameters:
ast_module - A Python module containing all the subclasses of `ast_utils.Ast`
Classes starting with an underscore (`_`) will be skipped.
transformer (Optional[Transformer]) - An initial transformer. Its attributes may be overwritten.
"""
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):
obj = inline(obj).__get__(t)

setattr(t, camel_to_snake(name), obj)

return t

Зареждане…
Отказ
Запис