yaparc 0.0.7 → 0.0.8

Sign up to get free protection for your applications and to get access to all the features.
Files changed (5) hide show
  1. data/README +172 -8
  2. data/lib/yaparc.rb +402 -69
  3. data/tests/test_calc.rb +42 -105
  4. data/tests/test_parser.rb +304 -67
  5. metadata +2 -2
data/lib/yaparc.rb CHANGED
@@ -22,13 +22,22 @@ module Yaparc
22
22
 
23
23
 
24
24
  def parse(input, &block)
25
- tree = @parser.call(input)
25
+ result = @parser.call(input)
26
26
  if block_given?
27
- @tree = yield tree
27
+ @tree = yield result.value
28
28
  else
29
- @tree = tree
29
+ @tree = result.value
30
30
  end
31
+ result
31
32
  end
33
+ # def parse(input, &block)
34
+ # result = @parser.call(input)
35
+ # if block_given?
36
+ # @tree = yield result
37
+ # else
38
+ # @tree = result
39
+ # end
40
+ # end
32
41
 
33
42
  def eval
34
43
  tree = parse(input)
@@ -52,61 +61,116 @@ module Yaparc
52
61
  # end
53
62
  # end
54
63
 
55
- def cparse(input, &block)
56
- tree = @@cparser.call.parse(input)
57
- if block_given?
58
- yield tree
59
- else
60
- tree
61
- end
62
- end
63
- module_function :cparse
64
+ # def cparse(input, &block)
65
+ # tree = @@cparser.call.parse(input)
66
+ # if block_given?
67
+ # yield tree
68
+ # else
69
+ # tree
70
+ # end
71
+ # end
72
+ # module_function :cparse
64
73
 
65
74
  end
66
75
  end # of Module Parsable
67
76
 
77
+ class Result
78
+ attr_accessor :message, :input, :value
79
+ def initialize(options = {})
80
+ @message = options[:message] if options[:message]
81
+ @input = options[:input] if options[:input]
82
+ @value = options[:value] if options[:value]
83
+ end
84
+ end
85
+
86
+ class OK < Result
87
+ end
88
+
89
+ class Fail < Result
90
+ end
91
+
92
+ class Error < Result
93
+ end
68
94
 
69
95
  class SucceedParser
70
96
  include Parsable
71
97
  attr_reader :remaining
72
98
  def initialize(value, remaining = nil)
73
- @parser = lambda {|input| [[value, input]]}
99
+ @parser = lambda do |input|
100
+ # [[value, input]]
101
+ OK.new(:value => value, :input => input)
102
+ end
74
103
  @remaining = remaining
75
104
  end
76
105
  end
106
+ # class SucceedParser
107
+ # include Parsable
108
+ # attr_reader :remaining
109
+ # def initialize(value, remaining = nil)
110
+ # @parser = lambda do |input|
111
+ # [[value, input]]
112
+ # end
113
+ # @remaining = remaining
114
+ # end
115
+ # end
77
116
 
78
117
  class FailParser
79
118
  include Parsable
80
119
  def initialize
81
- @parser = lambda {|input| []}
120
+ @parser = lambda do |input|
121
+ Fail.new
122
+ end
82
123
  end
83
124
  end
84
125
 
126
+ # class FailParser
127
+ # include Parsable
128
+ # def initialize
129
+ # @parser = lambda do |input|
130
+ # []
131
+ # end
132
+ # end
133
+ # end
134
+
85
135
  class ItemParser
86
136
  include Parsable
87
137
  def initialize
88
138
  @parser = lambda do |input|
89
139
  if input.nil? or input.empty?
90
- []
140
+ Fail.new
91
141
  else
92
- [[input[0..0],input[1..input.length]]]
142
+ # [[input[0..0],input[1..input.length]]]
143
+ OK.new(:value => input[0..0],:input => input[1..input.length])
93
144
  end
94
145
  end
95
146
  end
96
147
  end
97
148
 
149
+ # class ItemParser
150
+ # include Parsable
151
+ # def initialize
152
+ # @parser = lambda do |input|
153
+ # if input.nil? or input.empty?
154
+ # []
155
+ # else
156
+ # [[input[0..0],input[1..input.length]]]
157
+ # end
158
+ # end
159
+ # end
160
+ # end
161
+
98
162
  class SatisfyParser
