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
data/test/test_kpeg.rb
ADDED
@@ -0,0 +1,416 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
require 'kpeg'
|
3
|
+
require 'stringio'
|
4
|
+
|
5
|
+
class TestKPeg < Test::Unit::TestCase
|
6
|
+
def assert_match(m, str)
|
7
|
+
assert_kind_of KPeg::MatchString, m
|
8
|
+
assert_equal str, m.string
|
9
|
+
end
|
10
|
+
|
11
|
+
def test_dot
|
12
|
+
gram = KPeg.grammar do |g|
|
13
|
+
g.root = g.dot
|
14
|
+
end
|
15
|
+
|
16
|
+
assert_match KPeg.match("q", gram), "q"
|
17
|
+
end
|
18
|
+
|
19
|
+
def test_str
|
20
|
+
gram = KPeg.grammar do |g|
|
21
|
+
g.root = g.str("hello")
|
22
|
+
end
|
23
|
+
|
24
|
+
assert_match KPeg.match("hello", gram), "hello"
|
25
|
+
assert_equal nil, KPeg.match("vador", gram)
|
26
|
+
end
|
27
|
+
|
28
|
+
def test_reg
|
29
|
+
gram = KPeg.grammar do |g|
|
30
|
+
g.root = g.reg(/[0-9]/)
|
31
|
+
end
|
32
|
+
|
33
|
+
assert_match KPeg.match("3", gram), "3"
|
34
|
+
end
|
35
|
+
|
36
|
+
def test_char_range
|
37
|
+
gram = KPeg.grammar do |g|
|
38
|
+
g.root = g.range('0', '9')
|
39
|
+
end
|
40
|
+
|
41
|
+
assert_match KPeg.match("3", gram), "3"
|
42
|
+
end
|
43
|
+
|
44
|
+
def test_any
|
45
|
+
gram = KPeg.grammar do |g|
|
46
|
+
g.root = g.any g.str("hello"), g.str("chicken")
|
47
|
+
end
|
48
|
+
|
49
|
+
assert_match KPeg.match("hello", gram), "hello"
|
50
|
+
assert_match KPeg.match("chicken", gram), "chicken"
|
51
|
+
assert_equal nil, KPeg.match("vador", gram)
|
52
|
+
end
|
53
|
+
|
54
|
+
def test_maybe
|
55
|
+
gram = KPeg.grammar do |g|
|
56
|
+
g.root = g.maybe g.str("hello")
|
57
|
+
end
|
58
|
+
|
59
|
+
m = KPeg.match "hello", gram
|
60
|
+
assert_kind_of KPeg::Match, m
|
61
|
+
assert_equal 1, m.matches.size
|
62
|
+
assert_match m.matches[0], "hello"
|
63
|
+
|
64
|
+
m = KPeg.match "surprise", gram
|
65
|
+
assert_kind_of KPeg::Match, m
|
66
|
+
assert_equal 0, m.matches.size
|
67
|
+
end
|
68
|
+
|
69
|
+
def test_many
|
70
|
+
gram = KPeg.grammar do |g|
|
71
|
+
g.root = g.many g.str("run")
|
72
|
+
end
|
73
|
+
|
74
|
+
m = KPeg.match "runrunrun", gram
|
75
|
+
assert_kind_of KPeg::Match, m
|
76
|
+
assert_equal 3, m.matches.size
|
77
|
+
m.matches.each do |sm|
|
78
|
+
assert_match sm, "run"
|
79
|
+
end
|
80
|
+
|
81
|
+
assert_equal nil, KPeg.match("vador", gram)
|
82
|
+
end
|
83
|
+
|
84
|
+
def test_kleene
|
85
|
+
gram = KPeg.grammar do |g|
|
86
|
+
g.root = g.kleene g.str("run")
|
87
|
+
end
|
88
|
+
|
89
|
+
m = KPeg.match "runrunrun", gram
|
90
|
+
assert_kind_of KPeg::Match, m
|
91
|
+
assert_equal 3, m.matches.size
|
92
|
+
m.matches.each do |sm|
|
93
|
+
assert_match sm, "run"
|
94
|
+
end
|
95
|
+
|
96
|
+
m = KPeg.match "chicken", gram
|
97
|
+
assert_kind_of KPeg::Match, m
|
98
|
+
assert_equal 0, m.matches.size
|
99
|
+
end
|
100
|
+
|
101
|
+
def test_multiple
|
102
|
+
gram = KPeg.grammar do |g|
|
103
|
+
g.root = g.multiple g.str("run"), 2, 4
|
104
|
+
end
|
105
|
+
|
106
|
+
m = KPeg.match "runrun", gram
|
107
|
+
assert_kind_of KPeg::Match, m
|
108
|
+
assert_equal 2, m.matches.size
|
109
|
+
m.matches.each do |sm|
|
110
|
+
assert_match sm, "run"
|
111
|
+
end
|
112
|
+
|
113
|
+
m = KPeg.match "runrunrun", gram
|
114
|
+
assert_kind_of KPeg::Match, m
|
115
|
+
assert_equal 3, m.matches.size
|
116
|
+
m.matches.each do |sm|
|
117
|
+
assert_match sm, "run"
|
118
|
+
end
|
119
|
+
|
120
|
+
m = KPeg.match "runrunrunrun", gram
|
121
|
+
assert_kind_of KPeg::Match, m
|
122
|
+
assert_equal 4, m.matches.size
|
123
|
+
m.matches.each do |sm|
|
124
|
+
assert_match sm, "run"
|
125
|
+
end
|
126
|
+
|
127
|
+
assert_equal nil, KPeg.match("run", gram)
|
128
|
+
assert_equal nil, KPeg.match("runrunrunrunrun", gram)
|
129
|
+
assert_equal nil, KPeg.match("vador", gram)
|
130
|
+
end
|
131
|
+
|
132
|
+
def test_seq
|
133
|
+
gram = KPeg.grammar do |g|
|
134
|
+
g.root = g.seq g.str("hello"), g.str(", world")
|
135
|
+
end
|
136
|
+
|
137
|
+
m = KPeg.match "hello, world", gram
|
138
|
+
assert_kind_of KPeg::Match, m
|
139
|
+
assert_match m.matches[0], "hello"
|
140
|
+
assert_match m.matches[1], ", world"
|
141
|
+
|
142
|
+
assert_equal m.value, ["hello", ", world"]
|
143
|
+
|
144
|
+
assert_equal nil, KPeg.match("vador", gram)
|
145
|
+
assert_equal nil, KPeg.match("hello, vador", gram)
|
146
|
+
end
|
147
|
+
|
148
|
+
def test_andp
|
149
|
+
gram = KPeg.grammar do |g|
|
150
|
+
g.root = g.seq g.andp(g.str("h")), g.str("hello")
|
151
|
+
end
|
152
|
+
|
153
|
+
m = KPeg.match "hello", gram
|
154
|
+
assert_equal m.matches.size, 2
|
155
|
+
assert_match m.matches[0], ""
|
156
|
+
assert_match m.matches[1], "hello"
|
157
|
+
end
|
158
|
+
|
159
|
+
def test_notp
|
160
|
+
gram = KPeg.grammar do |g|
|
161
|
+
g.root = g.seq g.notp(g.str("g")), g.str("hello")
|
162
|
+
end
|
163
|
+
|
164
|
+
m = KPeg.match "hello", gram
|
165
|
+
assert_equal m.matches.size, 2
|
166
|
+
assert_match m.matches[0], ""
|
167
|
+
assert_match m.matches[1], "hello"
|
168
|
+
end
|
169
|
+
|
170
|
+
def test_ref
|
171
|
+
gram = KPeg.grammar do |g|
|
172
|
+
g.greeting = g.str("hello")
|
173
|
+
g.root = g.ref "greeting"
|
174
|
+
end
|
175
|
+
|
176
|
+
m = KPeg.match "hello", gram
|
177
|
+
assert_match m, "hello"
|
178
|
+
end
|
179
|
+
|
180
|
+
def test_invoke
|
181
|
+
gram = KPeg.grammar do |g|
|
182
|
+
g.greeting = g.str("hello")
|
183
|
+
g.root = g.invoke "greeting"
|
184
|
+
end
|
185
|
+
|
186
|
+
m = KPeg.match "hello", gram
|
187
|
+
assert_match m, "hello"
|
188
|
+
end
|
189
|
+
|
190
|
+
def test_foreign_ref
|
191
|
+
g1 = KPeg.grammar do |g|
|
192
|
+
g.greeting = "hello"
|
193
|
+
end
|
194
|
+
|
195
|
+
g2 = KPeg.grammar do |g|
|
196
|
+
g.root = g.ref("greeting", g1)
|
197
|
+
end
|
198
|
+
|
199
|
+
m = KPeg.match "hello", g2
|
200
|
+
assert_match m, "hello"
|
201
|
+
end
|
202
|
+
|
203
|
+
def test_foreign_ref_with_ref
|
204
|
+
g1 = KPeg.grammar do |g|
|
205
|
+
g.name = ", evan"
|
206
|
+
g.greeting = g.seq("hello", :name)
|
207
|
+
end
|
208
|
+
|
209
|
+
g2 = KPeg.grammar do |g|
|
210
|
+
g.root = g.ref("greeting", g1)
|
211
|
+
end
|
212
|
+
|
213
|
+
m = KPeg.match "hello, evan", g2
|
214
|
+
assert_match m.matches[0], "hello"
|
215
|
+
assert_match m.matches[1], ", evan"
|
216
|
+
end
|
217
|
+
|
218
|
+
def test_tag_with_name
|
219
|
+
gram = KPeg.grammar do |g|
|
220
|
+
g.root = g.seq(" ", g.t("hello", "greeting"))
|
221
|
+
end
|
222
|
+
|
223
|
+
m = KPeg.match " hello", gram
|
224
|
+
|
225
|
+
assert_equal 2, m.matches.size
|
226
|
+
tag = m.matches[1]
|
227
|
+
assert_kind_of KPeg::Tag, tag.op
|
228
|
+
assert_equal 1, tag.matches.size
|
229
|
+
assert_match tag.matches[0], "hello"
|
230
|
+
|
231
|
+
# show that tag influences the value of the sequence
|
232
|
+
assert_equal m.value, "hello"
|
233
|
+
end
|
234
|
+
|
235
|
+
def test_tag_without_name
|
236
|
+
gram = KPeg.grammar do |g|
|
237
|
+
g.root = g.seq(" ", g.t("hello"))
|
238
|
+
end
|
239
|
+
|
240
|
+
m = KPeg.match " hello", gram
|
241
|
+
assert_equal m.value, "hello"
|
242
|
+
end
|
243
|
+
|
244
|
+
def test_action
|
245
|
+
gram = KPeg.grammar do |g|
|
246
|
+
g.root = g.seq("hello", g.action("b + c"))
|
247
|
+
end
|
248
|
+
|
249
|
+
m = KPeg.match "hello", gram
|
250
|
+
assert_equal 2, m.matches.size
|
251
|
+
assert_match m.matches[0], "hello"
|
252
|
+
|
253
|
+
action = m.matches[1]
|
254
|
+
assert_equal action.op.action, "b + c"
|
255
|
+
end
|
256
|
+
|
257
|
+
def test_naming
|
258
|
+
gram = KPeg.grammar do |g|
|
259
|
+
g.greeting = g.str("hello")
|
260
|
+
g.root = g.greeting
|
261
|
+
end
|
262
|
+
|
263
|
+
m = KPeg.match "hello", gram
|
264
|
+
assert_match m, "hello"
|
265
|
+
end
|
266
|
+
|
267
|
+
def test_matching_curly
|
268
|
+
gram = KPeg.grammar do |g|
|
269
|
+
g.curly = g.seq("{", g.kleene(g.any(/[^{}]+/, :curly)), "}")
|
270
|
+
g.root = :curly
|
271
|
+
end
|
272
|
+
|
273
|
+
m = KPeg.match "{ hello }", gram
|
274
|
+
assert_match m.matches[0], "{"
|
275
|
+
assert_match m.matches[1].matches[0], " hello "
|
276
|
+
assert_match m.matches[2], "}"
|
277
|
+
|
278
|
+
parc = KPeg::Parser.new "{ foo { bar } }", gram
|
279
|
+
m = parc.parse
|
280
|
+
assert_equal "{ foo { bar } }", m.total_string
|
281
|
+
|
282
|
+
parc = KPeg::Parser.new "{ foo {\nbar }\n }", gram
|
283
|
+
m = parc.parse
|
284
|
+
assert_equal "{ foo {\nbar }\n }", m.total_string
|
285
|
+
end
|
286
|
+
|
287
|
+
def test_collect
|
288
|
+
gram = KPeg.grammar do |g|
|
289
|
+
g.root = g.collect(g.many(/[a-z]/))
|
290
|
+
end
|
291
|
+
|
292
|
+
m = KPeg.match "hellomatch", gram
|
293
|
+
assert_equal "hellomatch", m.value
|
294
|
+
end
|
295
|
+
|
296
|
+
def test_memoization
|
297
|
+
gram = KPeg.grammar do |g|
|
298
|
+
g.one = g.str("1")
|
299
|
+
g.two = g.str("2")
|
300
|
+
|
301
|
+
g.root = g.any(
|
302
|
+
[:one, "-", :two],
|
303
|
+
[:one, "+", :two]
|
304
|
+
)
|
305
|
+
end
|
306
|
+
|
307
|
+
parser = KPeg::Parser.new "1+2", gram
|
308
|
+
m = parser.parse
|
309
|
+
|
310
|
+
assert_equal 3, m.matches.size
|
311
|
+
assert_match m.matches[0], "1"
|
312
|
+
assert_match m.matches[1], "+"
|
313
|
+
assert_match m.matches[2], "2"
|
314
|
+
|
315
|
+
one = gram.find("one")
|
316
|
+
two = gram.find("two")
|
317
|
+
|
318
|
+
# We try 1 twice
|
319
|
+
assert_equal 2, parser.memoizations[one][0].uses
|
320
|
+
|
321
|
+
# but we only get as far as 2 once
|
322
|
+
assert_equal 1, parser.memoizations[two][2].uses
|
323
|
+
end
|
324
|
+
|
325
|
+
def test_left_recursion
|
326
|
+
gram = KPeg.grammar do |g|
|
327
|
+
g.num = g.reg(/[0-9]/)
|
328
|
+
g.expr = g.any [:expr, "-", :num], :num
|
329
|
+
|
330
|
+
g.root = g.expr
|
331
|
+
end
|
332
|
+
|
333
|
+
parser = KPeg::Parser.new "1-2-3", gram
|
334
|
+
|
335
|
+
m = parser.parse
|
336
|
+
assert_equal 3, m.matches.size
|
337
|
+
|
338
|
+
left = m.matches[0]
|
339
|
+
assert_equal 3, left.matches.size
|
340
|
+
assert_match left.matches[0], "1"
|
341
|
+
assert_match left.matches[1], "-"
|
342
|
+
assert_match left.matches[2], "2"
|
343
|
+
assert_match m.matches[1], "-"
|
344
|
+
assert_match m.matches[2], "3"
|
345
|
+
|
346
|
+
parser = KPeg::Parser.new "hello", gram
|
347
|
+
m = parser.parse
|
348
|
+
|
349
|
+
assert_equal nil, m
|
350
|
+
end
|
351
|
+
|
352
|
+
def test_math_grammar
|
353
|
+
gram = KPeg.grammar do |g|
|
354
|
+
g.num = '0'..'9'
|
355
|
+
g.term = g.seq(:term, "+", :term) \
|
356
|
+
| g.seq(:term, "-", :term) \
|
357
|
+
| :fact
|
358
|
+
|
359
|
+
g.fact = g.seq(:fact, "*", :fact) \
|
360
|
+
| g.seq(:fact, "/", :fact) \
|
361
|
+
| :num
|
362
|
+
|
363
|
+
g.root = g.term
|
364
|
+
end
|
365
|
+
|
366
|
+
sub = KPeg.match "4*3-8/9", gram
|
367
|
+
mul = sub.matches[0]
|
368
|
+
div = sub.matches[2]
|
369
|
+
|
370
|
+
assert_match mul.matches[0], "4"
|
371
|
+
assert_match mul.matches[1], "*"
|
372
|
+
assert_match mul.matches[2], "3"
|
373
|
+
|
374
|
+
assert_match sub.matches[1], "-"
|
375
|
+
|
376
|
+
assert_match div.matches[0], "8"
|
377
|
+
assert_match div.matches[1], "/"
|
378
|
+
assert_match div.matches[2], "9"
|
379
|
+
end
|
380
|
+
|
381
|
+
def test_calc
|
382
|
+
vars = {}
|
383
|
+
gram = KPeg.grammar do |g|
|
384
|
+
g.spaces = /\s*/
|
385
|
+
g.var = 'a'..'z'
|
386
|
+
g.num = g.lit(/[0-9]+/) { |i| i.to_i }
|
387
|
+
|
388
|
+
g.pri = g.seq(:spaces, :var) { |s,v| vars[v] } \
|
389
|
+
| g.seq(:spaces, :num) { |s,n| n } \
|
390
|
+
| g.seq('(', :expr, ')') { |_,e,_| e }
|
391
|
+
|
392
|
+
g.mul = g.seq(:mul, "*", :pri) { |x,_,y| x * y } \
|
393
|
+
| g.seq(:mul, "/", :pri) { |x,_,y| x / y } \
|
394
|
+
| :pri
|
395
|
+
|
396
|
+
g.add = g.seq(:add, "+", :mul) { |x,_,y| x + y } \
|
397
|
+
| g.seq(:add, "-", :mul) { |x,_,y| x - y } \
|
398
|
+
| :mul
|
399
|
+
|
400
|
+
g.expr = g.seq(:var, "=", :expr) { |v,_,e| vars[v] = e } \
|
401
|
+
| :add
|
402
|
+
|
403
|
+
g.root = g.seq(g.kleene(:expr), :spaces) { |e,_| e }
|
404
|
+
end
|
405
|
+
|
406
|
+
m = KPeg.match "3+4*5", gram
|
407
|
+
assert_equal 23, m.value
|
408
|
+
|
409
|
+
m = KPeg.match "x=2", gram
|
410
|
+
assert_equal 2, m.value
|
411
|
+
|
412
|
+
m = KPeg.match "x=x*7", gram
|
413
|
+
assert_equal 14, m.value
|
414
|
+
end
|
415
|
+
|
416
|
+
end
|
@@ -0,0 +1,1307 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
require 'kpeg'
|
3
|
+
require 'kpeg/code_generator'
|
4
|
+
require 'stringio'
|
5
|
+
|
6
|
+
class TestKPegCodeGenerator < Test::Unit::TestCase
|
7
|
+
def test_dot
|
8
|
+
gram = KPeg.grammar do |g|
|
9
|
+
g.root = g.dot
|
10
|
+
end
|
11
|
+
|
12
|
+
str = <<-STR
|
13
|
+
require 'kpeg/compiled_parser'
|
14
|
+
|
15
|
+
class Test < KPeg::CompiledParser
|
16
|
+
|
17
|
+
# root = .
|
18
|
+
def _root
|
19
|
+
_tmp = get_byte
|
20
|
+
set_failed_rule :_root unless _tmp
|
21
|
+
return _tmp
|
22
|
+
end
|
23
|
+
|
24
|
+
Rules = {}
|
25
|
+
Rules[:_root] = rule_info("root", ".")
|
26
|
+
end
|
27
|
+
STR
|
28
|
+
|
29
|
+
cg = KPeg::CodeGenerator.new "Test", gram
|
30
|
+
|
31
|
+
assert_equal str, cg.output
|
32
|
+
|
33
|
+
assert cg.parse("hello")
|
34
|
+
end
|
35
|
+
|
36
|
+
def test_str
|
37
|
+
gram = KPeg.grammar do |g|
|
38
|
+
g.root = g.str("hello")
|
39
|
+
end
|
40
|
+
|
41
|
+
str = <<-STR
|
42
|
+
require 'kpeg/compiled_parser'
|
43
|
+
|
44
|
+
class Test < KPeg::CompiledParser
|
45
|
+
|
46
|
+
# root = "hello"
|
47
|
+
def _root
|
48
|
+
_tmp = match_string("hello")
|
49
|
+
set_failed_rule :_root unless _tmp
|
50
|
+
return _tmp
|
51
|
+
end
|
52
|
+
|
53
|
+
Rules = {}
|
54
|
+
Rules[:_root] = rule_info("root", "\\\"hello\\\"")
|
55
|
+
end
|
56
|
+
STR
|
57
|
+
|
58
|
+
cg = KPeg::CodeGenerator.new "Test", gram
|
59
|
+
|
60
|
+
assert_equal str, cg.output
|
61
|
+
|
62
|
+
assert cg.parse("hello")
|
63
|
+
end
|
64
|
+
|
65
|
+
def test_reg
|
66
|
+
gram = KPeg.grammar do |g|
|
67
|
+
g.root = g.reg(/[0-9]/)
|
68
|
+
end
|
69
|
+
|
70
|
+
str = <<-STR
|
71
|
+
require 'kpeg/compiled_parser'
|
72
|
+
|
73
|
+
class Test < KPeg::CompiledParser
|
74
|
+
|
75
|
+
# root = /[0-9]/
|
76
|
+
def _root
|
77
|
+
_tmp = scan(/\\A(?-mix:[0-9])/)
|
78
|
+
set_failed_rule :_root unless _tmp
|
79
|
+
return _tmp
|
80
|
+
end
|
81
|
+
|
82
|
+
Rules = {}
|
83
|
+
Rules[:_root] = rule_info("root", "/[0-9]/")
|
84
|
+
end
|
85
|
+
STR
|
86
|
+
|
87
|
+
cg = KPeg::CodeGenerator.new "Test", gram
|
88
|
+
|
89
|
+
assert_equal str, cg.output
|
90
|
+
|
91
|
+
assert cg.parse("9")
|
92
|
+
assert cg.parse("1")
|
93
|
+
assert !cg.parse("a")
|
94
|
+
end
|
95
|
+
|
96
|
+
def test_char_range
|
97
|
+
gram = KPeg.grammar do |g|
|
98
|
+
g.root = g.range("a", "z")
|
99
|
+
end
|
100
|
+
|
101
|
+
str = <<-STR
|
102
|
+
require 'kpeg/compiled_parser'
|
103
|
+
|
104
|
+
class Test < KPeg::CompiledParser
|
105
|
+
|
106
|
+
# root = [a-z]
|
107
|
+
def _root
|
108
|
+
_save = self.pos
|
109
|
+
_tmp = get_byte
|
110
|
+
if _tmp
|
111
|
+
unless _tmp >= 97 and _tmp <= 122
|
112
|
+
self.pos = _save
|
113
|
+
_tmp = nil
|
114
|
+
end
|
115
|
+
end
|
116
|
+
set_failed_rule :_root unless _tmp
|
117
|
+
return _tmp
|
118
|
+
end
|
119
|
+
|
120
|
+
Rules = {}
|
121
|
+
Rules[:_root] = rule_info("root", "[a-z]")
|
122
|
+
end
|
123
|
+
STR
|
124
|
+
|
125
|
+
cg = KPeg::CodeGenerator.new "Test", gram
|
126
|
+
|
127
|
+
assert_equal str, cg.output
|
128
|
+
|
129
|
+
assert cg.parse("z")
|
130
|
+
assert cg.parse("a")
|
131
|
+
assert !cg.parse("0")
|
132
|
+
end
|
133
|
+
|
134
|
+
def test_char_range_in_seq
|
135
|
+
gram = KPeg.grammar do |g|
|
136
|
+
g.root = g.seq(g.range("a", "z"), "hello")
|
137
|
+
end
|
138
|
+
|
139
|
+
str = <<-STR
|
140
|
+
require 'kpeg/compiled_parser'
|
141
|
+
|
142
|
+
class Test < KPeg::CompiledParser
|
143
|
+
|
144
|
+
# root = [a-z] "hello"
|
145
|
+
def _root
|
146
|
+
|
147
|
+
_save = self.pos
|
148
|
+
while true # sequence
|
149
|
+
_save1 = self.pos
|
150
|
+
_tmp = get_byte
|
151
|
+
if _tmp
|
152
|
+
unless _tmp >= 97 and _tmp <= 122
|
153
|
+
self.pos = _save1
|
154
|
+
_tmp = nil
|
155
|
+
end
|
156
|
+
end
|
157
|
+
unless _tmp
|
158
|
+
self.pos = _save
|
159
|
+
break
|
160
|
+
end
|
161
|
+
_tmp = match_string("hello")
|
162
|
+
unless _tmp
|
163
|
+
self.pos = _save
|
164
|
+
end
|
165
|
+
break
|
166
|
+
end # end sequence
|
167
|
+
|
168
|
+
set_failed_rule :_root unless _tmp
|
169
|
+
return _tmp
|
170
|
+
end
|
171
|
+
|
172
|
+
Rules = {}
|
173
|
+
Rules[:_root] = rule_info("root", "[a-z] \\\"hello\\\"")
|
174
|
+
end
|
175
|
+
STR
|
176
|
+
|
177
|
+
cg = KPeg::CodeGenerator.new "Test", gram
|
178
|
+
|
179
|
+
assert_equal str, cg.output
|
180
|
+
|
181
|
+
assert cg.parse("ahello")
|
182
|
+
assert cg.parse("zhello")
|
183
|
+
assert !cg.parse("0hello")
|
184
|
+
assert !cg.parse("ajello")
|
185
|
+
end
|
186
|
+
|
187
|
+
def test_any
|
188
|
+
gram = KPeg.grammar do |g|
|
189
|
+
g.root = g.any("hello", "world")
|
190
|
+
end
|
191
|
+
|
192
|
+
str = <<-STR
|
193
|
+
require 'kpeg/compiled_parser'
|
194
|
+
|
195
|
+
class Test < KPeg::CompiledParser
|
196
|
+
|
197
|
+
# root = ("hello" | "world")
|
198
|
+
def _root
|
199
|
+
|
200
|
+
_save = self.pos
|
201
|
+
while true # choice
|
202
|
+
_tmp = match_string("hello")
|
203
|
+
break if _tmp
|
204
|
+
self.pos = _save
|
205
|
+
_tmp = match_string("world")
|
206
|
+
break if _tmp
|
207
|
+
self.pos = _save
|
208
|
+
break
|
209
|
+
end # end choice
|
210
|
+
|
211
|
+
set_failed_rule :_root unless _tmp
|
212
|
+
return _tmp
|
213
|
+
end
|
214
|
+
|
215
|
+
Rules = {}
|
216
|
+
Rules[:_root] = rule_info("root", "(\\\"hello\\\" | \\\"world\\\")")
|
217
|
+
end
|
218
|
+
STR
|
219
|
+
|
220
|
+
cg = KPeg::CodeGenerator.new "Test", gram
|
221
|
+
|
222
|
+
assert_equal str, cg.output
|
223
|
+
|
224
|
+
assert cg.parse("hello")
|
225
|
+
assert cg.parse("world")
|
226
|
+
assert !cg.parse("jello")
|
227
|
+
end
|
228
|
+
|
229
|
+
def test_any_resets_pos
|
230
|
+
gram = KPeg.grammar do |g|
|
231
|
+
g.root = g.any(g.seq("hello", "world"), "hello balloons")
|
232
|
+
end
|
233
|
+
|
234
|
+
cg = KPeg::CodeGenerator.new "Test", gram
|
235
|
+
|
236
|
+
code = cg.make("helloworld")
|
237
|
+
assert code.parse
|
238
|
+
assert_equal 10, code.pos
|
239
|
+
|
240
|
+
assert cg.parse("hello balloons")
|
241
|
+
end
|
242
|
+
|
243
|
+
def test_maybe
|
244
|
+
gram = KPeg.grammar do |g|
|
245
|
+
g.root = g.maybe("hello")
|
246
|
+
end
|
247
|
+
|
248
|
+
str = <<-STR
|
249
|
+
require 'kpeg/compiled_parser'
|
250
|
+
|
251
|
+
class Test < KPeg::CompiledParser
|
252
|
+
|
253
|
+
# root = "hello"?
|
254
|
+
def _root
|
255
|
+
_save = self.pos
|
256
|
+
_tmp = match_string("hello")
|
257
|
+
unless _tmp
|
258
|
+
_tmp = true
|
259
|
+
self.pos = _save
|
260
|
+
end
|
261
|
+
set_failed_rule :_root unless _tmp
|
262
|
+
return _tmp
|
263
|
+
end
|
264
|
+
|
265
|
+
Rules = {}
|
266
|
+
Rules[:_root] = rule_info("root", "\\\"hello\\\"?")
|
267
|
+
end
|
268
|
+
STR
|
269
|
+
|
270
|
+
cg = KPeg::CodeGenerator.new "Test", gram
|
271
|
+
|
272
|
+
assert_equal str, cg.output
|
273
|
+
|
274
|
+
assert cg.parse("hello")
|
275
|
+
assert cg.parse("jello")
|
276
|
+
end
|
277
|
+
|
278
|
+
def test_maybe_resets_pos
|
279
|
+
gram = KPeg.grammar do |g|
|
280
|
+
g.root = g.maybe(g.seq("hello", "world"))
|
281
|
+
end
|
282
|
+
|
283
|
+
cg = KPeg::CodeGenerator.new "Test", gram
|
284
|
+
|
285
|
+
assert cg.parse("helloworld")
|
286
|
+
|
287
|
+
code = cg.make("hellojello")
|
288
|
+
assert code.parse
|
289
|
+
assert_equal 0, code.pos
|
290
|
+
end
|
291
|
+
|
292
|
+
def test_kleene
|
293
|
+
gram = KPeg.grammar do |g|
|
294
|
+
g.root = g.kleene("hello")
|
295
|
+
end
|
296
|
+
|
297
|
+
str = <<-STR
|
298
|
+
require 'kpeg/compiled_parser'
|
299
|
+
|
300
|
+
class Test < KPeg::CompiledParser
|
301
|
+
|
302
|
+
# root = "hello"*
|
303
|
+
def _root
|
304
|
+
while true
|
305
|
+
_tmp = match_string("hello")
|
306
|
+
break unless _tmp
|
307
|
+
end
|
308
|
+
_tmp = true
|
309
|
+
set_failed_rule :_root unless _tmp
|
310
|
+
return _tmp
|
311
|
+
end
|
312
|
+
|
313
|
+
Rules = {}
|
314
|
+
Rules[:_root] = rule_info("root", "\\\"hello\\\"*")
|
315
|
+
end
|
316
|
+
STR
|
317
|
+
|
318
|
+
cg = KPeg::CodeGenerator.new "Test", gram
|
319
|
+
|
320
|
+
assert_equal str, cg.output
|
321
|
+
|
322
|
+
code = cg.make("hellohellohello")
|
323
|
+
assert code.parse
|
324
|
+
assert_equal 15, code.pos
|
325
|
+
end
|
326
|
+
|
327
|
+
def test_kleene_reset_pos
|
328
|
+
gram = KPeg.grammar do |g|
|
329
|
+
g.root = g.kleene(g.seq("hello", "world"))
|
330
|
+
end
|
331
|
+
|
332
|
+
cg = KPeg::CodeGenerator.new "Test", gram
|
333
|
+
|
334
|
+
code = cg.make("helloworldhelloworld")
|
335
|
+
assert code.parse
|
336
|
+
assert_equal 20, code.pos
|
337
|
+
|
338
|
+
code = cg.make("hellojello")
|
339
|
+
assert code.parse
|
340
|
+
assert_equal 0, code.pos
|
341
|
+
end
|
342
|
+
|
343
|
+
def test_many
|
344
|
+
gram = KPeg.grammar do |g|
|
345
|
+
g.root = g.many("hello")
|
346
|
+
end
|
347
|
+
|
348
|
+
str = <<-STR
|
349
|
+
require 'kpeg/compiled_parser'
|
350
|
+
|
351
|
+
class Test < KPeg::CompiledParser
|
352
|
+
|
353
|
+
# root = "hello"+
|
354
|
+
def _root
|
355
|
+
_save = self.pos
|
356
|
+
_tmp = match_string("hello")
|
357
|
+
if _tmp
|
358
|
+
while true
|
359
|
+
_tmp = match_string("hello")
|
360
|
+
break unless _tmp
|
361
|
+
end
|
362
|
+
_tmp = true
|
363
|
+
else
|
364
|
+
self.pos = _save
|
365
|
+
end
|
366
|
+
set_failed_rule :_root unless _tmp
|
367
|
+
return _tmp
|
368
|
+
end
|
369
|
+
|
370
|
+
Rules = {}
|
371
|
+
Rules[:_root] = rule_info("root", "\\\"hello\\\"+")
|
372
|
+
end
|
373
|
+
STR
|
374
|
+
|
375
|
+
cg = KPeg::CodeGenerator.new "Test", gram
|
376
|
+
|
377
|
+
assert_equal str, cg.output
|
378
|
+
|
379
|
+
code = cg.make("hellohello")
|
380
|
+
assert code.parse
|
381
|
+
assert_equal 10, code.pos
|
382
|
+
|
383
|
+
code = cg.make("hello")
|
384
|
+
assert code.parse
|
385
|
+
assert_equal 5, code.pos
|
386
|
+
|
387
|
+
code = cg.make("")
|
388
|
+
assert !code.parse
|
389
|
+
end
|
390
|
+
|
391
|
+
def test_many_resets_pos
|
392
|
+
gram = KPeg.grammar do |g|
|
393
|
+
g.root = g.many(g.seq("hello", "world"))
|
394
|
+
end
|
395
|
+
|
396
|
+
cg = KPeg::CodeGenerator.new "Test", gram
|
397
|
+
|
398
|
+
code = cg.make("helloworldhelloworld")
|
399
|
+
assert code.parse
|
400
|
+
assert_equal 20, code.pos
|
401
|
+
|
402
|
+
code = cg.make("hellojello")
|
403
|
+
assert !code.parse
|
404
|
+
assert_equal 0, code.pos
|
405
|
+
end
|
406
|
+
|
407
|
+
def test_multiple
|
408
|
+
gram = KPeg.grammar do |g|
|
409
|
+
g.root = g.multiple("hello", 5, 9)
|
410
|
+
end
|
411
|
+
|
412
|
+
str = <<-STR
|
413
|
+
require 'kpeg/compiled_parser'
|
414
|
+
|
415
|
+
class Test < KPeg::CompiledParser
|
416
|
+
|
417
|
+
# root = "hello"[5, 9]
|
418
|
+
def _root
|
419
|
+
_save = self.pos
|
420
|
+
_count = 0
|
421
|
+
while true
|
422
|
+
_tmp = match_string("hello")
|
423
|
+
if _tmp
|
424
|
+
_count += 1
|
425
|
+
break if _count == 9
|
426
|
+
else
|
427
|
+
break
|
428
|
+
end
|
429
|
+
end
|
430
|
+
if _count >= 5
|
431
|
+
_tmp = true
|
432
|
+
else
|
433
|
+
self.pos = _save
|
434
|
+
_tmp = nil
|
435
|
+
end
|
436
|
+
set_failed_rule :_root unless _tmp
|
437
|
+
return _tmp
|
438
|
+
end
|
439
|
+
|
440
|
+
Rules = {}
|
441
|
+
Rules[:_root] = rule_info("root", "\\\"hello\\\"[5, 9]")
|
442
|
+
end
|
443
|
+
STR
|
444
|
+
|
445
|
+
cg = KPeg::CodeGenerator.new "Test", gram
|
446
|
+
|
447
|
+
assert_equal str, cg.output
|
448
|
+
end
|
449
|
+
|
450
|
+
def test_seq
|
451
|
+
gram = KPeg.grammar do |g|
|
452
|
+
g.root = g.seq("hello", "world")
|
453
|
+
end
|
454
|
+
|
455
|
+
str = <<-STR
|
456
|
+
require 'kpeg/compiled_parser'
|
457
|
+
|
458
|
+
class Test < KPeg::CompiledParser
|
459
|
+
|
460
|
+
# root = "hello" "world"
|
461
|
+
def _root
|
462
|
+
|
463
|
+
_save = self.pos
|
464
|
+
while true # sequence
|
465
|
+
_tmp = match_string("hello")
|
466
|
+
unless _tmp
|
467
|
+
self.pos = _save
|
468
|
+
break
|
469
|
+
end
|
470
|
+
_tmp = match_string("world")
|
471
|
+
unless _tmp
|
472
|
+
self.pos = _save
|
473
|
+
end
|
474
|
+
break
|
475
|
+
end # end sequence
|
476
|
+
|
477
|
+
set_failed_rule :_root unless _tmp
|
478
|
+
return _tmp
|
479
|
+
end
|
480
|
+
|
481
|
+
Rules = {}
|
482
|
+
Rules[:_root] = rule_info("root", "\\\"hello\\\" \\\"world\\\"")
|
483
|
+
end
|
484
|
+
STR
|
485
|
+
|
486
|
+
cg = KPeg::CodeGenerator.new "Test", gram
|
487
|
+
|
488
|
+
assert_equal str, cg.output
|
489
|
+
end
|
490
|
+
|
491
|
+
def test_seq_resets_pos
|
492
|
+
gram = KPeg.grammar do |g|
|
493
|
+
g.root = g.seq("hello", "world")
|
494
|
+
end
|
495
|
+
|
496
|
+
cg = KPeg::CodeGenerator.new "Test", gram
|
497
|
+
|
498
|
+
code = cg.make("helloworld")
|
499
|
+
assert code.parse
|
500
|
+
|
501
|
+
code = cg.make("hellojello")
|
502
|
+
assert !code.parse
|
503
|
+
assert_equal 0, code.pos
|
504
|
+
end
|
505
|
+
|
506
|
+
def test_andp
|
507
|
+
gram = KPeg.grammar do |g|
|
508
|
+
g.root = g.andp("hello")
|
509
|
+
end
|
510
|
+
|
511
|
+
str = <<-STR
|
512
|
+
require 'kpeg/compiled_parser'
|
513
|
+
|
514
|
+
class Test < KPeg::CompiledParser
|
515
|
+
|
516
|
+
# root = &"hello"
|
517
|
+
def _root
|
518
|
+
_save = self.pos
|
519
|
+
_tmp = match_string("hello")
|
520
|
+
self.pos = _save
|
521
|
+
set_failed_rule :_root unless _tmp
|
522
|
+
return _tmp
|
523
|
+
end
|
524
|
+
|
525
|
+
Rules = {}
|
526
|
+
Rules[:_root] = rule_info("root", "&\\\"hello\\\"")
|
527
|
+
end
|
528
|
+
STR
|
529
|
+
|
530
|
+
cg = KPeg::CodeGenerator.new "Test", gram
|
531
|
+
|
532
|
+
assert_equal str, cg.output
|
533
|
+
|
534
|
+
code = cg.make("hello")
|
535
|
+
assert code.parse
|
536
|
+
assert_equal 0, code.pos
|
537
|
+
|
538
|
+
code = cg.make("jello")
|
539
|
+
assert !code.parse
|
540
|
+
assert_equal 0, code.pos
|
541
|
+
end
|
542
|
+
|
543
|
+
def test_andp_for_action
|
544
|
+
gram = KPeg.grammar do |g|
|
545
|
+
g.root = g.andp(g.action(" !defined? @fail "))
|
546
|
+
end
|
547
|
+
|
548
|
+
str = <<-STR
|
549
|
+
require 'kpeg/compiled_parser'
|
550
|
+
|
551
|
+
class Test < KPeg::CompiledParser
|
552
|
+
|
553
|
+
# root = &{ !defined? @fail }
|
554
|
+
def _root
|
555
|
+
_save = self.pos
|
556
|
+
_tmp = begin; !defined? @fail ; end
|
557
|
+
self.pos = _save
|
558
|
+
set_failed_rule :_root unless _tmp
|
559
|
+
return _tmp
|
560
|
+
end
|
561
|
+
|
562
|
+
Rules = {}
|
563
|
+
Rules[:_root] = rule_info("root", "&{ !defined? @fail }")
|
564
|
+
end
|
565
|
+
STR
|
566
|
+
|
567
|
+
cg = KPeg::CodeGenerator.new "Test", gram
|
568
|
+
|
569
|
+
assert_equal str, cg.output
|
570
|
+
|
571
|
+
code = cg.make("hello")
|
572
|
+
assert code.parse
|
573
|
+
assert_equal 0, code.pos
|
574
|
+
|
575
|
+
code = cg.make("jello")
|
576
|
+
code.instance_variable_set :@fail, true
|
577
|
+
assert !code.parse
|
578
|
+
assert_equal 0, code.pos
|
579
|
+
end
|
580
|
+
|
581
|
+
def test_notp
|
582
|
+
gram = KPeg.grammar do |g|
|
583
|
+
g.root = g.notp("hello")
|
584
|
+
end
|
585
|
+
|
586
|
+
str = <<-STR
|
587
|
+
require 'kpeg/compiled_parser'
|
588
|
+
|
589
|
+
class Test < KPeg::CompiledParser
|
590
|
+
|
591
|
+
# root = !"hello"
|
592
|
+
def _root
|
593
|
+
_save = self.pos
|
594
|
+
_tmp = match_string("hello")
|
595
|
+
_tmp = _tmp ? nil : true
|
596
|
+
self.pos = _save
|
597
|
+
set_failed_rule :_root unless _tmp
|
598
|
+
return _tmp
|
599
|
+
end
|
600
|
+
|
601
|
+
Rules = {}
|
602
|
+
Rules[:_root] = rule_info("root", "!\\\"hello\\\"")
|
603
|
+
end
|
604
|
+
STR
|
605
|
+
|
606
|
+
cg = KPeg::CodeGenerator.new "Test", gram
|
607
|
+
|
608
|
+
assert_equal str, cg.output
|
609
|
+
|
610
|
+
code = cg.make("hello")
|
611
|
+
assert !code.parse
|
612
|
+
assert_equal 0, code.pos
|
613
|
+
|
614
|
+
code = cg.make("jello")
|
615
|
+
assert code.parse
|
616
|
+
assert_equal 0, code.pos
|
617
|
+
end
|
618
|
+
|
619
|
+
def test_notp_for_action
|
620
|
+
gram = KPeg.grammar do |g|
|
621
|
+
g.root = g.notp(g.action(" defined? @fail "))
|
622
|
+
end
|
623
|
+
|
624
|
+
str = <<-STR
|
625
|
+
require 'kpeg/compiled_parser'
|
626
|
+
|
627
|
+
class Test < KPeg::CompiledParser
|
628
|
+
|
629
|
+
# root = !{ defined? @fail }
|
630
|
+
def _root
|
631
|
+
_save = self.pos
|
632
|
+
_tmp = begin; defined? @fail ; end
|
633
|
+
_tmp = _tmp ? nil : true
|
634
|
+
self.pos = _save
|
635
|
+
set_failed_rule :_root unless _tmp
|
636
|
+
return _tmp
|
637
|
+
end
|
638
|
+
|
639
|
+
Rules = {}
|
640
|
+
Rules[:_root] = rule_info("root", "!{ defined? @fail }")
|
641
|
+
end
|
642
|
+
STR
|
643
|
+
|
644
|
+
cg = KPeg::CodeGenerator.new "Test", gram
|
645
|
+
|
646
|
+
assert_equal str, cg.output
|
647
|
+
|
648
|
+
code = cg.make("hello")
|
649
|
+
assert code.parse
|
650
|
+
assert_equal 0, code.pos
|
651
|
+
|
652
|
+
code = cg.make("jello")
|
653
|
+
code.instance_variable_set :@fail, true
|
654
|
+
assert !code.parse
|
655
|
+
assert_equal 0, code.pos
|
656
|
+
end
|
657
|
+
|
658
|
+
|
659
|
+
def test_ref
|
660
|
+
gram = KPeg.grammar do |g|
|
661
|
+
g.greeting = "hello"
|
662
|
+
g.root = g.ref("greeting")
|
663
|
+
end
|
664
|
+
|
665
|
+
str = <<-STR
|
666
|
+
require 'kpeg/compiled_parser'
|
667
|
+
|
668
|
+
class Test < KPeg::CompiledParser
|
669
|
+
|
670
|
+
# greeting = "hello"
|
671
|
+
def _greeting
|
672
|
+
_tmp = match_string("hello")
|
673
|
+
set_failed_rule :_greeting unless _tmp
|
674
|
+
return _tmp
|
675
|
+
end
|
676
|
+
|
677
|
+
# root = greeting
|
678
|
+
def _root
|
679
|
+
_tmp = apply(:_greeting)
|
680
|
+
set_failed_rule :_root unless _tmp
|
681
|
+
return _tmp
|
682
|
+
end
|
683
|
+
|
684
|
+
Rules = {}
|
685
|
+
Rules[:_greeting] = rule_info("greeting", "\\\"hello\\\"")
|
686
|
+
Rules[:_root] = rule_info("root", "greeting")
|
687
|
+
end
|
688
|
+
STR
|
689
|
+
|
690
|
+
cg = KPeg::CodeGenerator.new "Test", gram
|
691
|
+
|
692
|
+
assert_equal str, cg.output
|
693
|
+
|
694
|
+
assert cg.parse("hello")
|
695
|
+
end
|
696
|
+
|
697
|
+
def test_invoke
|
698
|
+
gram = KPeg.grammar do |g|
|
699
|
+
g.greeting = "hello"
|
700
|
+
g.root = g.invoke("greeting")
|
701
|
+
end
|
702
|
+
|
703
|
+
str = <<-STR
|
704
|
+
require 'kpeg/compiled_parser'
|
705
|
+
|
706
|
+
class Test < KPeg::CompiledParser
|
707
|
+
|
708
|
+
# greeting = "hello"
|
709
|
+
def _greeting
|
710
|
+
_tmp = match_string("hello")
|
711
|
+
set_failed_rule :_greeting unless _tmp
|
712
|
+
return _tmp
|
713
|
+
end
|
714
|
+
|
715
|
+
# root = @greeting
|
716
|
+
def _root
|
717
|
+
_tmp = _greeting()
|
718
|
+
set_failed_rule :_root unless _tmp
|
719
|
+
return _tmp
|
720
|
+
end
|
721
|
+
|
722
|
+
Rules = {}
|
723
|
+
Rules[:_greeting] = rule_info("greeting", "\\\"hello\\\"")
|
724
|
+
Rules[:_root] = rule_info("root", "@greeting")
|
725
|
+
end
|
726
|
+
STR
|
727
|
+
|
728
|
+
cg = KPeg::CodeGenerator.new "Test", gram
|
729
|
+
|
730
|
+
assert_equal str, cg.output
|
731
|
+
|
732
|
+
assert cg.parse("hello")
|
733
|
+
end
|
734
|
+
|
735
|
+
def test_invoke_with_args
|
736
|
+
gram = KPeg.grammar do |g|
|
737
|
+
g.set("greeting", "hello", ["a", "b"])
|
738
|
+
g.root = g.invoke("greeting", "(1,2)")
|
739
|
+
end
|
740
|
+
|
741
|
+
str = <<-STR
|
742
|
+
require 'kpeg/compiled_parser'
|
743
|
+
|
744
|
+
class Test < KPeg::CompiledParser
|
745
|
+
|
746
|
+
# greeting = "hello"
|
747
|
+
def _greeting(a,b)
|
748
|
+
_tmp = match_string("hello")
|
749
|
+
set_failed_rule :_greeting unless _tmp
|
750
|
+
return _tmp
|
751
|
+
end
|
752
|
+
|
753
|
+
# root = greeting(1,2)
|
754
|
+
def _root
|
755
|
+
_tmp = _greeting(1,2)
|
756
|
+
set_failed_rule :_root unless _tmp
|
757
|
+
return _tmp
|
758
|
+
end
|
759
|
+
|
760
|
+
Rules = {}
|
761
|
+
Rules[:_greeting] = rule_info("greeting", "\\\"hello\\\"")
|
762
|
+
Rules[:_root] = rule_info("root", "greeting(1,2)")
|
763
|
+
end
|
764
|
+
STR
|
765
|
+
|
766
|
+
cg = KPeg::CodeGenerator.new "Test", gram
|
767
|
+
|
768
|
+
assert_equal str, cg.output
|
769
|
+
|
770
|
+
assert cg.parse("hello")
|
771
|
+
end
|
772
|
+
|
773
|
+
gram = <<-GRAM
|
774
|
+
greeting = "hello"
|
775
|
+
greeting2(a,b) = "hello"
|
776
|
+
GRAM
|
777
|
+
|
778
|
+
KPeg.compile gram, "TestParser", self
|
779
|
+
|
780
|
+
def test_foreign_invoke
|
781
|
+
gram = KPeg.grammar do |g|
|
782
|
+
g.add_foreign_grammar "blah", "TestKPegCodeGenerator::TestParser"
|
783
|
+
g.root = g.foreign_invoke("blah", "greeting")
|
784
|
+
end
|
785
|
+
|
786
|
+
str = <<-STR
|
787
|
+
require 'kpeg/compiled_parser'
|
788
|
+
|
789
|
+
class Test < KPeg::CompiledParser
|
790
|
+
def setup_foreign_grammar
|
791
|
+
@_grammar_blah = TestKPegCodeGenerator::TestParser.new(nil)
|
792
|
+
end
|
793
|
+
|
794
|
+
# root = %blah.greeting
|
795
|
+
def _root
|
796
|
+
_tmp = @_grammar_blah.external_invoke(self, :_greeting)
|
797
|
+
set_failed_rule :_root unless _tmp
|
798
|
+
return _tmp
|
799
|
+
end
|
800
|
+
|
801
|
+
Rules = {}
|
802
|
+
Rules[:_root] = rule_info("root", "%blah.greeting")
|
803
|
+
end
|
804
|
+
STR
|
805
|
+
|
806
|
+
cg = KPeg::CodeGenerator.new "Test", gram
|
807
|
+
|
808
|
+
assert_equal str, cg.output
|
809
|
+
|
810
|
+
assert cg.parse("hello")
|
811
|
+
end
|
812
|
+
|
813
|
+
def test_foreign_invoke_with_args
|
814
|
+
gram = KPeg.grammar do |g|
|
815
|
+
g.add_foreign_grammar "blah", "TestKPegCodeGenerator::TestParser"
|
816
|
+
g.root = g.foreign_invoke("blah", "greeting2", "(1,2)")
|
817
|
+
end
|
818
|
+
|
819
|
+
str = <<-STR
|
820
|
+
require 'kpeg/compiled_parser'
|
821
|
+
|
822
|
+
class Test < KPeg::CompiledParser
|
823
|
+
def setup_foreign_grammar
|
824
|
+
@_grammar_blah = TestKPegCodeGenerator::TestParser.new(nil)
|
825
|
+
end
|
826
|
+
|
827
|
+
# root = %blah.greeting2(1,2)
|
828
|
+
def _root
|
829
|
+
_tmp = @_grammar_blah.external_invoke(self, :_greeting2, 1,2)
|
830
|
+
set_failed_rule :_root unless _tmp
|
831
|
+
return _tmp
|
832
|
+
end
|
833
|
+
|
834
|
+
Rules = {}
|
835
|
+
Rules[:_root] = rule_info("root", "%blah.greeting2(1,2)")
|
836
|
+
end
|
837
|
+
STR
|
838
|
+
|
839
|
+
cg = KPeg::CodeGenerator.new "Test", gram
|
840
|
+
|
841
|
+
assert_equal str, cg.output
|
842
|
+
|
843
|
+
assert cg.parse("hello")
|
844
|
+
end
|
845
|
+
|
846
|
+
def test_tag
|
847
|
+
gram = KPeg.grammar do |g|
|
848
|
+
g.root = g.t g.str("hello"), "t"
|
849
|
+
end
|
850
|
+
|
851
|
+
str = <<-STR
|
852
|
+
require 'kpeg/compiled_parser'
|
853
|
+
|
854
|
+
class Test < KPeg::CompiledParser
|
855
|
+
|
856
|
+
# root = "hello":t
|
857
|
+
def _root
|
858
|
+
_tmp = match_string("hello")
|
859
|
+
t = @result
|
860
|
+
set_failed_rule :_root unless _tmp
|
861
|
+
return _tmp
|
862
|
+
end
|
863
|
+
|
864
|
+
Rules = {}
|
865
|
+
Rules[:_root] = rule_info("root", "\\\"hello\\\":t")
|
866
|
+
end
|
867
|
+
STR
|
868
|
+
|
869
|
+
cg = KPeg::CodeGenerator.new "Test", gram
|
870
|
+
|
871
|
+
assert_equal str, cg.output
|
872
|
+
end
|
873
|
+
|
874
|
+
def test_noname_tag
|
875
|
+
gram = KPeg.grammar do |g|
|
876
|
+
g.root = g.t g.str("hello")
|
877
|
+
end
|
878
|
+
|
879
|
+
str = <<-STR
|
880
|
+
require 'kpeg/compiled_parser'
|
881
|
+
|
882
|
+
class Test < KPeg::CompiledParser
|
883
|
+
|
884
|
+
# root = "hello"
|
885
|
+
def _root
|
886
|
+
_tmp = match_string("hello")
|
887
|
+
set_failed_rule :_root unless _tmp
|
888
|
+
return _tmp
|
889
|
+
end
|
890
|
+
|
891
|
+
Rules = {}
|
892
|
+
Rules[:_root] = rule_info("root", "\\\"hello\\\"")
|
893
|
+
end
|
894
|
+
STR
|
895
|
+
|
896
|
+
cg = KPeg::CodeGenerator.new "Test", gram
|
897
|
+
|
898
|
+
assert_equal str, cg.output
|
899
|
+
end
|
900
|
+
|
901
|
+
def test_tag_maybe
|
902
|
+
gram = KPeg.grammar do |g|
|
903
|
+
g.hello = g.seq(g.collect("hello"), g.action("text"))
|
904
|
+
g.root = g.seq g.t(g.maybe(:hello), "lots"), g.action("lots")
|
905
|
+
end
|
906
|
+
|
907
|
+
str = <<-STR
|
908
|
+
require 'kpeg/compiled_parser'
|
909
|
+
|
910
|
+
class Test < KPeg::CompiledParser
|
911
|
+
|
912
|
+
# hello = < "hello" > {text}
|
913
|
+
def _hello
|
914
|
+
|
915
|
+
_save = self.pos
|
916
|
+
while true # sequence
|
917
|
+
_text_start = self.pos
|
918
|
+
_tmp = match_string("hello")
|
919
|
+
if _tmp
|
920
|
+
text = get_text(_text_start)
|
921
|
+
end
|
922
|
+
unless _tmp
|
923
|
+
self.pos = _save
|
924
|
+
break
|
925
|
+
end
|
926
|
+
@result = begin; text; end
|
927
|
+
_tmp = true
|
928
|
+
unless _tmp
|
929
|
+
self.pos = _save
|
930
|
+
end
|
931
|
+
break
|
932
|
+
end # end sequence
|
933
|
+
|
934
|
+
set_failed_rule :_hello unless _tmp
|
935
|
+
return _tmp
|
936
|
+
end
|
937
|
+
|
938
|
+
# root = hello?:lots {lots}
|
939
|
+
def _root
|
940
|
+
|
941
|
+
_save = self.pos
|
942
|
+
while true # sequence
|
943
|
+
_save1 = self.pos
|
944
|
+
_tmp = apply(:_hello)
|
945
|
+
@result = nil unless _tmp
|
946
|
+
unless _tmp
|
947
|
+
_tmp = true
|
948
|
+
self.pos = _save1
|
949
|
+
end
|
950
|
+
lots = @result
|
951
|
+
unless _tmp
|
952
|
+
self.pos = _save
|
953
|
+
break
|
954
|
+
end
|
955
|
+
@result = begin; lots; end
|
956
|
+
_tmp = true
|
957
|
+
unless _tmp
|
958
|
+
self.pos = _save
|
959
|
+
end
|
960
|
+
break
|
961
|
+
end # end sequence
|
962
|
+
|
963
|
+
set_failed_rule :_root unless _tmp
|
964
|
+
return _tmp
|
965
|
+
end
|
966
|
+
|
967
|
+
Rules = {}
|
968
|
+
Rules[:_hello] = rule_info("hello", "< \\\"hello\\\" > {text}")
|
969
|
+
Rules[:_root] = rule_info("root", "hello?:lots {lots}")
|
970
|
+
end
|
971
|
+
STR
|
972
|
+
|
973
|
+
cg = KPeg::CodeGenerator.new "Test", gram
|
974
|
+
|
975
|
+
assert_equal str, cg.output
|
976
|
+
|
977
|
+
code = cg.make("hello")
|
978
|
+
assert code.parse
|
979
|
+
assert_equal "hello", code.result
|
980
|
+
|
981
|
+
code = cg.make("")
|
982
|
+
assert code.parse
|
983
|
+
assert_equal nil, code.result
|
984
|
+
end
|
985
|
+
|
986
|
+
|
987
|
+
def test_tag_multiple
|
988
|
+
gram = KPeg.grammar do |g|
|
989
|
+
g.hello = g.seq(g.collect("hello"), g.action("text"))
|
990
|
+
g.root = g.seq g.t(g.kleene(:hello), "lots"), g.action("lots")
|
991
|
+
end
|
992
|
+
|
993
|
+
str = <<-STR
|
994
|
+
require 'kpeg/compiled_parser'
|
995
|
+
|
996
|
+
class Test < KPeg::CompiledParser
|
997
|
+
|
998
|
+
# hello = < "hello" > {text}
|
999
|
+
def _hello
|
1000
|
+
|
1001
|
+
_save = self.pos
|
1002
|
+
while true # sequence
|
1003
|
+
_text_start = self.pos
|
1004
|
+
_tmp = match_string("hello")
|
1005
|
+
if _tmp
|
1006
|
+
text = get_text(_text_start)
|
1007
|
+
end
|
1008
|
+
unless _tmp
|
1009
|
+
self.pos = _save
|
1010
|
+
break
|
1011
|
+
end
|
1012
|
+
@result = begin; text; end
|
1013
|
+
_tmp = true
|
1014
|
+
unless _tmp
|
1015
|
+
self.pos = _save
|
1016
|
+
end
|
1017
|
+
break
|
1018
|
+
end # end sequence
|
1019
|
+
|
1020
|
+
set_failed_rule :_hello unless _tmp
|
1021
|
+
return _tmp
|
1022
|
+
end
|
1023
|
+
|
1024
|
+
# root = hello*:lots {lots}
|
1025
|
+
def _root
|
1026
|
+
|
1027
|
+
_save = self.pos
|
1028
|
+
while true # sequence
|
1029
|
+
_ary = []
|
1030
|
+
while true
|
1031
|
+
_tmp = apply(:_hello)
|
1032
|
+
_ary << @result if _tmp
|
1033
|
+
break unless _tmp
|
1034
|
+
end
|
1035
|
+
_tmp = true
|
1036
|
+
@result = _ary
|
1037
|
+
lots = @result
|
1038
|
+
unless _tmp
|
1039
|
+
self.pos = _save
|
1040
|
+
break
|
1041
|
+
end
|
1042
|
+
@result = begin; lots; end
|
1043
|
+
_tmp = true
|
1044
|
+
unless _tmp
|
1045
|
+
self.pos = _save
|
1046
|
+
end
|
1047
|
+
break
|
1048
|
+
end # end sequence
|
1049
|
+
|
1050
|
+
set_failed_rule :_root unless _tmp
|
1051
|
+
return _tmp
|
1052
|
+
end
|
1053
|
+
|
1054
|
+
Rules = {}
|
1055
|
+
Rules[:_hello] = rule_info("hello", "< \\\"hello\\\" > {text}")
|
1056
|
+
Rules[:_root] = rule_info("root", "hello*:lots {lots}")
|
1057
|
+
end
|
1058
|
+
STR
|
1059
|
+
|
1060
|
+
cg = KPeg::CodeGenerator.new "Test", gram
|
1061
|
+
|
1062
|
+
assert_equal str, cg.output
|
1063
|
+
|
1064
|
+
code = cg.make("hellohello")
|
1065
|
+
assert code.parse
|
1066
|
+
assert_equal ["hello", "hello"], code.result
|
1067
|
+
|
1068
|
+
code = cg.make("hello")
|
1069
|
+
assert code.parse
|
1070
|
+
assert_equal ["hello"], code.result
|
1071
|
+
|
1072
|
+
code = cg.make("")
|
1073
|
+
assert code.parse
|
1074
|
+
assert_equal [], code.result
|
1075
|
+
end
|
1076
|
+
|
1077
|
+
def test_tag_many
|
1078
|
+
gram = KPeg.grammar do |g|
|
1079
|
+
g.hello = g.seq(g.collect("hello"), g.action("text"))
|
1080
|
+
g.root = g.seq g.t(g.many(:hello), "lots"), g.action("lots")
|
1081
|
+
end
|
1082
|
+
|
1083
|
+
str = <<-STR
|
1084
|
+
require 'kpeg/compiled_parser'
|
1085
|
+
|
1086
|
+
class Test < KPeg::CompiledParser
|
1087
|
+
|
1088
|
+
# hello = < "hello" > {text}
|
1089
|
+
def _hello
|
1090
|
+
|
1091
|
+
_save = self.pos
|
1092
|
+
while true # sequence
|
1093
|
+
_text_start = self.pos
|
1094
|
+
_tmp = match_string("hello")
|
1095
|
+
if _tmp
|
1096
|
+
text = get_text(_text_start)
|
1097
|
+
end
|
1098
|
+
unless _tmp
|
1099
|
+
self.pos = _save
|
1100
|
+
break
|
1101
|
+
end
|
1102
|
+
@result = begin; text; end
|
1103
|
+
_tmp = true
|
1104
|
+
unless _tmp
|
1105
|
+
self.pos = _save
|
1106
|
+
end
|
1107
|
+
break
|
1108
|
+
end # end sequence
|
1109
|
+
|
1110
|
+
set_failed_rule :_hello unless _tmp
|
1111
|
+
return _tmp
|
1112
|
+
end
|
1113
|
+
|
1114
|
+
# root = hello+:lots {lots}
|
1115
|
+
def _root
|
1116
|
+
|
1117
|
+
_save = self.pos
|
1118
|
+
while true # sequence
|
1119
|
+
_save1 = self.pos
|
1120
|
+
_ary = []
|
1121
|
+
_tmp = apply(:_hello)
|
1122
|
+
if _tmp
|
1123
|
+
_ary << @result
|
1124
|
+
while true
|
1125
|
+
_tmp = apply(:_hello)
|
1126
|
+
_ary << @result if _tmp
|
1127
|
+
break unless _tmp
|
1128
|
+
end
|
1129
|
+
_tmp = true
|
1130
|
+
@result = _ary
|
1131
|
+
else
|
1132
|
+
self.pos = _save1
|
1133
|
+
end
|
1134
|
+
lots = @result
|
1135
|
+
unless _tmp
|
1136
|
+
self.pos = _save
|
1137
|
+
break
|
1138
|
+
end
|
1139
|
+
@result = begin; lots; end
|
1140
|
+
_tmp = true
|
1141
|
+
unless _tmp
|
1142
|
+
self.pos = _save
|
1143
|
+
end
|
1144
|
+
break
|
1145
|
+
end # end sequence
|
1146
|
+
|
1147
|
+
set_failed_rule :_root unless _tmp
|
1148
|
+
return _tmp
|
1149
|
+
end
|
1150
|
+
|
1151
|
+
Rules = {}
|
1152
|
+
Rules[:_hello] = rule_info("hello", "< \\\"hello\\\" > {text}")
|
1153
|
+
Rules[:_root] = rule_info("root", "hello+:lots {lots}")
|
1154
|
+
end
|
1155
|
+
STR
|
1156
|
+
|
1157
|
+
cg = KPeg::CodeGenerator.new "Test", gram
|
1158
|
+
|
1159
|
+
assert_equal str, cg.output
|
1160
|
+
|
1161
|
+
code = cg.make("hellohello")
|
1162
|
+
assert code.parse
|
1163
|
+
assert_equal ["hello", "hello"], code.result
|
1164
|
+
|
1165
|
+
code = cg.make("hello")
|
1166
|
+
assert code.parse
|
1167
|
+
assert_equal ["hello"], code.result
|
1168
|
+
|
1169
|
+
code = cg.make("")
|
1170
|
+
assert !code.parse
|
1171
|
+
end
|
1172
|
+
|
1173
|
+
def test_action
|
1174
|
+
gram = KPeg.grammar do |g|
|
1175
|
+
g.root = g.action "3 + 4"
|
1176
|
+
end
|
1177
|
+
|
1178
|
+
str = <<-STR
|
1179
|
+
require 'kpeg/compiled_parser'
|
1180
|
+
|
1181
|
+
class Test < KPeg::CompiledParser
|
1182
|
+
|
1183
|
+
# root = {3 + 4}
|
1184
|
+
def _root
|
1185
|
+
@result = begin; 3 + 4; end
|
1186
|
+
_tmp = true
|
1187
|
+
set_failed_rule :_root unless _tmp
|
1188
|
+
return _tmp
|
1189
|
+
end
|
1190
|
+
|
1191
|
+
Rules = {}
|
1192
|
+
Rules[:_root] = rule_info("root", "{3 + 4}")
|
1193
|
+
end
|
1194
|
+
STR
|
1195
|
+
|
1196
|
+
cg = KPeg::CodeGenerator.new "Test", gram
|
1197
|
+
|
1198
|
+
assert_equal str, cg.output
|
1199
|
+
|
1200
|
+
code = cg.make("")
|
1201
|
+
assert code.parse
|
1202
|
+
assert_equal 7, code.result
|
1203
|
+
end
|
1204
|
+
|
1205
|
+
def test_collect
|
1206
|
+
gram = KPeg.grammar do |g|
|
1207
|
+
g.root = g.seq(g.collect("hello"), g.action(" text "))
|
1208
|
+
end
|
1209
|
+
|
1210
|
+
str = <<-STR
|
1211
|
+
require 'kpeg/compiled_parser'
|
1212
|
+
|
1213
|
+
class Test < KPeg::CompiledParser
|
1214
|
+
|
1215
|
+
# root = < "hello" > { text }
|
1216
|
+
def _root
|
1217
|
+
|
1218
|
+
_save = self.pos
|
1219
|
+
while true # sequence
|
1220
|
+
_text_start = self.pos
|
1221
|
+
_tmp = match_string("hello")
|
1222
|
+
if _tmp
|
1223
|
+
text = get_text(_text_start)
|
1224
|
+
end
|
1225
|
+
unless _tmp
|
1226
|
+
self.pos = _save
|
1227
|
+
break
|
1228
|
+
end
|
1229
|
+
@result = begin; text ; end
|
1230
|
+
_tmp = true
|
1231
|
+
unless _tmp
|
1232
|
+
self.pos = _save
|
1233
|
+
end
|
1234
|
+
break
|
1235
|
+
end # end sequence
|
1236
|
+
|
1237
|
+
set_failed_rule :_root unless _tmp
|
1238
|
+
return _tmp
|
1239
|
+
end
|
1240
|
+
|
1241
|
+
Rules = {}
|
1242
|
+
Rules[:_root] = rule_info("root", "< \\\"hello\\\" > { text }")
|
1243
|
+
end
|
1244
|
+
STR
|
1245
|
+
|
1246
|
+
cg = KPeg::CodeGenerator.new "Test", gram
|
1247
|
+
|
1248
|
+
assert_equal str, cg.output
|
1249
|
+
|
1250
|
+
code = cg.make("hello")
|
1251
|
+
assert code.parse
|
1252
|
+
assert_equal "hello", code.result
|
1253
|
+
end
|
1254
|
+
|
1255
|
+
def test_parse_error
|
1256
|
+
gram = KPeg.grammar do |g|
|
1257
|
+
g.world = "world"
|
1258
|
+
g.root = g.seq("hello", :world)
|
1259
|
+
end
|
1260
|
+
|
1261
|
+
cg = KPeg::CodeGenerator.new "Test", gram
|
1262
|
+
|
1263
|
+
code = cg.make("no")
|
1264
|
+
assert !code.parse
|
1265
|
+
assert_equal 0, code.failing_rule_offset
|
1266
|
+
|
1267
|
+
cg2 = KPeg::CodeGenerator.new "Test", gram
|
1268
|
+
|
1269
|
+
code = cg2.make("hellono")
|
1270
|
+
assert !code.parse
|
1271
|
+
assert_equal 5, code.failing_rule_offset
|
1272
|
+
end
|
1273
|
+
|
1274
|
+
def test_setup_actions
|
1275
|
+
gram = KPeg.grammar do |g|
|
1276
|
+
g.root = g.dot
|
1277
|
+
g.add_setup g.action(" attr_reader :foo ")
|
1278
|
+
end
|
1279
|
+
|
1280
|
+
str = <<-STR
|
1281
|
+
require 'kpeg/compiled_parser'
|
1282
|
+
|
1283
|
+
class Test < KPeg::CompiledParser
|
1284
|
+
|
1285
|
+
attr_reader :foo
|
1286
|
+
|
1287
|
+
|
1288
|
+
# root = .
|
1289
|
+
def _root
|
1290
|
+
_tmp = get_byte
|
1291
|
+
set_failed_rule :_root unless _tmp
|
1292
|
+
return _tmp
|
1293
|
+
end
|
1294
|
+
|
1295
|
+
Rules = {}
|
1296
|
+
Rules[:_root] = rule_info("root", ".")
|
1297
|
+
end
|
1298
|
+
STR
|
1299
|
+
|
1300
|
+
cg = KPeg::CodeGenerator.new "Test", gram
|
1301
|
+
|
1302
|
+
assert_equal str, cg.output
|
1303
|
+
|
1304
|
+
assert cg.parse("hello")
|
1305
|
+
end
|
1306
|
+
|
1307
|
+
end
|