hemingway 0.0.0 → 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +19 -0
- data/.travis.yml +4 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +297 -0
- data/Rakefile +1 -0
- data/hemingway.gemspec +23 -0
- data/lib/hemingway/block/block.rb +378 -0
- data/lib/hemingway/block/block.treetop +36 -0
- data/lib/hemingway/block/block_nodes.rb +9 -0
- data/lib/hemingway/block/list/list.rb +412 -0
- data/lib/hemingway/block/list/list.treetop +51 -0
- data/lib/hemingway/block/list/list_nodes.rb +39 -0
- data/lib/hemingway/block/quote/quote.rb +192 -0
- data/lib/hemingway/block/quote/quote.treetop +27 -0
- data/lib/hemingway/block/quote/quote_nodes.rb +25 -0
- data/lib/hemingway/block/verbatim/verbatim.rb +159 -0
- data/lib/hemingway/block/verbatim/verbatim.treetop +21 -0
- data/lib/hemingway/block/verbatim/verbatim_nodes.rb +9 -0
- data/lib/hemingway/build.rb +65 -0
- data/lib/hemingway/footnote/footnote.rb +83 -0
- data/lib/hemingway/footnote/footnote.treetop +11 -0
- data/lib/hemingway/footnote/footnote_nodes.rb +21 -0
- data/lib/hemingway/latex.rb +409 -0
- data/lib/hemingway/latex.treetop +81 -0
- data/lib/hemingway/latex_nodes.rb +45 -0
- data/lib/hemingway/math/math.rb +135 -0
- data/lib/hemingway/math/math.treetop +29 -0
- data/lib/hemingway/math/math_nodes.rb +7 -0
- data/lib/hemingway/special/special.rb +164 -0
- data/lib/hemingway/special/special.treetop +17 -0
- data/lib/hemingway/special/special_nodes.rb +7 -0
- data/lib/hemingway/symbol/symbol.rb +460 -0
- data/lib/hemingway/symbol/symbol.treetop +47 -0
- data/lib/hemingway/symbol/symbol_nodes.rb +7 -0
- data/lib/hemingway/tag/tag.rb +538 -0
- data/lib/hemingway/tag/tag.treetop +63 -0
- data/lib/hemingway/tag/tag_nodes.rb +49 -0
- data/lib/hemingway/text/text.rb +121 -0
- data/lib/hemingway/text/text.treetop +35 -0
- data/lib/hemingway/text/text_nodes.rb +7 -0
- data/lib/hemingway/version.rb +3 -0
- data/lib/hemingway.rb +7 -0
- data/script/build +22 -0
- data/script/test +2 -0
- data/spec/build_spec.rb +65 -0
- data/spec/nodes/block/list_spec.rb +91 -0
- data/spec/nodes/block/quote_spec.rb +31 -0
- data/spec/nodes/block/verbatim_spec.rb +27 -0
- data/spec/nodes/block_spec.rb +21 -0
- data/spec/nodes/footnote_spec.rb +42 -0
- data/spec/nodes/math_spec.rb +31 -0
- data/spec/nodes/special_spec.rb +27 -0
- data/spec/nodes/tag_spec.rb +98 -0
- data/spec/parser_spec.rb +48 -0
- data/spec/spec_helper.rb +5 -0
- metadata +110 -18
@@ -0,0 +1,412 @@
|
|
1
|
+
# Autogenerated from a Treetop grammar. Edits may be lost.
|
2
|
+
|
3
|
+
|
4
|
+
require "hemingway/block/list/list_nodes"
|
5
|
+
|
6
|
+
module Hemingway
|
7
|
+
module Block
|
8
|
+
module List
|
9
|
+
include Treetop::Runtime
|
10
|
+
|
11
|
+
def root
|
12
|
+
@root ||= :list
|
13
|
+
end
|
14
|
+
|
15
|
+
def _nt_list
|
16
|
+
start_index = index
|
17
|
+
if node_cache[:list].has_key?(index)
|
18
|
+
cached = node_cache[:list][index]
|
19
|
+
if cached
|
20
|
+
cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
|
21
|
+
@index = cached.interval.end
|
22
|
+
end
|
23
|
+
return cached
|
24
|
+
end
|
25
|
+
|
26
|
+
s0, i0 = [], index
|
27
|
+
loop do
|
28
|
+
r1 = _nt_item
|
29
|
+
if r1
|
30
|
+
s0 << r1
|
31
|
+
else
|
32
|
+
break
|
33
|
+
end
|
34
|
+
end
|
35
|
+
if s0.empty?
|
36
|
+
@index = i0
|
37
|
+
r0 = nil
|
38
|
+
else
|
39
|
+
r0 = instantiate_node(SyntaxNode,input, i0...index, s0)
|
40
|
+
end
|
41
|
+
|
42
|
+
node_cache[:list][start_index] = r0
|
43
|
+
|
44
|
+
r0
|
45
|
+
end
|
46
|
+
|
47
|
+
def _nt_list_type
|
48
|
+
start_index = index
|
49
|
+
if node_cache[:list_type].has_key?(index)
|
50
|
+
cached = node_cache[:list_type][index]
|
51
|
+
if cached
|
52
|
+
cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
|
53
|
+
@index = cached.interval.end
|
54
|
+
end
|
55
|
+
return cached
|
56
|
+
end
|
57
|
+
|
58
|
+
i0 = index
|
59
|
+
if has_terminal?("itemize", false, index)
|
60
|
+
r1 = instantiate_node(ItemizeListNode,input, index...(index + 7))
|
61
|
+
@index += 7
|
62
|
+
else
|
63
|
+
terminal_parse_failure("itemize")
|
64
|
+
r1 = nil
|
65
|
+
end
|
66
|
+
if r1
|
67
|
+
r0 = r1
|
68
|
+
else
|
69
|
+
if has_terminal?("enumerate", false, index)
|
70
|
+
r2 = instantiate_node(EnumerateListNode,input, index...(index + 9))
|
71
|
+
@index += 9
|
72
|
+
else
|
73
|
+
terminal_parse_failure("enumerate")
|
74
|
+
r2 = nil
|
75
|
+
end
|
76
|
+
if r2
|
77
|
+
r0 = r2
|
78
|
+
else
|
79
|
+
if has_terminal?("description", false, index)
|
80
|
+
r3 = instantiate_node(DescriptionListNode,input, index...(index + 11))
|
81
|
+
@index += 11
|
82
|
+
else
|
83
|
+
terminal_parse_failure("description")
|
84
|
+
r3 = nil
|
85
|
+
end
|
86
|
+
if r3
|
87
|
+
r0 = r3
|
88
|
+
else
|
89
|
+
@index = i0
|
90
|
+
r0 = nil
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
node_cache[:list_type][start_index] = r0
|
96
|
+
|
97
|
+
r0
|
98
|
+
end
|
99
|
+
|
100
|
+
module Item0
|
101
|
+
def whitespace1
|
102
|
+
elements[1]
|
103
|
+
end
|
104
|
+
|
105
|
+
def label
|
106
|
+
elements[2]
|
107
|
+
end
|
108
|
+
|
109
|
+
def sequence
|
110
|
+
elements[3]
|
111
|
+
end
|
112
|
+
|
113
|
+
def whitespace2
|
114
|
+
elements[4]
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
def _nt_item
|
119
|
+
start_index = index
|
120
|
+
if node_cache[:item].has_key?(index)
|
121
|
+
cached = node_cache[:item][index]
|
122
|
+
if cached
|
123
|
+
cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
|
124
|
+
@index = cached.interval.end
|
125
|
+
end
|
126
|
+
return cached
|
127
|
+
end
|
128
|
+
|
129
|
+
i0, s0 = index, []
|
130
|
+
if has_terminal?("\\item", false, index)
|
131
|
+
r1 = instantiate_node(SyntaxNode,input, index...(index + 5))
|
132
|
+
@index += 5
|
133
|
+
else
|
134
|
+
terminal_parse_failure("\\item")
|
135
|
+
r1 = nil
|
136
|
+
end
|
137
|
+
s0 << r1
|
138
|
+
if r1
|
139
|
+
r2 = _nt_whitespace
|
140
|
+
s0 << r2
|
141
|
+
if r2
|
142
|
+
r4 = _nt_label
|
143
|
+
if r4
|
144
|
+
r3 = r4
|
145
|
+
else
|
146
|
+
r3 = instantiate_node(SyntaxNode,input, index...index)
|
147
|
+
end
|
148
|
+
s0 << r3
|
149
|
+
if r3
|
150
|
+
s5, i5 = [], index
|
151
|
+
loop do
|
152
|
+
r6 = _nt_content
|
153
|
+
if r6
|
154
|
+
s5 << r6
|
155
|
+
else
|
156
|
+
break
|
157
|
+
end
|
158
|
+
end
|
159
|
+
r5 = instantiate_node(SyntaxNode,input, i5...index, s5)
|
160
|
+
s0 << r5
|
161
|
+
if r5
|
162
|
+
r7 = _nt_whitespace
|
163
|
+
s0 << r7
|
164
|
+
end
|
165
|
+
end
|
166
|
+
end
|
167
|
+
end
|
168
|
+
if s0.last
|
169
|
+
r0 = instantiate_node(ItemNode,input, i0...index, s0)
|
170
|
+
r0.extend(Item0)
|
171
|
+
else
|
172
|
+
@index = i0
|
173
|
+
r0 = nil
|
174
|
+
end
|
175
|
+
|
176
|
+
node_cache[:item][start_index] = r0
|
177
|
+
|
178
|
+
r0
|
179
|
+
end
|
180
|
+
|
181
|
+
module Label0
|
182
|
+
def label_start
|
183
|
+
elements[0]
|
184
|
+
end
|
185
|
+
|
186
|
+
def sequence
|
187
|
+
elements[1]
|
188
|
+
end
|
189
|
+
|
190
|
+
def label_end
|
191
|
+
elements[2]
|
192
|
+
end
|
193
|
+
end
|
194
|
+
|
195
|
+
def _nt_label
|
196
|
+
start_index = index
|
197
|
+
if node_cache[:label].has_key?(index)
|
198
|
+
cached = node_cache[:label][index]
|
199
|
+
if cached
|
200
|
+
cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
|
201
|
+
@index = cached.interval.end
|
202
|
+
end
|
203
|
+
return cached
|
204
|
+
end
|
205
|
+
|
206
|
+
i0, s0 = index, []
|
207
|
+
r1 = _nt_label_start
|
208
|
+
s0 << r1
|
209
|
+
if r1
|
210
|
+
s2, i2 = [], index
|
211
|
+
loop do
|
212
|
+
r3 = _nt_label_content
|
213
|
+
if r3
|
214
|
+
s2 << r3
|
215
|
+
else
|
216
|
+
break
|
217
|
+
end
|
218
|
+
end
|
219
|
+
r2 = instantiate_node(SyntaxNode,input, i2...index, s2)
|
220
|
+
s0 << r2
|
221
|
+
if r2
|
222
|
+
r4 = _nt_label_end
|
223
|
+
s0 << r4
|
224
|
+
end
|
225
|
+
end
|
226
|
+
if s0.last
|
227
|
+
r0 = instantiate_node(LabelNode,input, i0...index, s0)
|
228
|
+
r0.extend(Label0)
|
229
|
+
else
|
230
|
+
@index = i0
|
231
|
+
r0 = nil
|
232
|
+
end
|
233
|
+
|
234
|
+
node_cache[:label][start_index] = r0
|
235
|
+
|
236
|
+
r0
|
237
|
+
end
|
238
|
+
|
239
|
+
def _nt_label_content
|
240
|
+
start_index = index
|
241
|
+
if node_cache[:label_content].has_key?(index)
|
242
|
+
cached = node_cache[:label_content][index]
|
243
|
+
if cached
|
244
|
+
cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
|
245
|
+
@index = cached.interval.end
|
246
|
+
end
|
247
|
+
return cached
|
248
|
+
end
|
249
|
+
|
250
|
+
i0 = index
|
251
|
+
r1 = _nt_special
|
252
|
+
if r1
|
253
|
+
r0 = r1
|
254
|
+
else
|
255
|
+
r2 = _nt_tag
|
256
|
+
if r2
|
257
|
+
r0 = r2
|
258
|
+
else
|
259
|
+
r3 = _nt_block
|
260
|
+
if r3
|
261
|
+
r0 = r3
|
262
|
+
else
|
263
|
+
r4 = _nt_math
|
264
|
+
if r4
|
265
|
+
r0 = r4
|
266
|
+
else
|
267
|
+
r5 = _nt_label_text
|
268
|
+
if r5
|
269
|
+
r0 = r5
|
270
|
+
else
|
271
|
+
@index = i0
|
272
|
+
r0 = nil
|
273
|
+
end
|
274
|
+
end
|
275
|
+
end
|
276
|
+
end
|
277
|
+
end
|
278
|
+
|
279
|
+
node_cache[:label_content][start_index] = r0
|
280
|
+
|
281
|
+
r0
|
282
|
+
end
|
283
|
+
|
284
|
+
module LabelText0
|
285
|
+
end
|
286
|
+
|
287
|
+
def _nt_label_text
|
288
|
+
start_index = index
|
289
|
+
if node_cache[:label_text].has_key?(index)
|
290
|
+
cached = node_cache[:label_text][index]
|
291
|
+
if cached
|
292
|
+
cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
|
293
|
+
@index = cached.interval.end
|
294
|
+
end
|
295
|
+
return cached
|
296
|
+
end
|
297
|
+
|
298
|
+
s0, i0 = [], index
|
299
|
+
loop do
|
300
|
+
i1, s1 = index, []
|
301
|
+
i2 = index
|
302
|
+
i3 = index
|
303
|
+
r4 = _nt_non_text
|
304
|
+
if r4
|
305
|
+
r3 = r4
|
306
|
+
else
|
307
|
+
r5 = _nt_label_end
|
308
|
+
if r5
|
309
|
+
r3 = r5
|
310
|
+
else
|
311
|
+
@index = i3
|
312
|
+
r3 = nil
|
313
|
+
end
|
314
|
+
end
|
315
|
+
if r3
|
316
|
+
r2 = nil
|
317
|
+
else
|
318
|
+
@index = i2
|
319
|
+
r2 = instantiate_node(SyntaxNode,input, index...index)
|
320
|
+
end
|
321
|
+
s1 << r2
|
322
|
+
if r2
|
323
|
+
if index < input_length
|
324
|
+
r6 = instantiate_node(SyntaxNode,input, index...(index + 1))
|
325
|
+
@index += 1
|
326
|
+
else
|
327
|
+
terminal_parse_failure("any character")
|
328
|
+
r6 = nil
|
329
|
+
end
|
330
|
+
s1 << r6
|
331
|
+
end
|
332
|
+
if s1.last
|
333
|
+
r1 = instantiate_node(SyntaxNode,input, i1...index, s1)
|
334
|
+
r1.extend(LabelText0)
|
335
|
+
else
|
336
|
+
@index = i1
|
337
|
+
r1 = nil
|
338
|
+
end
|
339
|
+
if r1
|
340
|
+
s0 << r1
|
341
|
+
else
|
342
|
+
break
|
343
|
+
end
|
344
|
+
end
|
345
|
+
if s0.empty?
|
346
|
+
@index = i0
|
347
|
+
r0 = nil
|
348
|
+
else
|
349
|
+
r0 = instantiate_node(TextNode,input, i0...index, s0)
|
350
|
+
end
|
351
|
+
|
352
|
+
node_cache[:label_text][start_index] = r0
|
353
|
+
|
354
|
+
r0
|
355
|
+
end
|
356
|
+
|
357
|
+
def _nt_label_start
|
358
|
+
start_index = index
|
359
|
+
if node_cache[:label_start].has_key?(index)
|
360
|
+
cached = node_cache[:label_start][index]
|
361
|
+
if cached
|
362
|
+
cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
|
363
|
+
@index = cached.interval.end
|
364
|
+
end
|
365
|
+
return cached
|
366
|
+
end
|
367
|
+
|
368
|
+
if has_terminal?("[", false, index)
|
369
|
+
r0 = instantiate_node(SyntaxNode,input, index...(index + 1))
|
370
|
+
@index += 1
|
371
|
+
else
|
372
|
+
terminal_parse_failure("[")
|
373
|
+
r0 = nil
|
374
|
+
end
|
375
|
+
|
376
|
+
node_cache[:label_start][start_index] = r0
|
377
|
+
|
378
|
+
r0
|
379
|
+
end
|
380
|
+
|
381
|
+
def _nt_label_end
|
382
|
+
start_index = index
|
383
|
+
if node_cache[:label_end].has_key?(index)
|
384
|
+
cached = node_cache[:label_end][index]
|
385
|
+
if cached
|
386
|
+
cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
|
387
|
+
@index = cached.interval.end
|
388
|
+
end
|
389
|
+
return cached
|
390
|
+
end
|
391
|
+
|
392
|
+
if has_terminal?("]", false, index)
|
393
|
+
r0 = instantiate_node(SyntaxNode,input, index...(index + 1))
|
394
|
+
@index += 1
|
395
|
+
else
|
396
|
+
terminal_parse_failure("]")
|
397
|
+
r0 = nil
|
398
|
+
end
|
399
|
+
|
400
|
+
node_cache[:label_end][start_index] = r0
|
401
|
+
|
402
|
+
r0
|
403
|
+
end
|
404
|
+
|
405
|
+
end
|
406
|
+
|
407
|
+
class ListParser < Treetop::Runtime::CompiledParser
|
408
|
+
include List
|
409
|
+
end
|
410
|
+
|
411
|
+
end
|
412
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
require "hemingway/block/list/list_nodes"
|
2
|
+
|
3
|
+
module Hemingway
|
4
|
+
module Block
|
5
|
+
grammar List
|
6
|
+
|
7
|
+
rule list
|
8
|
+
item+
|
9
|
+
end
|
10
|
+
|
11
|
+
rule list_type
|
12
|
+
"itemize" <ItemizeListNode>
|
13
|
+
/
|
14
|
+
"enumerate" <EnumerateListNode>
|
15
|
+
/
|
16
|
+
"description" <DescriptionListNode>
|
17
|
+
end
|
18
|
+
|
19
|
+
rule item
|
20
|
+
"\\item" whitespace label:label? sequence:content* whitespace <ItemNode>
|
21
|
+
end
|
22
|
+
|
23
|
+
rule label
|
24
|
+
label_start sequence:label_content* label_end <LabelNode>
|
25
|
+
end
|
26
|
+
|
27
|
+
# This is oddly similar to content. We have to use label_text
|
28
|
+
# instead of text though.. big time bummer.. gotta esacape that label
|
29
|
+
# closing bracket.
|
30
|
+
rule label_content
|
31
|
+
special / tag / block / math / label_text
|
32
|
+
end
|
33
|
+
|
34
|
+
# Example: \item[label_text]
|
35
|
+
# This totally sucks, but I need to escape a special character when
|
36
|
+
# I have text that resides within an item label. Oof.
|
37
|
+
rule label_text
|
38
|
+
( !( non_text / label_end ) . )+ <TextNode>
|
39
|
+
end
|
40
|
+
|
41
|
+
rule label_start
|
42
|
+
"["
|
43
|
+
end
|
44
|
+
|
45
|
+
rule label_end
|
46
|
+
"]"
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module Hemingway
|
2
|
+
|
3
|
+
module ItemizeListNode
|
4
|
+
def html(block_content)
|
5
|
+
Build.tag("ul", block_content.elements.map { |e| e.list_html }.join)
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
module EnumerateListNode
|
10
|
+
def html(block_content)
|
11
|
+
Build.tag("ol", block_content.elements.map { |e| e.list_html }.join)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
module DescriptionListNode
|
16
|
+
def html(block_content)
|
17
|
+
Build.tag("dl", block_content.elements.map { |e| e.description_html }.join)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
module ItemNode
|
22
|
+
def list_html
|
23
|
+
label_tag = label.empty? ? "" : Build.tag("span", label.html, :class => "list-label")
|
24
|
+
Build.tag("li", label_tag + sequence.elements.map { |e| e.html }.join)
|
25
|
+
end
|
26
|
+
|
27
|
+
def description_html
|
28
|
+
label_tag = label.empty? ? "" : Build.tag("dt", label.html)
|
29
|
+
Build.tag("dd", label_tag + sequence.elements.map { |e| e.html }.join)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
module LabelNode
|
34
|
+
def html
|
35
|
+
sequence.elements.map { |e| e.html }.join
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
@@ -0,0 +1,192 @@
|
|
1
|
+
# Autogenerated from a Treetop grammar. Edits may be lost.
|
2
|
+
|
3
|
+
|
4
|
+
require "hemingway/block/quote/quote_nodes"
|
5
|
+
|
6
|
+
module Hemingway
|
7
|
+
module Block
|
8
|
+
module Quote
|
9
|
+
include Treetop::Runtime
|
10
|
+
|
11
|
+
def root
|
12
|
+
@root ||= :quote_type
|
13
|
+
end
|
14
|
+
|
15
|
+
def _nt_quote_type
|
16
|
+
start_index = index
|
17
|
+
if node_cache[:quote_type].has_key?(index)
|
18
|
+
cached = node_cache[:quote_type][index]
|
19
|
+
if cached
|
20
|
+
cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
|
21
|
+
@index = cached.interval.end
|
22
|
+
end
|
23
|
+
return cached
|
24
|
+
end
|
25
|
+
|
26
|
+
if has_terminal?("quote", false, index)
|
27
|
+
r0 = instantiate_node(QuoteNode,input, index...(index + 5))
|
28
|
+
@index += 5
|
29
|
+
else
|
30
|
+
terminal_parse_failure("quote")
|
31
|
+
r0 = nil
|
32
|
+
end
|
33
|
+
|
34
|
+
node_cache[:quote_type][start_index] = r0
|
35
|
+
|
36
|
+
r0
|
37
|
+
end
|
38
|
+
|
39
|
+
def _nt_quote_entry
|
40
|
+
start_index = index
|
41
|
+
if node_cache[:quote_entry].has_key?(index)
|
42
|
+
cached = node_cache[:quote_entry][index]
|
43
|
+
if cached
|
44
|
+
cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
|
45
|
+
@index = cached.interval.end
|
46
|
+
end
|
47
|
+
return cached
|
48
|
+
end
|
49
|
+
|
50
|
+
s0, i0 = [], index
|
51
|
+
loop do
|
52
|
+
i1 = index
|
53
|
+
r2 = _nt_quote_paragraph
|
54
|
+
if r2
|
55
|
+
r1 = r2
|
56
|
+
else
|
57
|
+
r3 = _nt_quote_last_paragraph
|
58
|
+
if r3
|
59
|
+
r1 = r3
|
60
|
+
else
|
61
|
+
@index = i1
|
62
|
+
r1 = nil
|
63
|
+
end
|
64
|
+
end
|
65
|
+
if r1
|
66
|
+
s0 << r1
|
67
|
+
else
|
68
|
+
break
|
69
|
+
end
|
70
|
+
end
|
71
|
+
r0 = instantiate_node(QuoteEntryNode,input, i0...index, s0)
|
72
|
+
|
73
|
+
node_cache[:quote_entry][start_index] = r0
|
74
|
+
|
75
|
+
r0
|
76
|
+
end
|
77
|
+
|
78
|
+
module QuoteParagraph0
|
79
|
+
def sequence
|
80
|
+
elements[0]
|
81
|
+
end
|
82
|
+
|
83
|
+
def eop
|
84
|
+
elements[1]
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
def _nt_quote_paragraph
|
89
|
+
start_index = index
|
90
|
+
if node_cache[:quote_paragraph].has_key?(index)
|
91
|
+
cached = node_cache[:quote_paragraph][index]
|
92
|
+
if cached
|
93
|
+
cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
|
94
|
+
@index = cached.interval.end
|
95
|
+
end
|
96
|
+
return cached
|
97
|
+
end
|
98
|
+
|
99
|
+
i0, s0 = index, []
|
100
|
+
s1, i1 = [], index
|
101
|
+
loop do
|
102
|
+
r2 = _nt_content
|
103
|
+
if r2
|
104
|
+
s1 << r2
|
105
|
+
else
|
106
|
+
break
|
107
|
+
end
|
108
|
+
end
|
109
|
+
r1 = instantiate_node(SyntaxNode,input, i1...index, s1)
|
110
|
+
s0 << r1
|
111
|
+
if r1
|
112
|
+
r3 = _nt_eop
|
113
|
+
s0 << r3
|
114
|
+
end
|
115
|
+
if s0.last
|
116
|
+
r0 = instantiate_node(QuoteParagraphNode,input, i0...index, s0)
|
117
|
+
r0.extend(QuoteParagraph0)
|
118
|
+
else
|
119
|
+
@index = i0
|
120
|
+
r0 = nil
|
121
|
+
end
|
122
|
+
|
123
|
+
node_cache[:quote_paragraph][start_index] = r0
|
124
|
+
|
125
|
+
r0
|
126
|
+
end
|
127
|
+
|
128
|
+
module QuoteLastParagraph0
|
129
|
+
def sequence
|
130
|
+
elements[0]
|
131
|
+
end
|
132
|
+
|
133
|
+
end
|
134
|
+
|
135
|
+
def _nt_quote_last_paragraph
|
136
|
+
start_index = index
|
137
|
+
if node_cache[:quote_last_paragraph].has_key?(index)
|
138
|
+
cached = node_cache[:quote_last_paragraph][index]
|
139
|
+
if cached
|
140
|
+
cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
|
141
|
+
@index = cached.interval.end
|
142
|
+
end
|
143
|
+
return cached
|
144
|
+
end
|
145
|
+
|
146
|
+
i0, s0 = index, []
|
147
|
+
s1, i1 = [], index
|
148
|
+
loop do
|
149
|
+
r2 = _nt_content
|
150
|
+
if r2
|
151
|
+
s1 << r2
|
152
|
+
else
|
153
|
+
break
|
154
|
+
end
|
155
|
+
end
|
156
|
+
if s1.empty?
|
157
|
+
@index = i1
|
158
|
+
r1 = nil
|
159
|
+
else
|
160
|
+
r1 = instantiate_node(SyntaxNode,input, i1...index, s1)
|
161
|
+
end
|
162
|
+
s0 << r1
|
163
|
+
if r1
|
164
|
+
r4 = _nt_eop
|
165
|
+
if r4
|
166
|
+
r3 = r4
|
167
|
+
else
|
168
|
+
r3 = instantiate_node(SyntaxNode,input, index...index)
|
169
|
+
end
|
170
|
+
s0 << r3
|
171
|
+
end
|
172
|
+
if s0.last
|
173
|
+
r0 = instantiate_node(QuoteParagraphNode,input, i0...index, s0)
|
174
|
+
r0.extend(QuoteLastParagraph0)
|
175
|
+
else
|
176
|
+
@index = i0
|
177
|
+
r0 = nil
|
178
|
+
end
|
179
|
+
|
180
|
+
node_cache[:quote_last_paragraph][start_index] = r0
|
181
|
+
|
182
|
+
r0
|
183
|
+
end
|
184
|
+
|
185
|
+
end
|
186
|
+
|
187
|
+
class QuoteParser < Treetop::Runtime::CompiledParser
|
188
|
+
include Quote
|
189
|
+
end
|
190
|
+
|
191
|
+
end
|
192
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require "hemingway/block/quote/quote_nodes"
|
2
|
+
|
3
|
+
module Hemingway
|
4
|
+
module Block
|
5
|
+
grammar Quote
|
6
|
+
|
7
|
+
rule quote_type
|
8
|
+
"quote" <QuoteNode>
|
9
|
+
end
|
10
|
+
|
11
|
+
rule quote_entry
|
12
|
+
( quote_paragraph / quote_last_paragraph )* <QuoteEntryNode>
|
13
|
+
end
|
14
|
+
|
15
|
+
# This quote_paragraph / quote_last_paragraph business is the same pattern
|
16
|
+
# I use with paragraph and last paragraph.
|
17
|
+
rule quote_paragraph
|
18
|
+
sequence:( content )* eop <QuoteParagraphNode>
|
19
|
+
end
|
20
|
+
|
21
|
+
rule quote_last_paragraph
|
22
|
+
sequence:( content )+ eop? <QuoteParagraphNode>
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|