Browse Source

Initial: Added transformers.py, and Meta to tree

tags/gm/2021-09-23T00Z/github.com--lark-parser-lark/0.6.0
Erez Shinan 7 years ago
parent
commit
f960c1b8ac
6 changed files with 133 additions and 15 deletions
  1. +3
    -0
      lark/lexer.py
  2. +9
    -8
      lark/load_grammar.py
  3. +15
    -6
      lark/parse_tree_builder.py
  4. +93
    -0
      lark/transformers.py
  5. +12
    -0
      lark/tree.py
  6. +1
    -1
      tests/test_parser.py

+ 3
- 0
lark/lexer.py View File

@@ -34,6 +34,8 @@ class Token(Str):
self.value = value self.value = value
self.line = line self.line = line
self.column = column self.column = column
self.end_line = None
self.end_column = None
return self return self


@classmethod @classmethod
@@ -112,6 +114,7 @@ class _Lex:
if t: if t:
t.end_line = line_ctr.line t.end_line = line_ctr.line
t.end_column = line_ctr.column t.end_column = line_ctr.column

break break
else: else:
if line_ctr.char_pos < len(stream): if line_ctr.char_pos < len(stream):


+ 9
- 8
lark/load_grammar.py View File

@@ -14,7 +14,8 @@ from .parsers.lalr_parser import UnexpectedToken
from .common import is_terminal, GrammarError, LexerConf, ParserConf, PatternStr, PatternRE, TokenDef from .common import is_terminal, GrammarError, LexerConf, ParserConf, PatternStr, PatternRE, TokenDef
from .grammar import RuleOptions, Rule from .grammar import RuleOptions, Rule


from .tree import Tree, Transformer, InlineTransformer, Visitor, SlottedTree as ST
from .tree import Tree, Visitor, SlottedTree as ST
from .transformers import Transformer_Children, Transformer_ChildrenInline


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




class EBNF_to_BNF(InlineTransformer):
class EBNF_to_BNF(Transformer_ChildrenInline):
def __init__(self): def __init__(self):
self.new_rules = [] self.new_rules = []
self.rules_by_expr = {} self.rules_by_expr = {}
@@ -226,7 +227,7 @@ class SimplifyRule_Visitor(Visitor):
tree.children = list(set(tree.children)) tree.children = list(set(tree.children))




class RuleTreeToText(Transformer):
class RuleTreeToText(Transformer_Children):
def expansions(self, x): def expansions(self, x):
return x return x
def expansion(self, symbols): def expansion(self, symbols):
@@ -237,7 +238,7 @@ class RuleTreeToText(Transformer):
return expansion, alias.value return expansion, alias.value




class CanonizeTree(InlineTransformer):
class CanonizeTree(Transformer_ChildrenInline):
def maybe(self, expr): def maybe(self, expr):
return ST('expr', [expr, Token('OP', '?', -1)]) return ST('expr', [expr, Token('OP', '?', -1)])


@@ -247,7 +248,7 @@ class CanonizeTree(InlineTransformer):
tokenmods, value = args tokenmods, value = args
return tokenmods + [value] return tokenmods + [value]


class ExtractAnonTokens(InlineTransformer):
class ExtractAnonTokens(Transformer_ChildrenInline):
"Create a unique list of anonymous tokens. Attempt to give meaningful names to them when we add them" "Create a unique list of anonymous tokens. Attempt to give meaningful names to them when we add them"


def __init__(self, tokens): def __init__(self, tokens):
@@ -351,7 +352,7 @@ def _literal_to_pattern(literal):
'REGEXP': PatternRE }[literal.type](s, flags) 'REGEXP': PatternRE }[literal.type](s, flags)




class PrepareLiterals(InlineTransformer):
class PrepareLiterals(Transformer_ChildrenInline):
def literal(self, literal): def literal(self, literal):
return ST('pattern', [_literal_to_pattern(literal)]) return ST('pattern', [_literal_to_pattern(literal)])


@@ -363,13 +364,13 @@ class PrepareLiterals(InlineTransformer):
regexp = '[%s-%s]' % (start, end) regexp = '[%s-%s]' % (start, end)
return ST('pattern', [PatternRE(regexp)]) return ST('pattern', [PatternRE(regexp)])


