yaparc 0.1.5 → 0.1.6
Sign up to get free protection for your applications and to get access to all the features.
- data/README +1 -11
- data/lib/yaparc.rb +253 -89
- data/tests/abc20bnf.txt +264 -0
- data/tests/test_abc.rb +113 -0
- data/tests/test_calc.rb +10 -5
- data/tests/test_owl.rb +68 -0
- data/tests/test_parser.rb +89 -25
- data/tests/test_sql.rb +10 -10
- data/tests/test_uri.rb +752 -0
- metadata +9 -2
data/README
CHANGED
@@ -138,17 +138,7 @@ The ManyOneParser requires at least one successfull application of parser.
|
|
138
138
|
|
139
139
|
== Define your own parser
|
140
140
|
|
141
|
-
|
142
|
-
There are two ways to construct parser. One is to inherit from Yaparc::ParserBase class.
|
143
|
-
|
144
|
-
class StringMatch < Yaparc::ParserBase
|
145
|
-
|
146
|
-
def initialize(literal)
|
147
|
-
@parser = Yaparc::Token.new(Yaparc::StringParser.new(literal))
|
148
|
-
end
|
149
|
-
end
|
150
|
-
|
151
|
-
The other is to inherit from Yaparc::AbstractParser class.
|
141
|
+
In order to construct parsers, you make parser class to be inherited from Yaparc::AbstractParser class.
|
152
142
|
|
153
143
|
class Identifier < Yaparc::AbstractParser
|
154
144
|
def initialize
|
data/lib/yaparc.rb
CHANGED
@@ -39,12 +39,10 @@ module Yaparc
|
|
39
39
|
result = result.parse(input)
|
40
40
|
else
|
41
41
|
if block_given?
|
42
|
-
# @tree = yield result.value
|
43
42
|
result.value = yield result.value
|
44
43
|
@tree = result
|
45
44
|
else
|
46
45
|
@tree = result.value
|
47
|
-
# @tree = result.parse(input)
|
48
46
|
end
|
49
47
|
result
|
50
48
|
end
|
@@ -59,11 +57,11 @@ module Yaparc
|
|
59
57
|
def included(mod)
|
60
58
|
end
|
61
59
|
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
60
|
+
# def define_parser(&block)
|
61
|
+
# @@cparser = lambda do
|
62
|
+
# yield
|
63
|
+
# end
|
64
|
+
# end
|
67
65
|
end
|
68
66
|
end # of Module Parsable
|
69
67
|
|
@@ -104,6 +102,33 @@ module Yaparc
|
|
104
102
|
end
|
105
103
|
end
|
106
104
|
|
105
|
+
class ZeroOneParser
|
106
|
+
include Parsable
|
107
|
+
def initialize(parser, identity = [])
|
108
|
+
@parser = lambda do |input|
|
109
|
+
case result = parser.parse(input)
|
110
|
+
when Result::Fail
|
111
|
+
SucceedParser.new(identity)
|
112
|
+
when Result::Error
|
113
|
+
Result::Error.new(:value => result.value, :input => result.input)
|
114
|
+
when Result::OK
|
115
|
+
result
|
116
|
+
else
|
117
|
+
raise
|
118
|
+
end
|
119
|
+
|
120
|
+
# AltParser.new(parser, SucceedParser.new(identity))
|
121
|
+
# case result = AltParser.new(parser, SucceedParser.new(identity)).parse(input)
|
122
|
+
# if input.nil? or input.empty?
|
123
|
+
# Result::Fail.new(:input => input)
|
124
|
+
# else
|
125
|
+
# Result::OK.new(:value => input[0..0],:input => input[1..input.length])
|
126
|
+
# end
|
127
|
+
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
107
132
|
class SatisfyParser
|
108
133
|
include Parsable
|
109
134
|
def initialize(predicate)
|
@@ -197,7 +222,8 @@ module Yaparc
|
|
197
222
|
initial_result = Result::OK.new(:input => input)
|
198
223
|
final_result = Result::Fail.new(:input => input)
|
199
224
|
parsers.each do |parser|
|
200
|
-
case result = parser.parse(initial_result.input)
|
225
|
+
# case result = parser.parse(initial_result.input)
|
226
|
+
case result = parser.parse(input)
|
201
227
|
when Result::Fail
|
202
228
|
next
|
203
229
|
when Result::Error
|
@@ -256,32 +282,60 @@ module Yaparc
|
|
256
282
|
|
257
283
|
class RegexParser
|
258
284
|
include Parsable
|
259
|
-
|
260
|
-
def initialize(regex)
|
285
|
+
|
286
|
+
def initialize(regex, &block)
|
287
|
+
@regex = regex
|
261
288
|
@parser = lambda do |input|
|
262
289
|
if match = Regexp.new(regex).match(input)
|
263
|
-
|
290
|
+
if block_given?
|
291
|
+
SucceedParser.new(yield(*match.to_a[1..match.to_a.length])).parse(match.post_match)
|
292
|
+
else
|
293
|
+
Result::OK.new(:value => match[0], :input => match.post_match)
|
294
|
+
end
|
264
295
|
else
|
265
296
|
Result::Fail.new(:input => input)
|
266
297
|
end
|
267
298
|
end
|
268
299
|
end
|
300
|
+
|
301
|
+
def parse_with_parameter(input)
|
302
|
+
if match = Regexp.new(@regex).match(input)
|
303
|
+
if block_given?
|
304
|
+
yield match.to_a[1..match.to_a.length]
|
305
|
+
else
|
306
|
+
Result::OK.new(:value => match, :input => match.post_match)
|
307
|
+
end
|
308
|
+
else
|
309
|
+
Result::Fail.new(:input => input)
|
310
|
+
end
|
311
|
+
end
|
269
312
|
end
|
313
|
+
# class RegexParser
|
314
|
+
# include Parsable
|
315
|
+
|
316
|
+
# def initialize(regex)
|
317
|
+
# @parser = lambda do |input|
|
318
|
+
# if match = Regexp.new(regex).match(input)
|
319
|
+
# Result::OK.new(:value => match[0], :input => match.post_match)
|
320
|
+
# else
|
321
|
+
# Result::Fail.new(:input => input)
|
322
|
+
# end
|
323
|
+
# end
|
324
|
+
# end
|
325
|
+
# end
|
270
326
|
|
271
327
|
# permits zero or more applications of parser.
|
272
328
|
class ManyParser
|
273
329
|
include Parsable
|
274
|
-
# def initialize(parser, identity = "")
|
275
330
|
def initialize(parser, identity = [])
|
276
331
|
@parser = lambda do |input|
|
277
|
-
# AltParser.new(ManyOneParser.new(parser, identity), SucceedParser.new(identity)).parse(input)
|
278
332
|
AltParser.new(ManyOneParser.new(parser, identity), SucceedParser.new(identity))
|
279
333
|
end
|
280
334
|
end
|
281
335
|
|
282
|
-
|
283
|
-
|
284
|
-
|
336
|
+
# def parse(input)
|
337
|
+
# @parser.call(input).parse(input)
|
338
|
+
# end
|
285
339
|
end
|
286
340
|
|
287
341
|
# requires at least one successfull application of parser.
|
@@ -303,107 +357,91 @@ module Yaparc
|
|
303
357
|
end
|
304
358
|
end
|
305
359
|
|
306
|
-
class ParserBase
|
307
|
-
include Parsable
|
308
|
-
|
309
|
-
def parse(input)
|
310
|
-
@parser.parse(input)
|
311
|
-
end
|
312
|
-
end
|
313
360
|
|
314
|
-
class CharParser < ParserBase
|
315
361
|
|
316
|
-
def initialize(char)
|
317
|
-
equal_char = lambda {|i| i == char}
|
318
|
-
@parser = SatisfyParser.new(equal_char)
|
319
|
-
end
|
320
|
-
end
|
321
|
-
|
322
|
-
class ZeroOneParser < ParserBase
|
323
|
-
def initialize(parser)
|
324
|
-
@parser = AltParser.new(parser, SucceedParser.new([])) # Is it OK?
|
325
|
-
end
|
326
|
-
end
|
327
362
|
|
328
|
-
class
|
329
|
-
|
330
|
-
@parser = SeqParser.new(
|
331
|
-
SatisfyParser.new(IS_LOWER),
|
332
|
-
ManyParser.new(SatisfyParser.new(IS_ALPHANUM),"")
|
333
|
-
) do |head, tail|
|
334
|
-
head + tail
|
335
|
-
end
|
336
|
-
end
|
337
|
-
end
|
338
|
-
|
339
|
-
class Nat < ParserBase
|
340
|
-
def initialize
|
341
|
-
@parser = SeqParser.new(ManyOneParser.new(SatisfyParser.new(IS_DIGIT),"")) do |vs|
|
342
|
-
if vs == ""
|
343
|
-
vs
|
344
|
-
else
|
345
|
-
vs.to_i
|
346
|
-
end
|
347
|
-
end
|
348
|
-
end
|
349
|
-
end
|
350
|
-
|
351
|
-
|
352
|
-
class Space < ParserBase
|
363
|
+
class SpaceParser
|
364
|
+
include Parsable
|
353
365
|
def initialize
|
354
|
-
@parser =
|
355
|
-
|
366
|
+
@parser = lambda do |input|
|
367
|
+
SeqParser.new(ManyParser.new(SatisfyParser.new(IS_SPACE),""))
|
356
368
|
end
|
357
369
|
end
|
358
370
|
end
|
359
371
|
|
360
|
-
class
|
372
|
+
class WhiteSpaceParser
|
373
|
+
include Parsable
|
361
374
|
def initialize
|
362
|
-
@parser =
|
363
|
-
|
375
|
+
@parser = lambda do |input|
|
376
|
+
SeqParser.new(ManyParser.new(SatisfyParser.new(IS_WHITESPACE),''))
|
364
377
|
end
|
365
378
|
end
|
366
379
|
end
|
367
380
|
|
368
|
-
class
|
381
|
+
class TokenizeParser
|
382
|
+
include Parsable
|
369
383
|
attr_accessor :prefix, :postfix
|
370
384
|
|
371
|
-
def initialize(parser,
|
372
|
-
@
|
373
|
-
|
374
|
-
|
385
|
+
def initialize(parser, args = { }, &block)
|
386
|
+
@parser = lambda do |input|
|
387
|
+
@prefix = args[:prefix] ? args[:prefix] : WhiteSpaceParser.new
|
388
|
+
@postfix = args[:postfix] ? args[:postfix] : WhiteSpaceParser.new
|
389
|
+
if block_given?
|
390
|
+
yield self
|
391
|
+
SeqParser.new(@prefix, parser, @postfix) do |_, vs, _|
|
392
|
+
vs
|
393
|
+
end
|
394
|
+
else
|
395
|
+
SeqParser.new(@prefix, parser, @postfix) do |_, vs, _|
|
396
|
+
vs
|
397
|
+
end
|
398
|
+
end
|
375
399
|
end
|
376
400
|
end
|
377
401
|
end
|
378
402
|
|
379
|
-
|
380
|
-
|
403
|
+
# class Tokenize < ParserBase
|
404
|
+
# attr_accessor :prefix, :postfix
|
381
405
|
|
382
|
-
|
383
|
-
|
384
|
-
|
385
|
-
|
386
|
-
|
406
|
+
# def initialize(parser, &block)
|
407
|
+
# @prefix, @postfix = WhiteSpace.new,WhiteSpace.new
|
408
|
+
# yield self
|
409
|
+
# @parser = SeqParser.new(@prefix, parser, @postfix) do |_, vs, _|
|
410
|
+
# vs
|
411
|
+
# end
|
412
|
+
# end
|
413
|
+
# end
|
414
|
+
|
415
|
+
class LiteralParser
|
416
|
+
include Parsable
|
417
|
+
def initialize(literal)
|
418
|
+
@parser = lambda do |input|
|
419
|
+
TokenizeParser.new(StringParser.new(literal))
|
387
420
|
end
|
388
421
|
end
|
389
422
|
end
|
390
423
|
|
391
424
|
# Refer to http://www.cs.nott.ac.uk/~gmh/monparsing.pdf, p.23
|
425
|
+
|
392
426
|
class Identifier
|
393
|
-
include Parsable
|
427
|
+
include Yaparc::Parsable
|
428
|
+
@@identifier_regex = ::Yaparc::RegexParser.new(/\A[a-zA-Z_]+[a-zA-Z0-9_]*/)
|
429
|
+
|
394
430
|
def initialize(*keywords)
|
395
431
|
if keywords == []
|
396
432
|
@parser = lambda do |input|
|
397
|
-
|
433
|
+
TokenizeParser.new(@@identifier_regex)
|
434
|
+
# Yaparc::Token.new(@@identifier_regex)
|
398
435
|
end
|
399
436
|
else
|
400
437
|
@parser = lambda do |input|
|
401
|
-
keyword_parsers = keywords.map {|keyword| StringParser.new(keyword)}
|
402
|
-
case result = AltParser.new(*keyword_parsers).parse(input)
|
403
|
-
when Result::OK
|
404
|
-
FailParser.new
|
438
|
+
keyword_parsers = keywords.map {|keyword| Yaparc::StringParser.new(keyword)}
|
439
|
+
case result = Yaparc::AltParser.new(*keyword_parsers).parse(input)
|
440
|
+
when Yaparc::Result::OK
|
441
|
+
Yaparc::FailParser.new
|
405
442
|
else # Result::Fail or Result::Error
|
406
|
-
|
443
|
+
TokenizeParser.new(@@identifier_regex)
|
444
|
+
# Yaparc::Token.new(@@identifier_regex)
|
407
445
|
end
|
408
446
|
end
|
409
447
|
end
|
@@ -414,22 +452,148 @@ module Yaparc
|
|
414
452
|
end
|
415
453
|
end
|
416
454
|
|
455
|
+
# class ParserBase
|
456
|
+
# include Parsable
|
457
|
+
|
458
|
+
# def parse(input)
|
459
|
+
# @parser.parse(input)
|
460
|
+
# end
|
461
|
+
# end
|
462
|
+
|
463
|
+
class CharParser
|
464
|
+
include Parsable
|
465
|
+
|
466
|
+
def initialize(char)
|
467
|
+
equal_char = lambda {|i| i == char}
|
468
|
+
@parser = lambda do |input|
|
469
|
+
SatisfyParser.new(equal_char)
|
470
|
+
end
|
471
|
+
end
|
472
|
+
end
|
473
|
+
# class CharParser < ParserBase
|
474
|
+
|
475
|
+
# def initialize(char)
|
476
|
+
# equal_char = lambda {|i| i == char}
|
477
|
+
# @parser = SatisfyParser.new(equal_char)
|
478
|
+
# end
|
479
|
+
# end
|
417
480
|
|
418
|
-
|
481
|
+
# class ZeroOneParser < ParserBase
|
482
|
+
# def initialize(parser, identity = [])
|
483
|
+
# @parser = AltParser.new(parser, SucceedParser.new(identity)) # Is it OK?
|
484
|
+
# end
|
485
|
+
# end
|
419
486
|
|
487
|
+
class Ident
|
488
|
+
include Parsable
|
489
|
+
def initialize
|
490
|
+
@parser = lambda do |input|
|
491
|
+
SeqParser.new(
|
492
|
+
SatisfyParser.new(IS_LOWER),
|
493
|
+
ManyParser.new(SatisfyParser.new(IS_ALPHANUM),"")
|
494
|
+
) do |head, tail|
|
495
|
+
head + tail
|
496
|
+
end
|
497
|
+
end
|
498
|
+
end
|
499
|
+
end
|
500
|
+
# class Ident < ParserBase
|
501
|
+
# def initialize
|
502
|
+
# @parser = SeqParser.new(
|
503
|
+
# SatisfyParser.new(IS_LOWER),
|
504
|
+
# ManyParser.new(SatisfyParser.new(IS_ALPHANUM),"")
|
505
|
+
# ) do |head, tail|
|
506
|
+
# head + tail
|
507
|
+
# end
|
508
|
+
# end
|
509
|
+
# end
|
510
|
+
|
511
|
+
class Nat
|
512
|
+
include Parsable
|
420
513
|
def initialize
|
421
|
-
@parser =
|
514
|
+
@parser = lambda do |input|
|
515
|
+
SeqParser.new(ManyOneParser.new(SatisfyParser.new(IS_DIGIT),"")) do |vs|
|
516
|
+
if vs == ""
|
517
|
+
vs
|
518
|
+
else
|
519
|
+
vs.to_i
|
520
|
+
end
|
521
|
+
end
|
522
|
+
end
|
523
|
+
end
|
524
|
+
end
|
525
|
+
|
526
|
+
# class Nat < ParserBase
|
527
|
+
# def initialize
|
528
|
+
# @parser = SeqParser.new(ManyOneParser.new(SatisfyParser.new(IS_DIGIT),"")) do |vs|
|
529
|
+
# if vs == ""
|
530
|
+
# vs
|
531
|
+
# else
|
532
|
+
# vs.to_i
|
533
|
+
# end
|
534
|
+
# end
|
535
|
+
# end
|
536
|
+
# end
|
537
|
+
|
538
|
+
# class Space < ParserBase
|
539
|
+
# def initialize
|
540
|
+
# @parser = SeqParser.new(ManyParser.new(SatisfyParser.new(IS_SPACE),"")) do |vs|
|
541
|
+
# SucceedParser.new([])
|
542
|
+
# end
|
543
|
+
# end
|
544
|
+
# end
|
545
|
+
|
546
|
+
# class WhiteSpace < ParserBase
|
547
|
+
# def initialize
|
548
|
+
# @parser = SeqParser.new(ManyParser.new(SatisfyParser.new(IS_WHITESPACE),"")) do |vs|
|
549
|
+
# SucceedParser.new([])
|
550
|
+
# end
|
551
|
+
# end
|
552
|
+
# end
|
553
|
+
|
554
|
+
# class Token < ParserBase
|
555
|
+
# attr_accessor :prefix, :postfix
|
556
|
+
|
557
|
+
# def initialize(parser, prefix = WhiteSpace.new, postfix = WhiteSpace.new)
|
558
|
+
# @prefix, @postfix = prefix, postfix
|
559
|
+
# @parser = SeqParser.new(@prefix, parser, @postfix) do |_, vs, _|
|
560
|
+
# vs
|
561
|
+
# end
|
562
|
+
# end
|
563
|
+
# end
|
564
|
+
|
565
|
+
class Natural
|
566
|
+
include Parsable
|
567
|
+
def initialize(args = {})
|
568
|
+
@parser = lambda do |input|
|
569
|
+
TokenizeParser.new(Nat.new, args)
|
570
|
+
end
|
422
571
|
end
|
423
572
|
end
|
573
|
+
# class Natural < ParserBase
|
424
574
|
|
575
|
+
# def initialize
|
576
|
+
# @parser = Token.new(Nat.new)
|
577
|
+
# end
|
578
|
+
# end
|
425
579
|
|
426
|
-
class Symbol < ParserBase
|
427
580
|
|
428
|
-
|
429
|
-
|
581
|
+
class Symbol
|
582
|
+
include Parsable
|
583
|
+
def initialize(literal, args = {})
|
584
|
+
@parser = lambda do |input|
|
585
|
+
LiteralParser.new(literal)
|
586
|
+
end
|
430
587
|
end
|
431
588
|
end
|
432
589
|
|
590
|
+
# class Symbol < ParserBase
|
591
|
+
|
592
|
+
# def initialize(literal)
|
593
|
+
# @parser = Token.new(StringParser.new(literal))
|
594
|
+
# end
|
595
|
+
# end
|
596
|
+
|
433
597
|
class AbstractParser
|
434
598
|
include Parsable
|
435
599
|
|