This repository has been archived by the owner on Jul 21, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 13
/
output.py
234 lines (212 loc) · 9.01 KB
/
output.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
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
import os
import os.path
import sys
# Hardcoded list of tags allowed without -x flag.
BUILTIN_TAGS = ['add',
'atleast',
'b',
'collect',
'cost',
'count',
'dec',
'drop',
'found',
'has',
'hasnot',
'img',
'inc',
'init',
'lessthan',
'min',
'morethan',
'random',
'set',
'take',
'trade',
'xor']
NOT_BUILTIN_TAG_MESSAGE = "Unknown tag %s not allowed without -x flag."
COUNTER_CREATE_TAG = 'count'
COUNTER_USE_TAGS = set(['set', 'inc', 'dec', 'min',
'lessthan', 'morethan', 'atleast'])
class OutputFormat (object):
"Handles book output. Big FIXME required to make sense."
def __init__(self, templates, allow_unknown_tags, quote, name):
self.templates = templates
self.allow_unknown_tags = allow_unknown_tags
self.format_quote = quote
self.name = name
self.counter_names = {}
def quote(self, s):
if s:
return self.format_quote(s)
else:
return ""
def format_begin(self, bookconfig):
# FIXME make sure book config is properly quoted
return self.format_with_template("begin", bookconfig)
def format_intro_sections(self, introsections, shuffled_sections):
res = ""
for s in introsections:
if not s.hastag('dummy'):
res += self.format_intro_section(s, shuffled_sections)
return res
def format_intro_section(self, section, shuffled_sections):
# FIXME some serious code-duplication here
refs = []
refsdict = ReferenceFormatter(section.nr,
shuffled_sections.name_to_nr,
shuffled_sections.missingto,
self.templates.get("section_ref"),
self.templates.get("named_section_ref"),
self.quote)
formatted_text = self.format_section_body(section, refsdict)
return self.format_with_template("introsection", {
'name' : section.name,
'text' : formatted_text
})
def format_sections_begin(self, bookconfig):
return self.format_with_template("sections_begin",
bookconfig)
def format_shuffled_sections(self, shuffled_sections):
res = ""
for i, p in enumerate(shuffled_sections.as_list):
if p and not p.hastag('dummy'):
res += self.format_section(p, shuffled_sections)
elif i > 0:
res += self.format_empty_section(i)
return res
def format_section(self, section, shuffled_sections):
refs = []
refsdict = ReferenceFormatter(section.nr,
shuffled_sections.name_to_nr,
shuffled_sections.missingto,
self.templates.get("section_ref"),
self.templates.get("named_section_ref"),
self.quote)
formatted_text = self.format_section_body(section, refsdict)
return self.format_with_template("section", {
'nr' : section.nr,
'name' : section.name,
'text' : formatted_text
})
def format_section_body(self, section, references):
i = 0
res = ""
# FIXME refactor for readability once good tests are in place
while i < len(section.text):
ref_start = section.text.find('[[', i)
tag_start = section.text.find('[', i)
ref_name = None
if ref_start >= 0 and ref_start <= tag_start:
res += self.format_text(section.text[i:ref_start])
ref_end = section.text.find(']]', ref_start)
if ref_end > ref_start:
ref_name_div_start = section.text.find('][',
ref_start, ref_end)
if ref_name_div_start > ref_start:
ref_name = section.text[ref_name_div_start+2:ref_end]
ref = section.text[ref_start+2:ref_name_div_start]
else:
ref = section.text[ref_start+2:ref_end]
splitref = ref.split()
if len(splitref) > 1:
for refmod in splitref[:-1]:
res += self.format_with_template(refmod,
references)
res += references.ref(splitref[-1], ref_name)
i = ref_end + 2
else:
raise Exception('Mismatched ref start [[ in section %s' %
self.name)
elif tag_start >= 0:
res += self.format_text(section.text[i:tag_start])
tag_end = section.text.find(']', tag_start)
if tag_end < 0:
raise Exception('Mismatched tag start [ in section %s' %
self.name)
tag = section.text[tag_start+1:tag_end].strip()
tagparts = tag.split()
tagname = tagparts[0]
if not self.allow_unknown_tags and tagname not in BUILTIN_TAGS:
raise Exception(NOT_BUILTIN_TAG_MESSAGE % tagname)
end_tag_start = section.text.find('[', tag_end)
if (not end_tag_start > tag_end
and section.text[end_tag_start].startswith('[/' + tagname
+ ']')):
raise Exception('Bad format %s tag in %s.' % (
tag, self.name))
inner = section.text[tag_end+1:end_tag_start]
# FIXME this pollutes the mutable references object
references['inner'] = self.quote(inner)
for i, arg in enumerate(tagparts[1:]):
references['arg%d' % (i+1)] = self.quote(arg)
if tagname == COUNTER_CREATE_TAG and len(tagparts) > 1:
self.counter_names[tagparts[1]] = self.quote(inner)
references['counter'] = self.quote(inner)
elif tagname in COUNTER_USE_TAGS and len(tagparts) > 1:
if tagparts[1] in self.counter_names:
references['counter'] = self.counter_names[tagparts[1]]
f = self.format_with_template(tagname, references)
if len(f) > 0:
res += f
else:
res += self.quote(inner)
i = section.text.find(']', end_tag_start) + 1
else:
res += self.format_text(section.text[i:])
break
return res
def format_text(self, text):
return self.format_with_template('text', {'text' : self.quote(text)})
def format_empty_section(self, nr):
return self.format_with_template("empty_section", {
'nr' : nr,
})
def format_end(self, bookconfig):
return self.format_with_template("end", bookconfig)
def format_with_template(self, name, values=None):
template = self.templates.get(name)
if values:
return template % values
else:
return template
class ReferenceFormatter (object):
"There is probably a better way, but this hack seems to work."
def __init__(self, from_nr, name_to_nr, missingto, ref_template,
named_ref_template, quote):
self.from_nr = from_nr
self.name_to_nr = name_to_nr
self.ref_template = ref_template
self.named_ref_template = named_ref_template
self.items = {'nr' : from_nr}
self.quote = quote
self.missingto = missingto
def get_to_nr(self, key):
if key in self.name_to_nr:
return self.name_to_nr[key]
elif self.missingto in self.name_to_nr:
return self.name_to_nr[self.missingto]
else:
raise Exception('Missing reference target: %s' % key)
def __getitem__(self, key):
if key in self.items:
return self.quote(self.items[key])
else:
return self.ref_template % {
'nr' : self.get_to_nr(key),
'from_nr' : self.from_nr
}
def ref(self, key, name):
values = {
'nr' : self.get_to_nr(key),
'from_nr' : self.from_nr,
'name' : self.quote(name)
}
if name:
return self.named_ref_template % values
else:
return self.ref_template % values
def __setitem__(self, key, value):
self.items[key] = value
def __delitem__(self, key):
del self.items[key]