Browse Source

Refactored transformers, better code

tags/gm/2021-09-23T00Z/github.com--lark-parser-lark/0.6.0
Erez Shinan 6 years ago
parent
commit
9daacb9082
6 changed files with 98 additions and 73 deletions
  1. +0
    -1
      lark/__init__.py
  2. +17
    -14
      lark/load_grammar.py
  3. +74
    -39
      lark/transformers.py
  4. +0
    -2
      lark/tree.py
  5. +5
    -15
      lark/utils.py
  6. +2
    -2
      tests/test_parser.py

+ 0
- 1
lark/__init__.py View File

@@ -3,6 +3,5 @@ from .transformers import Transformer
from .common import ParseError, GrammarError, UnexpectedToken
from .lexer import UnexpectedInput, LexError
from .lark import Lark
from .utils import inline_args

__version__ = "0.5.6"

+ 17
- 14
lark/load_grammar.py View File

@@ -16,7 +16,7 @@ from .grammar import RuleOptions, Rule, Terminal, NonTerminal, Symbol
from .utils import classify, suppress

from .tree import Tree, SlottedTree as ST
from .transformers import Transformer, ChildrenTransformer, inline_args, Visitor
from .transformers import Transformer, Visitor, children_args, children_args_inline

__path__ = os.path.dirname(__file__)
IMPORT_PATHS = [os.path.join(__path__, 'grammars')]
@@ -138,8 +138,8 @@ RULES = {
}


@inline_args
class EBNF_to_BNF(ChildrenTransformer):
@children_args_inline
class EBNF_to_BNF(Transformer):
def __init__(self):
self.new_rules = []
self.rules_by_expr = {}
@@ -232,7 +232,8 @@ class SimplifyRule_Visitor(Visitor):
tree.children = list(set(tree.children))


class RuleTreeToText(ChildrenTransformer):
@children_args
class RuleTreeToText(Transformer):
def expansions(self, x):
return x
def expansion(self, symbols):
@@ -243,8 +244,8 @@ class RuleTreeToText(ChildrenTransformer):
return expansion, alias.value


@inline_args
class CanonizeTree(ChildrenTransformer):
@children_args_inline
class CanonizeTree(Transformer):
def maybe(self, expr):
return ST('expr', [expr, Token('OP', '?', -1)])

@@ -254,8 +255,8 @@ class CanonizeTree(ChildrenTransformer):
tokenmods, value = args
return tokenmods + [value]

@inline_args
class PrepareAnonTerminals(ChildrenTransformer):
@children_args_inline
class PrepareAnonTerminals(Transformer):
"Create a unique list of anonymous tokens. Attempt to give meaningful names to them when we add them"

def __init__(self, tokens):
@@ -354,8 +355,8 @@ def _literal_to_pattern(literal):
'REGEXP': PatternRE }[literal.type](s, flags)


@inline_args
class PrepareLiterals(ChildrenTransformer):
@children_args_inline
class PrepareLiterals(Transformer):
def literal(self, literal):
return ST('pattern', [_literal_to_pattern(literal)])

@@ -368,7 +369,8 @@ class PrepareLiterals(ChildrenTransformer):
return ST('pattern', [PatternRE(regexp)])


class TokenTreeToPattern(ChildrenTransformer):
@children_args
class TokenTreeToPattern(Transformer):
def pattern(self, ps):
p ,= ps
return p
@@ -407,7 +409,8 @@ class TokenTreeToPattern(ChildrenTransformer):
def value(self, v):
return v[0]

class PrepareSymbols(ChildrenTransformer):
@children_args
class PrepareSymbols(Transformer):
def value(self, v):
v ,= v
if isinstance(v, Tree):
@@ -532,8 +535,8 @@ def options_from_rule(name, *x):
def symbols_from_strcase(expansion):
return [Terminal(x, filter_out=x.startswith('_')) if is_terminal(x) else NonTerminal(x) for x in expansion]

@inline_args
class PrepareGrammar(ChildrenTransformer):
@children_args_inline
class PrepareGrammar(Transformer):
def terminal(self, name):
return name
def nonterminal(self, name):


+ 74
- 39
lark/transformers.py View File

@@ -1,7 +1,7 @@
import inspect
from functools import wraps

from . import utils
from .utils import smart_decorator
from .tree import Tree

class Discard(Exception):
@@ -13,46 +13,27 @@ class Base:
return getattr(self, tree.data, self.__default__)(tree)

def __default__(self, tree):
"Default operation on tree (for override)"
return tree

class Transformer(Base):
def _transform_children(self, children):
for c in children:
try:
yield self._transform(c) if isinstance(c, Tree) else c
yield self._transform_tree(c) if isinstance(c, Tree) else c
except Discard:
pass

def _transform(self, tree):
def _transform_tree(self, tree):
tree = Tree(tree.data, list(self._transform_children(tree.children)))
return self._call_userfunc(tree)

def transform(self, tree):
return self._transform(tree)
return self._transform_tree(tree)

def __mul__(self, other):
return TransformerChain(self, other)

class ChildrenTransformer(Transformer):
def _call_userfunc(self, tree):
# Assumes tree is already transformed
try:
f = getattr(self, tree.data)
except AttributeError:
return self.__default__(tree)
else:
return f(tree.children)

