-
Notifications
You must be signed in to change notification settings - Fork 12
/
driver.py
executable file
·118 lines (98 loc) · 4.17 KB
/
driver.py
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
#!/usr/bin/env python3
import re
from collections import namedtuple
from itertools import zip_longest, groupby
from pathlib import Path
from alectryon import cli, transforms
from alectryon.latex import ASSETS
def pair(*iterable):
iters = [iter(iterable)] * 2
return zip_longest(*iters, fillvalue=None)
Snippet = namedtuple("Snippet", "name io_annots s")
SNIPPET_DELIM_RE = re.compile(r"""
[(][*]\s*
(?P<kind>begin|end)\s+ snippet\s+ (?P<name>[^ ]+)
(?:[:][:]\s+ (?P<io_flags>.*?))?
\s*[*][)]
""", re.VERBOSE)
SNIPPET_IO_FLAGS_RE = re.compile(r"""
(?:\n\s*)? # As if flags were at end of last non-empty line
[(][*][|]\s*
(?:..\s+ coq::\s+ (.*?))?
\s*[|]?[*][)]
""", re.VERBOSE)
class NoSnippets(Exception):
pass
def check_snippet_boundaries(before, after):
assert before
if not after:
MSG = "Missing final ``(* end snippet {} *)`` delimiter"
raise ValueError(MSG.format(before.group("before_name")))
if before.group("kind") != "begin":
raise ValueError("Unexpected delimiter ``{}``".format(before.group()))
if after.group("kind") != "end":
raise ValueError("Unexpected delimiter ``{}``".format(before.group()))
if before.group("name") != after.group("name"):
MSG = "Mismatched delimiters: (* begin snippet {} *) and (* end snippet {} *)"
raise ValueError(MSG.format(before.group("name"), after.group("name")))
def split_snippet(name, io_flags, contents):
for substr, subsnippet in pair(io_flags, *SNIPPET_IO_FLAGS_RE.split(contents)):
io_annots = transforms.read_all_io_flags(substr or "")
yield Snippet(name, io_annots, subsnippet)
def parse_coq_snippets(coq, ctx):
end, chunks = 0, []
for before, after in pair(*SNIPPET_DELIM_RE.finditer(coq)):
check_snippet_boundaries(before, after)
if before.start() > end:
chunks.append(coq[end:before.start()])
name, io_flags = before.group("name", "io_flags")
chunks.extend(split_snippet(name, io_flags, coq[before.end():after.start()]))
end = after.end()
if not chunks:
raise NoSnippets()
if end < len(coq):
chunks.append(coq[end:])
ctx["chunks"] = chunks
return [(c.s if isinstance(c, Snippet) else c) for c in chunks]
def _prepare_snippets(annotated, chunks):
for chunk, frs in zip(chunks, annotated):
if isinstance(chunk, Snippet):
frs = transforms.inherit_io_annots(frs, chunk.io_annots)
yield chunk, list(frs)
def prepare_snippets(annotated, chunks, ctx):
ctx["snippets"], annotated = zip(*_prepare_snippets(annotated, chunks))
return annotated
def drop_hidden(annotated, snippets):
for snippet, frs in zip(snippets, annotated):
yield [] if transforms.all_hidden(frs, snippet.io_annots) else frs
def _group_subsnippets(annotated, snippets):
for name, group in groupby(zip(snippets, annotated), lambda p: p[0].name):
frs = transforms.coalesce_text(fr for _, frs in group for fr in frs)
yield name, list(frs)
def group_subsnippets(annotated, snippets, ctx):
ctx["names"], annotated = zip(*_group_subsnippets(annotated, snippets))
return annotated
def trim_annotated(annotated):
for frs in annotated:
yield transforms.strip_text(frs)
def write_snippets(latex, names, fpath, output_directory):
for name, ltx in zip(names, latex):
target = (Path(output_directory) / name).with_suffix(".tex")
print(">> {} → {}".format(fpath, target))
target.write_text(ltx.render())
def record_assets(v, assets):
cli._record_assets(assets, ASSETS.PATH, ASSETS.ALECTRYON_STY + ASSETS.PYGMENTS_STY)
return v
cli.PIPELINES['coq']['snippets-hydras'] = (
cli.read_plain, parse_coq_snippets, cli.annotate_chunks, prepare_snippets,
# Transforms applied twice: once to prepare comments for drop_hidden, once
# to add comments and newlines to sentences after grouping subsnippets.
cli.apply_transforms, drop_hidden, group_subsnippets,
cli.apply_transforms, trim_annotated, cli.gen_latex_snippets, write_snippets
)
cli.PIPELINES['coq']['assets'] = (record_assets, cli.copy_assets)
if __name__ == '__main__':
try:
cli.main()
except NoSnippets:
pass