Browse Source

Write tests for TreeForestTransformer

tags/gm/2021-09-23T00Z/github.com--lark-parser-lark/0.10.0
Chanic Panic 5 years ago
parent
commit
b89ee6b2fc
1 changed files with 247 additions and 0 deletions
  1. +247
    -0
      tests/test_tree_forest_transformer.py

+ 247
- 0
tests/test_tree_forest_transformer.py View File

@@ -0,0 +1,247 @@
from __future__ import absolute_import

import unittest

from lark import Lark
from lark.lexer import Token
from lark.tree import Tree
from lark.visitors import Visitor, Transformer, Discard
from lark.parsers.earley_forest import TreeForestTransformer, handles_ambiguity

class TestTreeForestTransformer(unittest.TestCase):

grammar = """
start: ab bc cd
!ab: "A" "B"?
!bc: "B"? "C"?
!cd: "C"? "D"
"""

parser = Lark(grammar, parser='earley', ambiguity='forest')
forest = parser.parse("ABCD")

def test_identity_resolve_ambiguity(self):
l = Lark(self.grammar, parser='earley', ambiguity='resolve')
tree1 = l.parse("ABCD")
tree2 = TreeForestTransformer(resolve_ambiguity=True).transform(self.forest)
self.assertEqual(tree1, tree2)

def test_identity_explicit_ambiguity(self):
l = Lark(self.grammar, parser='earley', ambiguity='explicit')
tree1 = l.parse("ABCD")
tree2 = TreeForestTransformer(resolve_ambiguity=False).transform(self.forest)
self.assertEqual(tree1, tree2)

def test_tree_class(self):

class CustomTree(Tree):
pass

class TreeChecker(Visitor):
def __default__(self, tree):
assert isinstance(tree, CustomTree)

tree = TreeForestTransformer(resolve_ambiguity=False, tree_class=CustomTree).transform(self.forest)
TreeChecker().visit(tree)

def test_token_calls(self):

visited_A = False
visited_B = False
visited_C = False
visited_D = False

class CustomTransformer(TreeForestTransformer):
def A(self, node):
assert node.type == 'A'
nonlocal visited_A
visited_A = True
def B(self, node):
assert node.type == 'B'
nonlocal visited_B
visited_B = True
def C(self, node):
assert node.type == 'C'
nonlocal visited_C
visited_C = True
def D(self, node):
assert node.type == 'D'
nonlocal visited_D
visited_D = True

tree = CustomTransformer(resolve_ambiguity=False).transform(self.forest)
self.assertTrue(visited_A)
self.assertTrue(visited_B)
self.assertTrue(visited_C)
self.assertTrue(visited_D)

def test_default_token(self):

token_count = 0

class CustomTransformer(TreeForestTransformer):
def __default_token__(self, node):
nonlocal token_count
token_count += 1
assert isinstance(node, Token)

tree = CustomTransformer(resolve_ambiguity=True).transform(self.forest)
self.assertEqual(token_count, 4)

def test_rule_calls(self):

visited_start = False
visited_ab = False
visited_bc = False
visited_cd = False

class CustomTransformer(TreeForestTransformer):
def start(self, data):
nonlocal visited_start
visited_start = True
def ab(self, data):
nonlocal visited_ab
visited_ab = True
def bc(self, data):
nonlocal visited_bc
visited_bc = True
def cd(self, data):
nonlocal visited_cd
visited_cd = True

tree = CustomTransformer(resolve_ambiguity=False).transform(self.forest)
self.assertTrue(visited_start)
self.assertTrue(visited_ab)
self.assertTrue(visited_bc)
self.assertTrue(visited_cd)

def test_default_rule(self):

rule_count = 0

class CustomTransformer(TreeForestTransformer):
def __default__(self, name, data):
nonlocal rule_count
rule_count += 1

tree = CustomTransformer(resolve_ambiguity=True).transform(self.forest)
self.assertEqual(rule_count, 4)

def test_default_ambig(self):

ambig_count = 0

class CustomTransformer(TreeForestTransformer):
def __default_ambig__(self, name, data):
nonlocal ambig_count
if len(data) > 1:
ambig_count += 1

tree = CustomTransformer(resolve_ambiguity=False).transform(self.forest)
self.assertEqual(ambig_count, 1)

def test_handles_ambiguity(self):

class CustomTransformer(TreeForestTransformer):
@handles_ambiguity
def start(self, data):
assert isinstance(data, list)
assert len(data) == 4
for tree in data:
assert tree.data == 'start'
return 'handled'

@handles_ambiguity
def ab(self, data):
assert isinstance(data, list)
assert len(data) == 1
assert data[0].data == 'ab'

tree = CustomTransformer(resolve_ambiguity=False).transform(self.forest)
self.assertEqual(tree, 'handled')

def test_discard(self):

class CustomTransformer(TreeForestTransformer):
def bc(self, data):
raise Discard

def D(self, node):
raise Discard

class TreeChecker(Transformer):
def bc(self, children):
assert False

def D(self, token):
assert False

tree = CustomTransformer(resolve_ambiguity=False).transform(self.forest)
TreeChecker(visit_tokens=True).transform(tree)

def test_aliases(self):

visited_ambiguous = False
visited_full = False

class CustomTransformer(TreeForestTransformer):
@handles_ambiguity
def start(self, data):
for tree in data:
assert tree.data == 'ambiguous' or tree.data == 'full'

def ambiguous(self, data):
nonlocal visited_ambiguous
visited_ambiguous = True
assert len(data) == 3
assert data[0].data == 'ab'
assert data[1].data == 'bc'
assert data[2].data == 'cd'
return self.tree_class('ambiguous', data)

def full(self, data):
nonlocal visited_full
visited_full = True
assert len(data) == 1
assert data[0].data == 'abcd'
return self.tree_class('full', data)

grammar = """
start: ab bc cd -> ambiguous
| abcd -> full
!ab: "A" "B"?
!bc: "B"? "C"?
!cd: "C"? "D"
!abcd: "ABCD"
"""

l = Lark(grammar, parser='earley', ambiguity='forest')
forest = l.parse('ABCD')
tree = CustomTransformer(resolve_ambiguity=False).transform(forest)
self.assertTrue(visited_ambiguous)
self.assertTrue(visited_full)

def test_transformation(self):

class CustomTransformer(TreeForestTransformer):
def __default__(self, name, data):
result = []
for item in data:
if isinstance(item, list):
result += item
else:
result.append(item)
return result

def __default_token__(self, node):
return node.lower()

def __default_ambig__(self, name, data):
return data[0]

result = CustomTransformer(resolve_ambiguity=False).transform(self.forest)
expected = ['a', 'b', 'c', 'd']
self.assertEqual(result, expected)

if __name__ == '__main__':
unittest.main()

Loading…
Cancel
Save