class ChildrenInlineTransformer(Transformer):
def _call_userfunc(self, tree):
# Assumes tree is already transformed
try:
f = getattr(self, tree.data)
except AttributeError:
return self.__default__(tree)
else:
return f(*tree.children)


class TransformerChain(object):
def __init__(self, *transformers):
@@ -68,14 +49,22 @@ class TransformerChain(object):


class Transformer_InPlace(Transformer):
def _transform(self, tree):
def _transform_tree(self, tree): # Cancel recursion
return self._call_userfunc(tree)

def transform(self, tree):
for subtree in tree.iter_subtrees():
subtree.children = list(self._transform_children(subtree.children))

return self._transform(tree)
return self._transform_tree(tree)


class Transformer_InPlaceRecursive(Transformer):
def _transform_tree(self, tree):
tree.children = list(self._transform_children(tree.children))
return self._call_userfunc(tree)



class Visitor(Base):
"Bottom-up visitor"
@@ -85,11 +74,6 @@ class Visitor(Base):
self._call_userfunc(subtree)
return tree

class Transformer_InPlaceRecursive(Transformer):
def _transform(self, tree):
tree.children = list(self._transform_children(tree.children))
return self._call_userfunc(tree)

class Visitor_Recursive(Base):
def visit(self, tree):
for child in tree.children:
@@ -101,7 +85,6 @@ class Visitor_Recursive(Base):
return tree


from functools import wraps
def visit_children_decor(func):
@wraps(func)
def inner(cls, tree):
@@ -126,11 +109,63 @@ class Interpreter(object):
return self.visit_children(tree)


def inline_args(obj):
if inspect.isclass(obj) and issubclass(obj, ChildrenTransformer):
class _NewTransformer(ChildrenInlineTransformer, obj):
pass
return _NewTransformer
else:
return utils.inline_args(obj)

def _children_args__func(f):
@wraps(f)
def create_decorator(_f, with_self):
if with_self:
def f(self, tree):
return _f(self, tree.children)
else:
def f(args):
return _f(tree.children)

return smart_decorator(f, create_decorator)

def _children_args__class(cls):
def _call_userfunc(self, tree):
# Assumes tree is already transformed
try:
f = getattr(self, tree.data)
except AttributeError:
return self.__default__(tree)
else:
return f(tree.children)
cls._call_userfunc = _call_userfunc
return cls


def children_args(obj):
decorator = _children_args__class if issubclass(obj, Base) else _children_args__func
return decorator(obj)



def _children_args_inline__func(f):
@wraps(f)
def create_decorator(_f, with_self):
if with_self:
def f(self, tree):
return _f(self, *tree.children)
else:
def f(args):
return _f(*tree.children)

return smart_decorator(f, create_decorator)


def _children_args_inline__class(cls):
def _call_userfunc(self, tree):
# Assumes tree is already transformed
try:
f = getattr(self, tree.data)
except AttributeError:
return self.__default__(tree)
else:
return f(*tree.children)
cls._call_userfunc = _call_userfunc
return cls

def children_args_inline(obj):
decorator = _children_args_inline__class if issubclass(obj, Base) else _children_args_inline__func
return decorator(obj)

+ 0
- 2
lark/tree.py View File

@@ -5,8 +5,6 @@ except ImportError:

from copy import deepcopy

from .utils import inline_args

class Meta:
pass



+ 5
- 15
lark/utils.py View File

@@ -50,22 +50,22 @@ except NameError: # Python 3
###{standalone

import types
import functools
from functools import wraps, partial
from contextlib import contextmanager

Str = type(u'')

def smart_decorator(f, create_decorator):
if isinstance(f, types.FunctionType):
return functools.wraps(create_decorator(f, True))
return wraps(create_decorator(f, True))

elif isinstance(f, (type, types.BuiltinFunctionType)):
return functools.wraps(create_decorator(f, False))
return wraps(create_decorator(f, False))

elif isinstance(f, types.MethodType):
return functools.wraps(create_decorator(f.__func__, True))
return wraps(create_decorator(f.__func__, True))

elif isinstance(f, functools.partial):
elif isinstance(f, partial):
# wraps does not work for partials in 2.7: https://bugs.python.org/issue3445
return create_decorator(f.__func__, True)

@@ -73,16 +73,6 @@ def smart_decorator(f, create_decorator):
return create_decorator(f.__func__.__call__, True)


def inline_args(f):
def create_decorator(_f, with_self):
if with_self:
def f(self, args):
return _f(self, *args)
else:
def f(args):
return _f(*args)

return smart_decorator(f, create_decorator)


try:


+ 2
- 2
tests/test_parser.py View File

@@ -21,8 +21,7 @@ from lark.lark import Lark
from lark.common import GrammarError, ParseError, UnexpectedToken
from lark.lexer import LexError, UnexpectedInput
from lark.tree import Tree
from lark.transformers import ChildrenTransformer as Transformer
# from lark.tree import Transformer
from lark.transformers import Transformer, children_args

__path__ = os.path.dirname(__file__)
def _read(n, *args):
@@ -94,6 +93,7 @@ class TestParsers(unittest.TestCase):
self.assertEqual( r.children[0].data, "c" )

def test_embedded_transformer(self):
@children_args
class T(Transformer):
def a(self, children):
return "<a>"


Loading…
Cancel
Save