kpeg 0.7
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.
- data/Gemfile +4 -0
- data/LICENSE +25 -0
- data/README.md +8 -0
- data/Rakefile +24 -0
- data/bin/kpeg +126 -0
- data/doc/syntax_kpeg/ftdetect/kpeg.vim +1 -0
- data/doc/syntax_kpeg/syntax/kpeg.vim +55 -0
- data/kpeg.gemspec +24 -0
- data/lib/kpeg.rb +50 -0
- data/lib/kpeg/code_generator.rb +355 -0
- data/lib/kpeg/compiled_parser.rb +299 -0
- data/lib/kpeg/format_parser.rb +2440 -0
- data/lib/kpeg/grammar.rb +807 -0
- data/lib/kpeg/grammar_renderer.rb +172 -0
- data/lib/kpeg/match.rb +70 -0
- data/lib/kpeg/parser.rb +193 -0
- data/lib/kpeg/position.rb +34 -0
- data/lib/kpeg/string_escape.rb +322 -0
- data/lib/kpeg/version.rb +3 -0
- data/test/test_file_parser_roundtrip.rb +112 -0
- data/test/test_gen_calc.rb +63 -0
- data/test/test_kpeg.rb +416 -0
- data/test/test_kpeg_code_generator.rb +1307 -0
- data/test/test_kpeg_compiled_parser.rb +81 -0
- data/test/test_kpeg_format.rb +467 -0
- data/test/test_kpeg_grammar_renderer.rb +223 -0
- metadata +97 -0
@@ -0,0 +1,81 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
require 'kpeg'
|
3
|
+
require 'kpeg/compiled_parser'
|
4
|
+
require 'stringio'
|
5
|
+
|
6
|
+
class TestKPegCompiledParser < Test::Unit::TestCase
|
7
|
+
|
8
|
+
gram = <<-GRAM
|
9
|
+
letter = [a-z]
|
10
|
+
root = letter
|
11
|
+
GRAM
|
12
|
+
|
13
|
+
KPeg.compile gram, "TestParser", self
|
14
|
+
|
15
|
+
gram = <<-GRAM
|
16
|
+
%test = TestKPegCompiledParser::TestParser
|
17
|
+
root = %test.letter "!"
|
18
|
+
GRAM
|
19
|
+
|
20
|
+
KPeg.compile gram, "CompTestParser", self
|
21
|
+
|
22
|
+
def test_current_column
|
23
|
+
r = TestParser.new "hello\nsir"
|
24
|
+
assert_equal 2, r.current_column(1)
|
25
|
+
assert_equal 6, r.current_column(5)
|
26
|
+
assert_equal 1, r.current_column(7)
|
27
|
+
assert_equal 4, r.current_column(10)
|
28
|
+
end
|
29
|
+
|
30
|
+
def test_failed_rule
|
31
|
+
r = TestParser.new "9"
|
32
|
+
assert !r.parse, "shouldn't parse"
|
33
|
+
|
34
|
+
assert_equal :_letter, r.failed_rule
|
35
|
+
end
|
36
|
+
|
37
|
+
def test_failure_info
|
38
|
+
r = TestParser.new "9"
|
39
|
+
assert !r.parse, "shouldn't parse"
|
40
|
+
|
41
|
+
expected = "line 1, column 1: failed rule 'letter' = '[a-z]'"
|
42
|
+
assert_equal 0, r.failing_rule_offset
|
43
|
+
assert_equal expected, r.failure_info
|
44
|
+
end
|
45
|
+
|
46
|
+
def test_failure_caret
|
47
|
+
r = TestParser.new "9"
|
48
|
+
assert !r.parse, "shouldn't parse"
|
49
|
+
|
50
|
+
assert_equal "9\n^", r.failure_caret
|
51
|
+
end
|
52
|
+
|
53
|
+
def test_failure_character
|
54
|
+
r = TestParser.new "9"
|
55
|
+
assert !r.parse, "shouldn't parse"
|
56
|
+
|
57
|
+
assert_equal "9", r.failure_character
|
58
|
+
end
|
59
|
+
|
60
|
+
def test_failure_oneline
|
61
|
+
r = TestParser.new "9"
|
62
|
+
assert !r.parse, "shouldn't parse"
|
63
|
+
|
64
|
+
expected = "@1:1 failed rule 'letter', got '9'"
|
65
|
+
assert_equal expected, r.failure_oneline
|
66
|
+
end
|
67
|
+
|
68
|
+
def test_composite_grammar
|
69
|
+
r = CompTestParser.new "l!"
|
70
|
+
assert r.parse, "should parse"
|
71
|
+
end
|
72
|
+
|
73
|
+
def test_composite_grammar_failure
|
74
|
+
r = CompTestParser.new "9"
|
75
|
+
assert !r.parse, "should parse"
|
76
|
+
|
77
|
+
expected = "@1:1 failed rule 'TestKPegCompiledParser::TestParser#_letter', got '9'"
|
78
|
+
assert_equal expected, r.failure_oneline
|
79
|
+
end
|
80
|
+
|
81
|
+
end
|
@@ -0,0 +1,467 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
require 'kpeg'
|
3
|
+
require 'kpeg/format_parser'
|
4
|
+
require 'kpeg/grammar_renderer'
|
5
|
+
require 'stringio'
|
6
|
+
require 'rubygems'
|
7
|
+
|
8
|
+
class TestKPegFormat < Test::Unit::TestCase
|
9
|
+
G = KPeg::Grammar.new
|
10
|
+
|
11
|
+
gram = File.read File.expand_path("../../lib/kpeg/format.kpeg", __FILE__)
|
12
|
+
KPeg.compile gram, "TestParser", self
|
13
|
+
|
14
|
+
def match(str, gram=nil, log=false)
|
15
|
+
parc = TestParser.new str
|
16
|
+
parc.raise_error unless parc.parse
|
17
|
+
|
18
|
+
return parc.grammar
|
19
|
+
end
|
20
|
+
|
21
|
+
def assert_rule(expect, gram, name="a")
|
22
|
+
actual = gram.find name.to_s
|
23
|
+
assert_equal expect, actual.op
|
24
|
+
end
|
25
|
+
|
26
|
+
def test_assignment
|
27
|
+
assert_rule G.ref("b"), match("a=b"), "a"
|
28
|
+
end
|
29
|
+
|
30
|
+
def test_invoke
|
31
|
+
assert_rule G.invoke("b"), match("a=@b"), "a"
|
32
|
+
end
|
33
|
+
|
34
|
+
def test_assignment_hyphen_only
|
35
|
+
assert_rule G.ref("b"), match("-=b"), "-"
|
36
|
+
end
|
37
|
+
|
38
|
+
def test_assigment_sp
|
39
|
+
assert_rule G.ref("b"), match(" a=b")
|
40
|
+
assert_rule G.ref("b"), match(" a =b")
|
41
|
+
assert_rule G.ref("b"), match(" a = b")
|
42
|
+
assert_rule G.ref("b"), match(" a = b ")
|
43
|
+
end
|
44
|
+
|
45
|
+
def test_assign_with_arg
|
46
|
+
gram = match("a(t) = b")
|
47
|
+
rule = gram.find "a"
|
48
|
+
assert_equal ["t"], rule.arguments
|
49
|
+
end
|
50
|
+
|
51
|
+
def test_assign_with_arg_disambiguated_from_grouping
|
52
|
+
str = <<-STR
|
53
|
+
a = c
|
54
|
+
b(p) = x
|
55
|
+
STR
|
56
|
+
|
57
|
+
gram = match(str)
|
58
|
+
end
|
59
|
+
|
60
|
+
def test_assign_with_multiple_args
|
61
|
+
gram = match("a(t,x) = b")
|
62
|
+
rule = gram.find "a"
|
63
|
+
assert_equal ["t", "x"], rule.arguments
|
64
|
+
end
|
65
|
+
|
66
|
+
def test_assign_with_args_spacing
|
67
|
+
gram = match("a( t) = b")
|
68
|
+
rule = gram.find "a"
|
69
|
+
assert_equal ["t"], rule.arguments
|
70
|
+
|
71
|
+
gram = match("a( t ) = b")
|
72
|
+
rule = gram.find "a"
|
73
|
+
assert_equal ["t"], rule.arguments
|
74
|
+
|
75
|
+
gram = match("a( t,x) = b")
|
76
|
+
rule = gram.find "a"
|
77
|
+
assert_equal ["t", "x"], rule.arguments
|
78
|
+
|
79
|
+
gram = match("a( t,x ) = b")
|
80
|
+
rule = gram.find "a"
|
81
|
+
assert_equal ["t", "x"], rule.arguments
|
82
|
+
|
83
|
+
gram = match("a( t ,x ) = b")
|
84
|
+
rule = gram.find "a"
|
85
|
+
assert_equal ["t", "x"], rule.arguments
|
86
|
+
|
87
|
+
gram = match("a( t , x ) = b")
|
88
|
+
rule = gram.find "a"
|
89
|
+
assert_equal ["t", "x"], rule.arguments
|
90
|
+
end
|
91
|
+
|
92
|
+
def test_invoke_with_arg
|
93
|
+
gram = match("a=b(1)")
|
94
|
+
rule = gram.find "a"
|
95
|
+
assert_equal "(1)", rule.op.arguments
|
96
|
+
end
|
97
|
+
|
98
|
+
def test_invoke_with_multiple_args
|
99
|
+
assert_rule G.invoke("b", "(1,2)"), match("a=b(1,2)"), "a"
|
100
|
+
end
|
101
|
+
|
102
|
+
def test_invoke_foreign_rule
|
103
|
+
assert_rule G.foreign_invoke("blah", "letters"),
|
104
|
+
match("a=%blah.letters"), "a"
|
105
|
+
end
|
106
|
+
|
107
|
+
def test_add_foreign_grammar
|
108
|
+
gram = match "%blah = OtherGrammar"
|
109
|
+
assert_equal "OtherGrammar", gram.foreign_grammars["blah"]
|
110
|
+
end
|
111
|
+
|
112
|
+
def test_invoke_parent_rule
|
113
|
+
assert_rule G.foreign_invoke("parent", "letters"),
|
114
|
+
match("a=^letters"), "a"
|
115
|
+
end
|
116
|
+
|
117
|
+
def test_dot
|
118
|
+
assert_rule G.dot, match("a=.")
|
119
|
+
end
|
120
|
+
|
121
|
+
def test_string
|
122
|
+
assert_rule G.str("hello"), match('a="hello"')
|
123
|
+
assert_rule G.str("h\"ello"), match('a="h\"ello"')
|
124
|
+
end
|
125
|
+
|
126
|
+
def test_regexp
|
127
|
+
assert_rule G.reg(/foo/), match('a=/foo/')
|
128
|
+
assert_rule G.reg(/foo\/bar/), match('a=/foo\/bar/')
|
129
|
+
assert_rule G.reg(/[^"]/), match('a=/[^"]/')
|
130
|
+
end
|
131
|
+
|
132
|
+
def test_regexp_options
|
133
|
+
assert_rule G.reg(/foo/u), match('a=/foo/u')
|
134
|
+
end
|
135
|
+
|
136
|
+
def test_char_range
|
137
|
+
assert_rule G.range("a", "z"), match('a=[a-z]')
|
138
|
+
end
|
139
|
+
|
140
|
+
def test_maybe
|
141
|
+
assert_rule G.maybe(:b), match('a=b?')
|
142
|
+
end
|
143
|
+
|
144
|
+
def test_many
|
145
|
+
assert_rule G.many(:b), match('a=b+')
|
146
|
+
end
|
147
|
+
|
148
|
+
def test_many_sequence
|
149
|
+
assert_rule G.many([:b, :c]), match('a=(b c)+')
|
150
|
+
end
|
151
|
+
|
152
|
+
def test_many_sequence_with_action
|
153
|
+
assert_rule G.seq(G.many([:b, :c]), G.action(" 1 ")),
|
154
|
+
match('a=(b c)+ { 1 }')
|
155
|
+
end
|
156
|
+
|
157
|
+
def test_kleene
|
158
|
+
assert_rule G.kleene(:b), match('a=b*')
|
159
|
+
end
|
160
|
+
|
161
|
+
def test_arbitrary_multiple
|
162
|
+
assert_rule G.multiple(:b, 5, 9), match('a=b[5,9]')
|
163
|
+
end
|
164
|
+
|
165
|
+
def test_no_max_multiple
|
166
|
+
assert_rule G.multiple(:b, 5, nil), match('a=b[5,*]')
|
167
|
+
end
|
168
|
+
|
169
|
+
def test_no_max_multiple_sp
|
170
|
+
assert_rule G.multiple(:b, 5, nil), match('a=b[5, *]')
|
171
|
+
assert_rule G.multiple(:b, 5, nil), match('a=b[5, * ]')
|
172
|
+
assert_rule G.multiple(:b, 5, nil), match('a=b[5 , * ]')
|
173
|
+
assert_rule G.multiple(:b, 5, nil), match('a=b[ 5 , * ]')
|
174
|
+
end
|
175
|
+
|
176
|
+
def test_andp
|
177
|
+
assert_rule G.andp(:c), match('a=&c')
|
178
|
+
end
|
179
|
+
|
180
|
+
def test_notp
|
181
|
+
assert_rule G.notp(:c), match('a=!c')
|
182
|
+
end
|
183
|
+
|
184
|
+
def test_choice
|
185
|
+
assert_rule G.any(:b, :c), match('a=b|c')
|
186
|
+
end
|
187
|
+
|
188
|
+
def test_choice_seq_priority
|
189
|
+
assert_rule G.any([:num, :b], :c), match('a=num b|c')
|
190
|
+
end
|
191
|
+
|
192
|
+
def test_choice_sp
|
193
|
+
m = match 'a=num "+" dig | dig'
|
194
|
+
expected = G.any([:num, "+", :dig], :dig)
|
195
|
+
assert_rule expected, m
|
196
|
+
end
|
197
|
+
|
198
|
+
def test_choice_sp2
|
199
|
+
str = <<-STR
|
200
|
+
Stmt = - Expr:e EOL
|
201
|
+
| ( !EOL . )* EOL
|
202
|
+
STR
|
203
|
+
m = match str
|
204
|
+
expected = G.any(
|
205
|
+
[:"-", G.t(:Expr, "e"), :EOL],
|
206
|
+
[G.kleene([G.notp(:EOL), G.dot]), :EOL])
|
207
|
+
|
208
|
+
assert_rule expected, m, "Stmt"
|
209
|
+
end
|
210
|
+
|
211
|
+
def test_choice_with_actions
|
212
|
+
str = <<-STR
|
213
|
+
Stmt = - Expr:e EOL { p e }
|
214
|
+
| ( !EOL . )* EOL { puts "error" }
|
215
|
+
STR
|
216
|
+
m = match str
|
217
|
+
expected = G.any(
|
218
|
+
[:"-", G.t(:Expr, "e"), :EOL, G.action(" p e ")],
|
219
|
+
[G.kleene([G.notp(:EOL), G.dot]), :EOL,
|
220
|
+
G.action(" puts \"error\" ")])
|
221
|
+
|
222
|
+
assert_rule expected, m, "Stmt"
|
223
|
+
end
|
224
|
+
|
225
|
+
def test_multiline_seq
|
226
|
+
str = <<-STR
|
227
|
+
Sum = Product:l
|
228
|
+
( PLUS Product:r { l += r }
|
229
|
+
| MINUS Product:r { l -= r }
|
230
|
+
)* { l }
|
231
|
+
STR
|
232
|
+
m = match str
|
233
|
+
expected = G.seq(
|
234
|
+
G.t(:Product, "l"),
|
235
|
+
G.kleene(
|
236
|
+
G.any(
|
237
|
+
[:PLUS, G.t(:Product, "r"), G.action(" l += r ")],
|
238
|
+
[:MINUS, G.t(:Product, "r"), G.action(" l -= r ")]
|
239
|
+
)),
|
240
|
+
G.action(" l "))
|
241
|
+
|
242
|
+
assert_rule expected, m, "Sum"
|
243
|
+
end
|
244
|
+
|
245
|
+
def test_multiline_seq2
|
246
|
+
str = <<-STR
|
247
|
+
Value = NUMBER:i { i }
|
248
|
+
| ID:i !ASSIGN { vars[i] }
|
249
|
+
| OPEN Expr:i CLOSE { i }
|
250
|
+
STR
|
251
|
+
m = match(str)
|
252
|
+
end
|
253
|
+
|
254
|
+
def test_seq
|
255
|
+
m = match 'a=b c'
|
256
|
+
assert_rule G.seq(:b, :c), m
|
257
|
+
|
258
|
+
m = match 'a=b c d'
|
259
|
+
assert_rule G.seq(:b, :c, :d), m
|
260
|
+
|
261
|
+
m = match 'a=b c d e f'
|
262
|
+
assert_rule G.seq(:b, :c, :d, :e, :f), m
|
263
|
+
end
|
264
|
+
|
265
|
+
def test_tag
|
266
|
+
m = match 'a=b:x'
|
267
|
+
assert_rule G.t(:b, "x"), m
|
268
|
+
end
|
269
|
+
|
270
|
+
def test_tag_parens
|
271
|
+
m = match 'a=(b c):x'
|
272
|
+
assert_rule G.t([:b, :c], "x"), m
|
273
|
+
end
|
274
|
+
|
275
|
+
def test_tag_priority
|
276
|
+
m = match 'a=d (b c):x'
|
277
|
+
assert_rule G.seq(:d, G.t([:b, :c], "x")), m
|
278
|
+
|
279
|
+
m = match 'a=d c*:x'
|
280
|
+
assert_rule G.seq(:d, G.t(G.kleene(:c), "x")), m
|
281
|
+
end
|
282
|
+
|
283
|
+
def test_parens
|
284
|
+
m = match 'a=(b c)'
|
285
|
+
assert_rule G.seq(:b, :c), m
|
286
|
+
end
|
287
|
+
|
288
|
+
def test_parens_sp
|
289
|
+
m = match 'a=( b c )'
|
290
|
+
assert_rule G.seq(:b, :c), m
|
291
|
+
end
|
292
|
+
|
293
|
+
def test_parens_as_outer
|
294
|
+
m = match 'a=b (c|d)'
|
295
|
+
assert_rule G.seq(:b, G.any(:c, :d)), m
|
296
|
+
end
|
297
|
+
|
298
|
+
def test_action
|
299
|
+
m = match 'a=b c { b + c }'
|
300
|
+
assert_rule G.seq(:b, :c, G.action(" b + c ")), m
|
301
|
+
end
|
302
|
+
|
303
|
+
def test_action_nested_curly
|
304
|
+
m = match 'a=b c { b + { c + d } }'
|
305
|
+
assert_rule G.seq(:b, :c, G.action(" b + { c + d } ")), m
|
306
|
+
end
|
307
|
+
|
308
|
+
def test_collect
|
309
|
+
m = match 'a = < b c >'
|
310
|
+
assert_rule G.collect(G.seq(:b, :c)), m
|
311
|
+
end
|
312
|
+
|
313
|
+
def test_comment
|
314
|
+
m = match "a=b # this is a comment\n"
|
315
|
+
assert_rule G.ref('b'), m
|
316
|
+
end
|
317
|
+
|
318
|
+
def test_comment_span
|
319
|
+
m = match "a=b # this is a comment\n c"
|
320
|
+
assert_rule G.seq(G.ref('b'), G.ref("c")), m
|
321
|
+
end
|
322
|
+
|
323
|
+
def test_parser_setup
|
324
|
+
m = match "%% { def initialize; end }\na=b"
|
325
|
+
assert_rule G.ref("b"), m
|
326
|
+
assert_equal " def initialize; end ", m.setup_actions.first.action
|
327
|
+
end
|
328
|
+
|
329
|
+
def test_parser_name
|
330
|
+
m = match "%%name = BlahParser"
|
331
|
+
assert_equal "BlahParser", m.variables["name"]
|
332
|
+
end
|
333
|
+
|
334
|
+
def test_multiple_rules
|
335
|
+
m = match "a=b\nc=d\ne=f"
|
336
|
+
assert_rule G.ref("b"), m, "a"
|
337
|
+
assert_rule G.ref("d"), m, "c"
|
338
|
+
assert_rule G.ref("f"), m, "e"
|
339
|
+
end
|
340
|
+
|
341
|
+
def test_multiline_choice
|
342
|
+
gram = <<-GRAM
|
343
|
+
expr = num "+" num
|
344
|
+
| num "-" num
|
345
|
+
GRAM
|
346
|
+
|
347
|
+
m = match gram
|
348
|
+
expected = G.seq(:num, "+", :num) |
|
349
|
+
G.seq(:num, "-", :num)
|
350
|
+
assert_rule expected, m, "expr"
|
351
|
+
end
|
352
|
+
|
353
|
+
def test_multiline_choice_many2
|
354
|
+
gram = <<-GRAM
|
355
|
+
term = term "+" fact
|
356
|
+
| term "-" fact
|
357
|
+
| fact
|
358
|
+
fact = fact "*" num
|
359
|
+
| fact "/" num
|
360
|
+
| num
|
361
|
+
GRAM
|
362
|
+
|
363
|
+
m = match gram
|
364
|
+
term = G.any([:term, "+", :fact],
|
365
|
+
[:term, "-", :fact],
|
366
|
+
:fact)
|
367
|
+
fact = G.any([:fact, "*", :num],
|
368
|
+
[:fact, "/", :num],
|
369
|
+
:num)
|
370
|
+
|
371
|
+
assert_equal term, m.find("term").op
|
372
|
+
assert_equal fact, m.find("fact").op
|
373
|
+
end
|
374
|
+
|
375
|
+
def test_multiline_choice_many
|
376
|
+
gram = <<-GRAM
|
377
|
+
term = term "+" fact
|
378
|
+
| term "-" fact
|
379
|
+
fact = fact "*" num
|
380
|
+
| fact "/" num
|
381
|
+
GRAM
|
382
|
+
|
383
|
+
m = match gram
|
384
|
+
term = G.any([:term, "+", :fact],
|
385
|
+
[:term, "-", :fact])
|
386
|
+
fact = G.any([:fact, "*", :num],
|
387
|
+
[:fact, "/", :num])
|
388
|
+
|
389
|
+
assert_equal term, m.find("term").op
|
390
|
+
assert_equal fact, m.find("fact").op
|
391
|
+
end
|
392
|
+
|
393
|
+
def make_parser(str, gram, debug=false)
|
394
|
+
cg = KPeg::CodeGenerator.new "Test", gram, debug
|
395
|
+
inst = cg.make(str)
|
396
|
+
return inst
|
397
|
+
end
|
398
|
+
|
399
|
+
def test_roundtrip
|
400
|
+
path = File.expand_path("../../lib/kpeg/format.kpeg", __FILE__)
|
401
|
+
parser = KPeg::FormatParser.new File.read(path)
|
402
|
+
assert parser.parse, "Unable to parse"
|
403
|
+
|
404
|
+
start = parser.grammar
|
405
|
+
|
406
|
+
gr = KPeg::GrammarRenderer.new(start)
|
407
|
+
io = StringIO.new
|
408
|
+
gr.render(io)
|
409
|
+
|
410
|
+
scan = make_parser io.string, start
|
411
|
+
unless scan.parse
|
412
|
+
puts io.string
|
413
|
+
scan.show_error
|
414
|
+
assert !scan.failed?, "parsing the grammar"
|
415
|
+
end
|
416
|
+
|
417
|
+
g2 = scan.grammar
|
418
|
+
|
419
|
+
gr2 = KPeg::GrammarRenderer.new(g2)
|
420
|
+
io2 = StringIO.new
|
421
|
+
gr2.render(io2)
|
422
|
+
|
423
|
+
unless io.string == io2.string
|
424
|
+
require 'tempfile'
|
425
|
+
|
426
|
+
Tempfile.open "diff" do |f1|
|
427
|
+
f1 << io.string
|
428
|
+
f1.close
|
429
|
+
|
430
|
+
Tempfile.open "diff" do |f2|
|
431
|
+
f2 << io2.string
|
432
|
+
f2.close
|
433
|
+
|
434
|
+
system "diff -u #{f1.path} #{f2.path}"
|
435
|
+
end
|
436
|
+
end
|
437
|
+
end
|
438
|
+
|
439
|
+
assert_equal io.string, io2.string
|
440
|
+
|
441
|
+
# Go for a 3rd generation!
|
442
|
+
scan2 = make_parser io2.string, g2
|
443
|
+
assert scan2.parse, "parsing the grammar"
|
444
|
+
|
445
|
+
g3 = scan2.grammar
|
446
|
+
|
447
|
+
unless g3.rules.empty?
|
448
|
+
gr3 = KPeg::GrammarRenderer.new(g3)
|
449
|
+
io3 = StringIO.new
|
450
|
+
gr3.render(io3)
|
451
|
+
|
452
|
+
assert_equal io2.string, io3.string
|
453
|
+
|
454
|
+
# INCEPTION! 4! go for 4!
|
455
|
+
scan3 = make_parser io3.string, g3
|
456
|
+
assert scan3.parse, "parsing the grammar"
|
457
|
+
|
458
|
+
g4 = scan3.grammar
|
459
|
+
|
460
|
+
gr4 = KPeg::GrammarRenderer.new(g4)
|
461
|
+
io4 = StringIO.new
|
462
|
+
gr4.render(io4)
|
463
|
+
|
464
|
+
assert_equal io3.string, io4.string
|
465
|
+
end
|
466
|
+
end
|
467
|
+
end
|