File: generator2.py

package info (click to toggle)
python-pegen 0.3.0-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 10,980 kB
  • sloc: python: 15,064; makefile: 89
file content (70 lines) | stat: -rw-r--r-- 2,200 bytes parent folder | download
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
"""Simple code generator."""

from contextlib import contextmanager

from story3.grammar import Rule

HEADER = """\
# This is @generated code; do not edit!

from token import NAME, NUMBER, STRING, NEWLINE, ENDMARKER

from story3.memo import memoize
from story3.node import Node
from story3.parser import Parser
"""


class Generator:

    def __init__(self, stream=None):
        self.stream = stream  # If None, write to sys.stdout.
        self.indentation = ""

    def __call__(self, *args):
        # Note: print(..., file=None) prints to sys.stdout.
        print(end=self.indentation, file=self.stream)
        print(*args, file=self.stream)

    @contextmanager
    def indent(self):
        save = self.indentation
        try:
            self.indentation += "    "
            yield
        finally:
            self.indentation = save
        

def generate(rules, stream=None):
    gen = Generator(stream)
    gen(HEADER)
    gen(f"class ToyParser(Parser):")
    for rule in rules:
        gen()
        with gen.indent():
            gen(f"@memoize")
            gen(f"def {rule.name}(self):")
            with gen.indent():
                gen(f"pos = self.mark()")
                for alt in rule.alts:
                    items = []
                    gen(f"if (True")
                    with gen.indent():
                        for item in alt:
                            if item[0] in ('"', "'"):
                                gen(f"and self.expect({item})")
                            else:
                                var = item.lower()
                                if var in items:
                                    var += str(len(items))
                                items.append(var)
                                if item.isupper():
                                    gen(f"and ({var} := self.expect({item}))")
                                else:
                                    gen(f"and ({var} := self.{item}())")
                    gen(f"):")
                    with gen.indent():
                        gen(f"return Node({rule.name!r}, [{', '.join(items)}])")
                    gen(f"self.reset(pos)")
                gen(f"return None")