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")
|