File: semantics_test.py

package info (click to toggle)
python-tatsu 5.16.0%2Bds-1
  • links: PTS, VCS
  • area: main
  • in suites: forky
  • size: 1,196 kB
  • sloc: python: 10,037; makefile: 46
file content (118 lines) | stat: -rw-r--r-- 3,195 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
import unittest

from tatsu import synth
from tatsu.model import Node
from tatsu.semantics import ModelBuilderSemantics
from tatsu.tool import compile


class MyNode:
    def __init__(self, ast):
        pass


class SemanticsTests(unittest.TestCase):
    def test_builder_semantics(self):
        grammar = r"""
            start::sum = {number}+ $ ;
            number::int = /\d+/ ;
        """
        text = '5 4 3 2 1'

        semantics = ModelBuilderSemantics()
        model = compile(grammar, 'test')
        ast = model.parse(text, semantics=semantics)
        self.assertEqual(15, ast)

        import functools

        dotted = functools.partial(str.join, '.')
        dotted.__name__ = 'dotted'  # type: ignore

        grammar = r"""
            start::dotted = {number}+ $ ;
            number = /\d+/ ;
        """

        semantics = ModelBuilderSemantics(types=[dotted])
        model = compile(grammar, 'test')
        ast = model.parse(text, semantics=semantics)
        self.assertEqual('5.4.3.2.1', ast)

    def test_builder_subclassing(self):
        registry = getattr(synth, '__REGISTRY')

        grammar = """
            @@grammar :: Test
            start::A::B::C = $ ;
        """

        model = compile(grammar, asmodel=True)
        model.parse('')

        print(f'{registry=}')
        A = registry['A']
        B = registry['B']
        C = registry['C']

        self.assertTrue(
            issubclass(A, B)
            and issubclass(A, synth._Synthetic)
            and issubclass(A, Node),
        )
        self.assertTrue(
            issubclass(B, C)
            and issubclass(B, synth._Synthetic)
            and issubclass(A, Node),
        )
        self.assertTrue(
            issubclass(C, synth._Synthetic) and issubclass(C, Node),
        )

    def test_builder_basetype_codegen(self):
        grammar = """
            @@grammar :: Test
            start::A::B::C = a:() b:() $ ;
            second::D::A = ();
            third = ();
        """

        from tatsu.tool import to_python_model

        src = to_python_model(grammar, base_type=MyNode)
        print(src)

        globals = {}
        exec(src, globals)  # pylint: disable=W0122
        semantics = globals['TestModelBuilderSemantics']()

        A = globals['A']
        B = globals['B']
        C = globals['C']
        D = globals['D']

        model = compile(grammar, semantics=semantics)
        ast = model.parse('', semantics=semantics)

        self.assertIsInstance(ast, MyNode)
        self.assertIsInstance(ast, (A, B, C))
        self.assertTrue(hasattr(ast, 'a'))
        self.assertTrue(hasattr(ast, 'b'))

        self.assertTrue(issubclass(D, A | B | C))

    def test_optional_attributes(self):
        grammar = r"""
            foo::Foo = left:identifier [ ':' right:identifier ] $ ;
            identifier = /\w+/ ;
        """

        grammar = compile(grammar)

        a = grammar.parse('foo : bar', semantics=ModelBuilderSemantics())
        assert a.left == 'foo'
        assert a.right == 'bar'

        b = grammar.parse('foo', semantics=ModelBuilderSemantics())
        self.assertEqual(b.left, 'foo')
        self.assertIsNone(b.right)