99
163
  include Parsable
100
164
  def initialize(predicate)
101
165
  assert_at(__FILE__,__LINE__){predicate.instance_of?(Proc)}
102
166
 
103
167
  @parser = lambda do |input|
104
- item = ItemParser.new.parse(input)
105
- if item == []
168
+ case result = ItemParser.new.parse(input)
169
+ when Fail
106
170
  FailParser.new
107
171
  else
108
- parser = if predicate.call(item[0][0])
109
- SucceedParser.new(item[0][0], item[0][1])
172
+ parser = if predicate.call(result.value)
173
+ SucceedParser.new(result.value, result.input)
110
174
  else
111
175
  FailParser.new
112
176
  end
@@ -124,72 +188,173 @@ module Yaparc
124
188
  raise
125
189
  end
126
190
  end
127
-
128
191
  end
129
192
 
193
+ # class SatisfyParser
194
+ # include Parsable
195
+ # def initialize(predicate)
196
+ # assert_at(__FILE__,__LINE__){predicate.instance_of?(Proc)}
197
+
198
+ # @parser = lambda do |input|
199
+ # item = ItemParser.new.parse(input)
200
+ # if item == []
201
+ # FailParser.new
202
+ # else
203
+ # parser = if predicate.call(item[0][0])
204
+ # SucceedParser.new(item[0][0], item[0][1])
205
+ # else
206
+ # FailParser.new
207
+ # end
208
+ # end
209
+ # end
210
+ # end
211
+
212
+ # def parse(input)
213
+ # case parser = @parser.call(input)
214
+ # when SucceedParser
215
+ # parser.parse(parser.remaining)
216
+ # when FailParser
217
+ # parser.parse(input)
218
+ # else
219
+ # raise
220
+ # end
221
+ # end
222
+
223
+ # end
224
+
130
225
 
131
226
  class SeqParser
132
227
  include Parsable
133
228
  def initialize(*parsers, &block)
134
229
  @parser = lambda do |input|
135
230
  args = []
136
- remains = parsers.inject(input) do |accumulator, parser|
137
- result = parser.parse(accumulator)
138
- if result == []
139
- break []
231
+ initial_result = OK.new(:input => input)
232
+ final_result = parsers.inject(initial_result) do |subsequent, parser|
233
+ case result = parser.parse(subsequent.input)
234
+ when Fail
235
+ break Fail.new
140
236
  else
141
- args << result[0][0]
142
- result[0][1]
237
+ args << result.value
238
+ result
143
239
  end
144
240
  end
145
- if remains == []
146
- []
147
- else
148
- retval = if block_given?
241
+
242
+ case final_result
243
+ when Fail
244
+ Fail.new
245
+ when OK
246
+ final_value = if block_given?
149
247
  yield(*args)
150
248
  else
151
249
  args.last
152
250
  end
153
- [[retval, remains]]
251
+ OK.new(:value => final_value, :input => final_result.input)
252
+ else
253
+ raise
154
254
  end
155
255
  end
156
256
  end # of initialize
157
-
158
257
  end # of SeqParser
159
258
 
259
+ # class SeqParser
260
+ # include Parsable
261
+ # def initialize(*parsers, &block)
262
+ # @parser = lambda do |input|
263
+ # args = []
264
+ # remains = parsers.inject(input) do |accumulator, parser|
265
+ # result = parser.parse(accumulator)
266
+ # if result == []
267
+ # break []
268
+ # else
269
+ # args << result[0][0]
270
+ # result[0][1]
271
+ # end
272
+ # end
273
+ # if remains == []
274
+ # []
275
+ # else
276
+ # retval = if block_given?
277
+ # yield(*args)
278
+ # else
279
+ # args.last
280
+ # end
281
+ # [[retval, remains]]
282
+ # end
283
+ # end
284
+ # end # of initialize
285
+
286
+ # end # of SeqParser
287
+
160
288
  class AltParser
161
289
  include Parsable
162
290
  def initialize(*parsers)
163
291
  @parser = lambda do |input|