class SplitLiterals(InlineTransformer):
class SplitLiterals(Transformer_ChildrenInline):
def pattern(self, p): def pattern(self, p):
if isinstance(p, PatternStr) and len(p.value)>1: if isinstance(p, PatternStr) and len(p.value)>1:
return ST('expansion', [ST('pattern', [PatternStr(ch, flags=p.flags)]) for ch in p.value]) return ST('expansion', [ST('pattern', [PatternStr(ch, flags=p.flags)]) for ch in p.value])
return ST('pattern', [p]) return ST('pattern', [p])


class TokenTreeToPattern(Transformer):
class TokenTreeToPattern(Transformer_Children):
def pattern(self, ps): def pattern(self, ps):
p ,= ps p ,= ps
return p return p


+ 15
- 6
lark/parse_tree_builder.py View File

@@ -2,6 +2,7 @@ from .common import is_terminal, GrammarError
from .utils import suppress from .utils import suppress
from .lexer import Token from .lexer import Token
from .grammar import Rule from .grammar import Rule
from .tree import Tree


###{standalone ###{standalone
from functools import partial from functools import partial
@@ -38,15 +39,23 @@ class PropagatePositions:


if children: if children:
for a in children: for a in children:
with suppress(AttributeError):
res.line = a.line
res.column = a.column
if isinstance(a, Tree):
res.meta.line = a.meta.line
res.meta.column = a.meta.column
elif isinstance(a, Token):
res.meta.line = a.line
res.meta.column = a.column
break break


for a in reversed(children): for a in reversed(children):
with suppress(AttributeError):
res.end_line = a.end_line
res.end_column = a.end_column
# with suppress(AttributeError):
if isinstance(a, Tree):
res.meta.end_line = a.meta.end_line
res.meta.end_column = a.meta.end_column
elif isinstance(a, Token):
res.meta.end_line = a.end_line
res.meta.end_column = a.end_column

break break


return res return res


+ 93
- 0
lark/transformers.py View File

@@ -0,0 +1,93 @@
from functools import wraps

from .tree import Tree

class Discard(Exception):
pass


class Transformer:
def _get_userfunc(self, name):
return getattr(self, name)

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

def _transform(self, tree):
children = []
for c in tree.children:
try:
children.append(self._transform(c) if isinstance(c, Tree) else c)
except Discard:
pass

tree = Tree(tree.data, children)
return self._call_userfunc(tree)

def __default__(self, tree):
return tree

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

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

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

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


class TransformerChain(object):
def __init__(self, *transformers):
self.transformers = transformers

def transform(self, tree):
for t in self.transformers:
tree = t.transform(tree)
return tree

def __mul__(self, other):
return TransformerChain(*self.transformers + (other,))



#### XXX PSEUDOCODE TODO
# def items(obj):
# if isinstance(obj, Transformer):
# def new_get_userfunc(self, name):
# uf = self._get_userfunc(name)
# def _f(tree):
# return uf(tree.children)
# return _f
# obj._get_userfunc = new_get_userfunc
# else:
# assert callable(obj)
# # apply decorator
# def _f(tree):
# return obj(tree.children)
# return _f



+ 12
- 0
lark/tree.py View File

@@ -7,11 +7,23 @@ from copy import deepcopy


from .utils import inline_args from .utils import inline_args


class Meta:
pass

###{standalone ###{standalone
class Tree(object): class Tree(object):
__slots__ = ('data', 'children', '_meta', 'rule')

def __init__(self, data, children): def __init__(self, data, children):
self.data = data self.data = data
self.children = children self.children = children
self._meta = None

@property
def meta(self):
if self._meta is None:
self._meta = Meta()
return self._meta


def __repr__(self): def __repr__(self):
return 'Tree(%s, %s)' % (self.data, self.children) return 'Tree(%s, %s)' % (self.data, self.children)


+ 1
- 1
tests/test_parser.py View File

@@ -60,7 +60,7 @@ class TestParsers(unittest.TestCase):
""", propagate_positions=True) """, propagate_positions=True)


r = g.parse('a') r = g.parse('a')
self.assertEqual( r.children[0].line, 1 )
self.assertEqual( r.children[0].meta.line, 1 )


def test_expand1(self): def test_expand1(self):




Loading…
Cancel
Save