kpeg 0.7
Sign up to get free protection for your applications and to get access to all the features.
- 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
|