164
- parsers.inject([]) do |accum, parser|
165
- result = parser.parse(input)
166
- if result == []
167
- result
292
+ initial_result = OK.new(:input => input)
293
+ final_result = Fail.new
294
+ parsers.each do |parser|
295
+ case result = parser.parse(initial_result.input)
296
+ when Fail
297
+ next
298
+ when OK
299
+ break final_result = result
168
300
  else
169
- break [result[0]]
301
+ raise
170
302
  end
171
303
  end
304
+ final_result
172
305
  end
173
306
  end # of initialize
174
307
  end
175
308
 
309
+ # class AltParser
310
+ # include Parsable
311
+ # def initialize(*parsers)
312
+ # @parser = lambda do |input|
313
+ # parsers.inject([]) do |accum, parser|
314
+ # result = parser.parse(input)
315
+ # if result == []
316
+ # result
317
+ # else
318
+ # break [result[0]]
319
+ # end
320
+ # end
321
+ # end
322
+ # end # of initialize
323
+ # end
176
324
 
177
325
 
178
- class StringParser
326
+ class ApplyParser
179
327
  include Parsable
180
- def initialize(string)
328
+ def initialize(parser, &block)
181
329
  @parser = lambda do |input|
182
- result = ItemParser.new.parse(string)
330
+ args = nil
331
+ result = parser.parse(input)
183
332
  if result == []
184
- SucceedParser.new(result)
333
+ FailParser.new.parse(input)
185
334
  else
335
+ SucceedParser.new(yield(result[0][0])).parse(result[0][1])
336
+ end
337
+ end
338
+ end # of initialize
339
+ end # of ApplyParser
340
+
341
+ class StringParser
342
+ include Parsable
343
+ def initialize(string)
344
+ @parser = lambda do |input|
345
+ case result = ItemParser.new.parse(string)
346
+ when Fail
347
+ SucceedParser.new(result) # Is it OK?
348
+ when OK
186
349
  SeqParser.new(
187
- CharParser.new(result[0][0]),
188
- StringParser.new(result[0][1]),
189
- SucceedParser.new(result[0][0] + result[0][1])
350
+ CharParser.new(result.value),
351
+ StringParser.new(result.input),
352
+ SucceedParser.new(result.value + result.input)
190
353
  ) do |char_result, string_result, succeed_result|
191
354
  succeed_result
192
355
  end
356
+ else
357
+ raise
193
358
  end
194
359
  end
195
360
  end
@@ -199,6 +364,30 @@ module Yaparc
199
364
  end
200
365
  end
201
366
 
367
+ # class StringParser
368
+ # include Parsable
369
+ # def initialize(string)
370
+ # @parser = lambda do |input|
371
+ # result = ItemParser.new.parse(string)
372
+ # if result == []
373
+ # SucceedParser.new(result)
374
+ # else
375
+ # SeqParser.new(
376
+ # CharParser.new(result[0][0]),
377
+ # StringParser.new(result[0][1]),
378
+ # SucceedParser.new(result[0][0] + result[0][1])
379
+ # ) do |char_result, string_result, succeed_result|
380
+ # succeed_result
381
+ # end
382
+ # end
383
+ # end
384
+ # end
385
+
386
+ # def parse(input)
387
+ # @parser.call(input).parse(input)
388
+ # end
389
+ # end
390
+
202
391
 
203
392
  class RegexParser
204
393
  include Parsable
@@ -206,20 +395,34 @@ module Yaparc
206
395
  def initialize(regex)
207
396
  @parser = lambda do |input|
208
397
  if match = Regexp.new(regex).match(input)
209
- [[match[0],match.post_match]]
398
+ OK.new(:value => match[0], :input => match.post_match)
210
399
  else
211
- []
400
+ Fail.new
212
401
  end
213
402
  end
214
403
  end
215
404
  end
216
405
 
406
+ # class RegexParser
407
+ # include Parsable
408
+
409
+ # def initialize(regex)
410
+ # @parser = lambda do |input|
411
+ # if match = Regexp.new(regex).match(input)
412
+ # [[match[0],match.post_match]]
413
+ # else
414
+ # []
415
+ # end
416
+ # end
417
+ # end
418
+ # end
419
+
217
420
  # permits zero or more applications of parser.
