File: stateful_test.py

package info (click to toggle)
python-tatsu 5.16.0%2Bds-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 1,196 kB
  • sloc: python: 10,037; makefile: 46
file content (113 lines) | stat: -rw-r--r-- 3,666 bytes parent folder | download | duplicates (4)
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
import unittest

from tatsu.exceptions import FailedSemantics
from tatsu.grammars import ModelContext
from tatsu.tool import compile


class StatefulTests(unittest.TestCase):
    def test_stateful(self):
        # Parser for mediawiki-style unordered lists.
        grammar = r"""
            document = @:ul [ nl ] $ ;
            ul = "*" ul_start el+:li { nl el:li } * ul_end ;
            li = ul | li_text ;
            (* Quirk: If a text line is followed by a sublist, the sublist does not get its own li. *)
            li_text = text:text [ ul:li_followed_by_ul ] ;
            li_followed_by_ul = nl @:ul ;
            text = ?/.*/? ;
            nl = ?/\n/? ul_marker ;
            (* The following rules are placeholders for state transitions. *)
            ul_start = () ;
            ul_end = () ;
            (* The following rules are placeholders for state validations and grammar rules. *)
            ul_marker = () ;
            """

        class StatefulSemantics:
            def __init__(self, parser):
                self._context = parser

            def ul_start(self, ast):
                ctx = self._context
                ctx.substate = 1 if ctx.substate is None else ctx.substate + 1
                return ast

            def ul_end(self, ast):
                ctx = self._context
                ctx.substate = (
                    None
                    if ctx.substate is None or ctx.substate <= 1
                    else ctx.substate - 1
                )
                return ast

            def ul_marker(self, ast):
                ctx = self._context
                if ctx.substate is not None and not ctx.tokenizer.match(
                    '*' * ctx.substate,
                ):
                    raise FailedSemantics('not at correct level')
                return ast

            def ul(self, ast):
                return '<ul>' + ''.join(ast.el) + '</ul>'

            def li(self, ast):
                return '<li>' + ast + '</li>'

            def li_text(self, ast):
                return ast.text if ast.ul is None else ast.text + ast.ul

        model = compile(grammar, 'test')
        context = ModelContext(model.rules, whitespace='', nameguard=False)

        ast = model.parse(
            '*abc',
            start='document',
            ctx=context,
            semantics=StatefulSemantics(context),
            whitespace='',
            nameguard=False,
        )
        self.assertEqual(ast, '<ul><li>abc</li></ul>')

        ast = model.parse(
            '*abc\n',
            start='document',
            ctx=context,
            semantics=StatefulSemantics(context),
            whitespace='',
            nameguard=False,
        )
        self.assertEqual('<ul><li>abc</li></ul>', ast)

        ast = model.parse(
            '*abc\n*def\n',
            start='document',
            ctx=context,
            semantics=StatefulSemantics(context),
            whitespace='',
            nameguard=False,
        )
        self.assertEqual('<ul><li>abc</li><li>def</li></ul>', ast)

        ast = model.parse(
            '**abc',
            start='document',
            ctx=context,
            semantics=StatefulSemantics(context),
            whitespace='',
            nameguard=False,
        )
        self.assertEqual('<ul><li><ul><li>abc</li></ul></li></ul>', ast)

        ast = model.parse(
            '*abc\n**def\n',
            start='document',
            ctx=context,
            semantics=StatefulSemantics(context),
            whitespace='',
            nameguard=False,
        )
        self.assertEqual('<ul><li>abc<ul><li>def</li></ul></li></ul>', ast)