218
421
  class ManyParser
219
422
  include Parsable
220
423
  def initialize(parser)
221
424
  @parser = lambda do |input|
222
- AltParser.new(ManyOneParser.new(parser), SucceedParser.new([])).parse(input)
425
+ AltParser.new(ManyOneParser.new(parser), SucceedParser.new("")).parse(input)
223
426
  end
224
427
  end
225
428
 
@@ -228,6 +431,19 @@ module Yaparc
228
431
  end
229
432
  end
230
433
 
434
+ # class ManyParser
435
+ # include Parsable
436
+ # def initialize(parser)
437
+ # @parser = lambda do |input|
438
+ # AltParser.new(ManyOneParser.new(parser), SucceedParser.new([])).parse(input)
439
+ # end
440
+ # end
441
+
442
+ # def parse(input)
443
+ # @parser.call(input)
444
+ # end
445
+ # end
446
+
231
447
  # requires at least one successfull application of parser.
232
448
  class ManyOneParser
233
449
  include Parsable
@@ -236,12 +452,8 @@ module Yaparc
236
452
  SeqParser.new(
237
453
  parser,
238
454
  ManyParser.new(parser)
239
- ) do |v, vs|
240
- if vs == []
241
- v
242
- else
243
- v + vs.to_s
244
- end
455
+ ) do |head, tail|
456
+ head + tail
245
457
  end
246
458
  end
247
459
  end
@@ -251,6 +463,28 @@ module Yaparc
251
463
  end
252
464
  end
253
465
 
466
+ # class ManyOneParser
467
+ # include Parsable
468
+ # def initialize(parser)
469
+ # @parser = lambda do |input|
470
+ # SeqParser.new(
471
+ # parser,
472
+ # ManyParser.new(parser)
473
+ # ) do |v, vs|
474
+ # if vs == []
475
+ # v
476
+ # else
477
+ # v + vs.to_s
478
+ # end
479
+ # end
480
+ # end
481
+ # end
482
+
483
+ # def parse(input)
484
+ # @parser.call(input).parse(input)
485
+ # end
486
+ # end
487
+
254
488
 
255
489
  class ParserBase
256
490
  include Parsable
@@ -268,34 +502,58 @@ module Yaparc
268
502
  end
269
503
  end
270
504
 
505
+ # class CharParser < ParserBase
506
+
507
+ # def initialize(char)
508
+ # equal_char = lambda {|i| i == char}
509
+ # @parser = SatisfyParser.new(equal_char)
510
+ # end
511
+ # end
512
+
271
513
 
272
514
  class ZeroOneParser < ParserBase
273
515
  def initialize(parser)
274
- @parser = AltParser.new(parser, SucceedParser.new([]))
516
+ @parser = AltParser.new(parser, SucceedParser.new([])) # Is it OK?
275
517
  end
276
518
  end
277
519
 
520
+ # class ZeroOneParser < ParserBase
521
+ # def initialize(parser)
522
+ # @parser = AltParser.new(parser, SucceedParser.new([]))
523
+ # end
524
+ # end
525
+
278
526
 
279
527
  class Ident < ParserBase
280
528
  def initialize
281
529
  @parser = SeqParser.new(
282
530
  SatisfyParser.new(IS_LOWER),
283
531
  ManyParser.new(SatisfyParser.new(IS_ALPHANUM))
284
- ) do |v, vs|
285
- if vs == []
286
- v
287
- else
288
- v + vs.to_s
289
- end
532
+ ) do |head, tail|
533
+ head + tail
290
534
  end
291
535
  end
292
536
  end
293
537
 
294
- class Nat < ParserBase
538
+ # class Ident < ParserBase
539
+ # def initialize
540
+ # @parser = SeqParser.new(
541
+ # SatisfyParser.new(IS_LOWER),
542
+ # ManyParser.new(SatisfyParser.new(IS_ALPHANUM))
543
+ # ) do |v, vs|
544
+ # if vs == []
545
+ # v
546
+ # else
547
+ # v + vs.to_s
548
+ # end
549
+ # end
550
+ # end
551
+ # end
295
552
 
553
+ class Nat < ParserBase
296
554
  def initialize
297
555
  @parser = SeqParser.new(ManyOneParser.new(SatisfyParser.new(IS_DIGIT))) do |vs|
298
- if vs == []
556
+ if vs == ""
299
557
  vs
300
558
  else
301
559
  vs.to_i
@@ -304,9 +562,21 @@ module Yaparc
304
562
  end
305
563
  end
306
564
 
565
+ # class Nat < ParserBase
566
+
567
+ # def initialize
568
+ # @parser = SeqParser.new(ManyOneParser.new(SatisfyParser.new(IS_DIGIT))) do |vs|
569
+ # if vs == []
570
+ # vs
571
+ # else
572
+ # vs.to_i
573
+ # end
574
+ # end
575
+ # end
576
+ # end
307
577
 
308
- class Space < ParserBase
309
578
 
579
+ class Space < ParserBase
310
580
  def initialize
311
581
  @parser = SeqParser.new(ManyParser.new(SatisfyParser.new(IS_SPACE))) do |vs|
312
582
  []
@@ -314,22 +584,78 @@ module Yaparc
314
584
  end
315
585
  end
316
586
 
587
+ # class Space < ParserBase
588
+
589
+ # def initialize
590
+ # @parser = SeqParser.new(ManyParser.new(SatisfyParser.new(IS_SPACE))) do |vs|
591
+ # []
592
+ # end
593
+ # end
594
+ # end
595
+
317
596
  class Token < ParserBase
318
597
 
319
- def initialize(parser)
320
- @parser = SeqParser.new(Space.new, parser, Space.new) do |_, vs, _|
598
+ def initialize(parser, prefix = Space.new, postfix = Space.new)
599
+ # @parser = SeqParser.new(Space.new, parser, Space.new) do |_, vs, _|
600
+ @parser = SeqParser.new(prefix, parser, postfix) do |_, vs, _|
321
601
  vs
322
602
  end
323
603
  end
324
604
  end
325
605
 
326
- class Identifier < ParserBase
606
+ # Refer to http://www.cs.nott.ac.uk/~gmh/monparsing.pdf, p.23
607
+ class Identifier
608
+ include Parsable
609
+ def initialize(*keywords)
610
+ if keywords == []
611
+ @parser = lambda do |input|
612
+ Token.new(Ident.new)
613
+ end
614
+ else
615
+ @parser = lambda do |input|
616
+ keyword_parsers = keywords.map {|keyword| StringParser.new(keyword)}
617
+ case result = AltParser.new(*keyword_parsers).parse(input)
618
+ when OK
619
+ FailParser.new
620
+ when Fail
621
+ Token.new(Ident.new)
622
+ else
623
+ raise
624
+ end
625
+ end
626
+ end
627
+ end
327
628
 
328
- def initialize
329
- @parser = Token.new(Ident.new)
629
+ def parse(input)
630
+ @parser.call(input).parse(input)
330
631
  end
331
632
  end
332
633
 
634
+ # class Identifier
635
+ # include Parsable
636
+ # def initialize(*keywords)
637
+ # if keywords == []
638
+ # @parser = lambda do |input|
639
+ # Token.new(Ident.new)
640
+ # end
641
+ # else
642
+ # @parser = lambda do |input|
643
+ # keyword_parsers = keywords.map {|keyword| StringParser.new(keyword)}
644
+ # result = AltParser.new(*keyword_parsers).parse(input)
645
+ # unless result == []
646
+ # FailParser.new
647
+ # else
648
+ # Token.new(Ident.new)
649
+ # end
650
+ # end
651
+ # end
652
+ # end
653
+
654
+ # def parse(input)
655
+ # @parser.call(input).parse(input)
656
+ # end
657
+ # end
658
+
333
659
  class Natural < ParserBase
334
660
 
335
661
  def initialize
@@ -337,6 +663,13 @@ module Yaparc
337
663
  end
338
664
  end
339
665
 
666
+ # class Natural < ParserBase
667
+
668
+ # def initialize
669
+ # @parser = Token.new(Nat.new)
670
+ # end
671
+ # end
672
+
340
673
  class Symbol < ParserBase
341
674
 
342
675
  def initialize(literal)