rparsec2 1.1.0 → 1.2.1

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.
@@ -1,624 +1,1047 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'rparsec/parser'
2
4
 
3
5
  module RParsec
6
+ #
7
+ # This module provides all out-of-box parser implementations.
8
+ #
9
+ module Parsers
10
+ #
11
+ # A parser that always fails with the given error message.
12
+ #
13
+ def failure msg
14
+ FailureParser.new(msg)
15
+ end
4
16
 
5
- class FailureParser < Parser
6
- init :msg
7
- def _parse ctxt
8
- return ctxt.failure(@msg)
9
- end
10
- end
17
+ #
18
+ # A parser that always succeeds with the given return value.
19
+ #
20
+ def value v
21
+ ValueParser.new(v)
22
+ end
11
23
 
12
- class ValueParser < Parser
13
- init :value
14
- def _parse ctxt
15
- ctxt.retn @value
16
- end
17
- end
24
+ #
25
+ # A parser that calls alternative parsers until one succeed,
26
+ # or any failure with input consumption beyond the current look-ahead.
27
+ #
28
+ def sum(*alts)
29
+ PlusParser.new(alts)
30
+ end
18
31
 
19
- class LazyParser < Parser
20
- init :block
21
- def _parse ctxt
22
- @block.call._parse ctxt
23
- end
24
- end
32
+ #
33
+ # A parser that calls alternative parsers until one succeeds.
34
+ #
35
+ def alt(*alts)
36
+ AltParser.new(alts)
37
+ end
25
38
 
26
- class Failures
27
- def self.add_error(err, e)
28
- return e if err.nil?
29
- return err if e.nil?
30
- cmp = compare_error(err, e)
31
- return err if cmp > 0
32
- return e if cmp < 0
33
- err
34
- # merge_error(err, e)
35
- end
39
+ #
40
+ # A parser that succeeds when the given predicate returns true
41
+ # (with the current input as the parameter). +expected+ is the
42
+ # error message when +pred+ returns false.
43
+ #
44
+ def satisfies(expected, &pred)
45
+ SatisfiesParser.new(pred, expected)
46
+ end
36
47
 
37
- class << self
38
- private
48
+ #
49
+ # A parser that succeeds when the the current input is equal to
50
+ # the given value. +expected+ is the error message when the
51
+ # predicate returns false.
52
+ #
53
+ def is(v, expected = "#{v} expected")
54
+ satisfies(expected) { |c| c == v }
55
+ end
56
+
57
+ #
58
+ # A parser that succeeds when the the current input is not equal
59
+ # to the given value. +expected+ is the error message when the
60
+ # predicate returns false.
61
+ #
62
+ def isnt(v, expected = "#{v} unexpected")
63
+ satisfies(expected) { |c| c != v }
64
+ end
65
+
66
+ #
67
+ # A parser that succeeds when the the current input is among the given values.
68
+ #
69
+ def among(*vals)
70
+ expected = "one of [#{vals.join(', ')}] expected"
71
+ vals = as_list vals
72
+ satisfies(expected) { |c| vals.include? c }
73
+ end
74
+
75
+ #
76
+ # A parser that succeeds when the the current input is not among the given values.
77
+ #
78
+ def not_among(*vals)
79
+ expected = "one of [#{vals.join(', ')}] unexpected"
80
+ vals = as_list vals
81
+ satisfies(expected) { |c| !vals.include? c }
82
+ end
39
83
 
40
- def get_first_element(err)
41
- while err.kind_of?(Array)
42
- err = err[0]
84
+ #
85
+ # A parser that succeeds when the the current input is the given character.
86
+ #
87
+ def char(c)
88
+ if c.kind_of? Integer
89
+ nm = c.chr
90
+ is(c, "'#{nm}' expected").setName(nm)
91
+ else
92
+ is(c[0], "'#{c}' expected").setName(c)
43
93
  end
44
- err
45
94
  end
46
95
 
47
- def compare_error(e1, e2)
48
- e1, e2 = get_first_element(e1), get_first_element(e2)
49
- return -1 if e1.index < e2.index
50
- return 1 if e1.index > e2.index
51
- 0
96
+ #
97
+ # A parser that succeeds when the the current input is not the given character.
98
+ #
99
+ def not_char(c)
100
+ if c.kind_of? Integer
101
+ nm = c.chr
102
+ isnt(c, "'#{nm}' unexpected").setName("~#{nm}")
103
+ else
104
+ isnt(c[0], "'#{c}' unexpected").setName("~#{c}")
105
+ end
52
106
  end
53
- end
54
- end
55
107
 
56
- ###############################################
57
- #def merge_error(e1, e2)
58
- # return e1 << e2 if e1.kind_of?(Array)
59
- # [e1,e2]
60
- #end
61
- ###############################################
62
- class ThrowParser < Parser
63
- init :symbol
64
- def _parse _ctxt
65
- throw @symbol
66
- end
67
- end
108
+ #
109
+ # A parser that succeeds when there's no input available.
110
+ #
111
+ def eof(expected = "EOF expected")
112
+ EofParser.new(expected).setName('EOF')
113
+ end
68
114
 
69
- class CatchParser < Parser
70
- init :symbol, :parser
71
- def _parse ctxt
72
- interrupted = true
73
- ok = false
74
- catch @symbol do
75
- ok = @parser._parse(ctxt)
76
- interrupted = false
115
+ #
116
+ # A parser that tries to match the current inputs one by one
117
+ # with the given values.
118
+ # It succeeds only when all given values are matched, in which case all the
119
+ # matched inputs are consumed.
120
+ #
121
+ def are(vals, expected = "#{vals} expected")
122
+ AreParser.new(vals, expected)
77
123
  end
78
- return ctxt.retn(@symbol) if interrupted
79
- ok
80
- end
81
- end
82
124
 
83
- class PeekParser < Parser
84
- init :parser
85
- def _parse ctxt
86
- ind = ctxt.index
87
- return false unless @parser._parse ctxt
88
- ctxt.index = ind
89
- return true
90
- end
91
- def peek
92
- self
93
- end
94
- end
125
+ #
126
+ # A parser that makes sure that the given values don't match
127
+ # the current inputs. One input is consumed if it succeeds.
128
+ #
129
+ def arent(vals, expected = "#{vals} unexpected")
130
+ are(vals, '').not(expected) >> any
131
+ end
132
+
133
+ #
134
+ # A parser that matches the given string.
135
+ #
136
+ def string(str, msg = "\"#{str}\" expected")
137
+ are(str, msg).setName(str)
138
+ end
139
+
140
+ #
141
+ # A parser that makes sure that the current input doesn't match a string.
142
+ # One character is consumed if it succeeds.
143
+ #
144
+ def not_string(str, msg = "\"#{str}\" unexpected")
145
+ string(str).not(msg) >> any
146
+ end
147
+
148
+ alias str string
95
149
 
96
- class AtomParser < Parser
97
- init :parser
98
- def _parse ctxt
99
- ind = ctxt.index
100
- return true if @parser._parse ctxt
101
- ctxt.index = ind
102
- return false
150
+ #
151
+ # A parser that sequentially run the given +parsers+. The result
152
+ # of the last parser is used as return value. If a block is
153
+ # given, the results of the +parsers+ are passed into the block as
154
+ # parameters, and the block return value is used as result
155
+ # instead.
156
+ #
157
+ def sequence(*parsers, &proc)
158
+ SequenceParser.new(parsers, proc)
159
+ end
160
+
161
+ #
162
+ # A parser that returns the current input index (starting from 0).
163
+ #
164
+ def get_index
165
+ GetIndexParser.new.setName('get_index')
166
+ end
167
+
168
+ #
169
+ # A parser that moves the current input pointer to a certain index.
170
+ #
171
+ def set_index ind
172
+ SetIndexParser.new(ind).setName('set_index')
173
+ end
174
+
175
+ #
176
+ # A parser that tries all given alternative +parsers+ and picks
177
+ # the one with the longest match.
178
+ #
179
+ def longest(*parsers)
180
+ BestParser.new(parsers, true)
181
+ end
182
+
183
+ #
184
+ # A parser that tries all given alternative +parsers+ and picks
185
+ # the one with the shortest match.
186
+ #
187
+ def shortest(*parsers)
188
+ BestParser.new(parsers, false)
189
+ end
190
+
191
+ alias shorter shortest
192
+ alias longer longest
193
+
194
+ #
195
+ # A parser that consumes one input.
196
+ #
197
+ def any
198
+ AnyParser.new
199
+ end
200
+
201
+ #
202
+ # A parser that always fails.
203
+ #
204
+ def zero
205
+ ZeroParser.new
206
+ end
207
+
208
+ #
209
+ # A parser that always succeeds.
210
+ #
211
+ def one
212
+ OneParser.new
213
+ end
214
+
215
+ #
216
+ # A parser that succeeds if the current input is within a certain range.
217
+ #
218
+ def range(from, to, msg = "#{as_char from}..#{as_char to} expected")
219
+ from, to = as_num(from), as_num(to)
220
+ satisfies(msg) { |c| c <= to && c >= from }
221
+ end
222
+
223
+ #
224
+ # A parser that throws a +symbol+.
225
+ #
226
+ def throwp(symbol)
227
+ ThrowParser.new(symbol)
228
+ end
229
+
230
+ #
231
+ # A parser that succeeds if the current inputs match
232
+ # the given regular expression.
233
+ # The matched string is consumed and returned as result.
234
+ #
235
+ def regexp(ptn, expected = "/#{ptn}/ expected")
236
+ RegexpParser.new(as_regexp(ptn), expected).setName(expected)
237
+ end
238
+
239
+ #
240
+ # A parser that parses a word
241
+ # (starting with alpha or underscore, followed by 0 or more alpha, number or underscore).
242
+ # and return the matched word as string.
243
+ #
244
+ def word(expected = 'word expected')
245
+ regexp(/[a-zA-Z_]\w*/, expected)
246
+ end
247
+
248
+ #
249
+ # A parser that parses an integer
250
+ # and return the matched integer as string.
251
+ #
252
+ def integer(expected = 'integer expected')
253
+ regexp(/\d+(?!\w)/, expected)
254
+ end
255
+
256
+ #
257
+ # A parser that parses a number (integer, or decimal number)
258
+ # and return the matched number as string.
259
+ #
260
+ def number(expected = 'number expected')
261
+ regexp(/\d+(\.\d+)?/, expected)
262
+ end
263
+
264
+ #
265
+ # A parser that matches the given string, case insensitively.
266
+ #
267
+ def string_nocase(str, expected = "'#{str}' expected")
268
+ StringCaseInsensitiveParser.new(str, expected).setName(str)
269
+ end
270
+
271
+ #
272
+ # A parser that succeeds when the current input is a token with
273
+ # one of the the given token +kinds+. If a block is given, the
274
+ # token text is passed to the block as parameter, and the block
275
+ # return value is used as result. Otherwise, the token object is
276
+ # used as result.
277
+ #
278
+ def token(*kinds, &proc)
279
+ expected = "#{kinds.join(' or ')} expected"
280
+ recognizer = nil
281
+ if kinds.length == 1
282
+ kind = kinds[0]
283
+ recognizer = satisfies(expected) do |tok|
284
+ tok.respond_to? :kind, :text and kind == tok.kind
285
+ end
286
+ else
287
+ recognizer = satisfies(expected) do |tok|
288
+ tok.respond_to? :kind, :text and kinds.include? tok.kind
289
+ end
290
+ end
291
+ recognizer = recognizer.map { |tok| proc.call(tok.text) } if proc
292
+ recognizer
293
+ end
294
+
295
+ #
296
+ # A parser that parses a white space character.
297
+ #
298
+ def whitespace(expected = "whitespace expected")
299
+ satisfies(expected) { |c| Whitespaces.include? c }
300
+ end
301
+
302
+ #
303
+ # A parser that parses 1 or more white space characters.
304
+ #
305
+ def whitespaces(expected = "whitespace(s) expected")
306
+ whitespace(expected).many_(1)
307
+ end
308
+
309
+ #
310
+ # A parser that parses a line started with +start+. +nil+ is the
311
+ # result.
312
+ #
313
+ def comment_line start
314
+ string(start) >> not_char(?\n).many_ >> char(?\n).optional >> value(nil)
315
+ end
316
+
317
+ #
318
+ # A parser that parses a chunk of text started with +open+ and
319
+ # ended by +close+. +nil+ is the result.
320
+ #
321
+ def comment_block open, close
322
+ string(open) >> not_string(close).many_ >> string(close) >> value(nil)
323
+ end
324
+
325
+ #
326
+ # A lazy parser, when executed, calls the given +block+ to get a
327
+ # parser object and delegate the call to this lazily instantiated
328
+ # parser.
329
+ #
330
+ def lazy(&block)
331
+ LazyParser.new(block)
332
+ end
333
+
334
+ #
335
+ # A parser that watches the current parser result without changing
336
+ # it. The following assert will succeed:
337
+ ##
338
+ # char(?a) >> watch { |x| assert_equal(?a, x) }
339
+ #
340
+ # +watch+ can also be used as a handy tool to print trace
341
+ # information, for example:
342
+ #
343
+ # some_parser >> watch { puts "some_parser succeeded." }
344
+ #
345
+ def watch(&block)
346
+ return one unless block
347
+ WatchParser.new(block)
348
+ end
349
+
350
+ #
351
+ # A parser that watches the current parser result without changing
352
+ # it. The following assert will succeed:
353
+ #
354
+ # char(?a).repeat(2) >> watchn { |x, y| assert_equal([?a, ?a], [x, y]) }
355
+ #
356
+ # Slightly different from #watch, +watchn+ expands the current
357
+ # parser result before passing it into the associated block.
358
+ #
359
+ def watchn(&block)
360
+ return one unless block
361
+ WatchnParser.new(block)
362
+ end
363
+
364
+ #
365
+ # A parser that maps current parser result to a new result using
366
+ # the given +block+.
367
+ #
368
+ # Different from Parser#map, this method does not need to be
369
+ # combined with any Parser object. It is rather an independent
370
+ # Parser object that maps the _current_ parser result.
371
+ #
372
+ # <tt>parser1.map { |x| ... }</tt> is equivalent to <tt>parser1 >>
373
+ # map { |x| ... }</tt>.
374
+ #
375
+ # See also Parser#>>.
376
+ #
377
+ def map(&block)
378
+ return one unless block
379
+ MapCurrentParser.new(block)
380
+ end
381
+
382
+ #
383
+ # A parser that maps current parser result to a new result using
384
+ # the given +block+. If the current parser result is an array,
385
+ # the array elements are expanded and then passed as parameters to
386
+ # the +block+.
387
+ #
388
+ # Different from Parser#mapn, this method does not need to be
389
+ # combined with any Parser object. It is rather an independent
390
+ # Parser object that maps the _current_ parser result.
391
+ #
392
+ # <tt>parser1.mapn { |x, y| ... }</tt> is equivalent to
393
+ # <tt>parser1 >> mapn { |x, y| ... }</tt>.
394
+ #
395
+ # See also Parser#>>.
396
+ #
397
+ def mapn(&block)
398
+ return one unless block
399
+ MapnCurrentParser.new(block)
400
+ end
401
+
402
+ private
403
+
404
+ #
405
+ # characters considered white space.
406
+ #
407
+ Whitespaces = " \t\r\n"
408
+
409
+ def as_regexp ptn
410
+ case ptn when String then Regexp.new(ptn) else ptn end
411
+ end
412
+
413
+ def as_char c
414
+ case c when String then c else c.chr end
415
+ end
416
+
417
+ def as_num c
418
+ case c when String then c[0] else c end
419
+ end
420
+
421
+ def as_list vals
422
+ return vals unless vals.length == 1
423
+ val = vals[0]
424
+ return vals unless val.kind_of? String
425
+ val
426
+ end
427
+
428
+ extend self
103
429
  end
104
- def atomize
105
- self
430
+
431
+ class FailureParser < Parser # :nodoc:
432
+ init :msg
433
+ def _parse ctxt
434
+ return ctxt.failure(@msg)
435
+ end
106
436
  end
107
- end
108
437
 
109
- class LookAheadSensitiveParser < Parser
110
- def initialize(la = 1)
111
- super()
112
- @lookahead = la
438
+ class ValueParser < Parser # :nodoc:
439
+ init :value
440
+ def _parse ctxt
441
+ ctxt.retn @value
442
+ end
113
443
  end
114
- def visible(ctxt, n)
115
- ctxt.index - n < @lookahead
444
+
445
+ class LazyParser < Parser # :nodoc:
446
+ init :block
447
+ def _parse ctxt
448
+ @block.call._parse ctxt
449
+ end
116
450
  end
117
- def lookahead(n)
118
- raise ArgumentError, "lookahead number #{n} should be positive" unless n > 0
119
- return self if n == @lookahead
120
- withLookahead(n)
451
+
452
+ class Failures # :nodoc:
453
+ def self.add_error(err, e)
454
+ return e if err.nil?
455
+ return err if e.nil?
456
+ cmp = compare_error(err, e)
457
+ return err if cmp > 0
458
+ return e if cmp < 0
459
+ err
460
+ # merge_error(err, e)
461
+ end
462
+
463
+ class << self
464
+ private
465
+
466
+ def get_first_element(err)
467
+ while err.kind_of?(Array)
468
+ err = err[0]
469
+ end
470
+ err
471
+ end
472
+
473
+ def compare_error(e1, e2)
474
+ e1, e2 = get_first_element(e1), get_first_element(e2)
475
+ return -1 if e1.index < e2.index
476
+ return 1 if e1.index > e2.index
477
+ 0
478
+ end
479
+ end
121
480
  end
122
- def not(msg = "#{self} unexpected")
123
- NotParser.new(self, msg, @lookahead)
481
+
482
+ ###############################################
483
+ #def merge_error(e1, e2)
484
+ # return e1 << e2 if e1.kind_of?(Array)
485
+ # [e1,e2]
486
+ #end
487
+ ###############################################
488
+ class ThrowParser < Parser # :nodoc:
489
+ init :symbol
490
+ def _parse _ctxt
491
+ throw @symbol
492
+ end
124
493
  end
125
- end
126
494
 
127
- class NotParser < LookAheadSensitiveParser
128
- def initialize(parser, msg, la = 1)
129
- super(la)
130
- @parser, @msg, @name = parser, msg, "~#{parser.name}"
495
+ class CatchParser < Parser # :nodoc:
496
+ init :symbol, :parser
497
+ def _parse ctxt
498
+ interrupted = true
499
+ ok = false
500
+ catch @symbol do
501
+ ok = @parser._parse(ctxt)
502
+ interrupted = false
503
+ end
504
+ return ctxt.retn(@symbol) if interrupted
505
+ ok
506
+ end
131
507
  end
132
- def _parse ctxt
133
- ind = ctxt.index
134
- if @parser._parse ctxt
508
+
509
+ class PeekParser < Parser # :nodoc:
510
+ init :parser
511
+ def _parse ctxt
512
+ ind = ctxt.index
513
+ return false unless @parser._parse ctxt
135
514
  ctxt.index = ind
136
- return ctxt.expecting(@msg)
515
+ return true
516
+ end
517
+ def peek
518
+ self
137
519
  end
138
- return ctxt.retn(nil) if visible(ctxt, ind)
139
- return false
140
- end
141
- def withLookahead(n)
142
- NotParser.new(@parser, @msg, n)
143
- end
144
- def not()
145
- @parser
146
520
  end
147
- end
148
521
 
149
- class ExpectParser < Parser
150
- def initialize(parser, msg)
151
- super()
152
- @parser, @msg, @name = parser, msg, msg
153
- end
154
- def _parse ctxt
155
- ind = ctxt.index
156
- return true if @parser._parse ctxt
157
- return false unless ind == ctxt.index
158
- ctxt.expecting(@msg)
522
+ class AtomParser < Parser # :nodoc:
523
+ init :parser
524
+ def _parse ctxt
525
+ ind = ctxt.index
526
+ return true if @parser._parse ctxt
527
+ ctxt.index = ind
528
+ return false
529
+ end
530
+ def atomize
531
+ self
532
+ end
159
533
  end
160
- end
161
534
 
162
- class PlusParser < LookAheadSensitiveParser
163
- def initialize(alts, la = 1)
164
- super(la)
165
- @alts = alts
535
+ class LookAheadSensitiveParser < Parser # :nodoc:
536
+ def initialize(la = 1)
537
+ super()
538
+ @lookahead = la
539
+ end
540
+ def visible(ctxt, n)
541
+ ctxt.index - n < @lookahead
542
+ end
543
+ def lookahead(n)
544
+ raise ArgumentError, "lookahead number #{n} should be positive" unless n > 0
545
+ return self if n == @lookahead
546
+ withLookahead(n)
547
+ end
548
+ def not(msg = "#{self} unexpected")
549
+ NotParser.new(self, msg, @lookahead)
550
+ end
166
551
  end
167
- def _parse ctxt
168
- ind, result, err = ctxt.index, ctxt.result, ctxt.error
169
- for p in @alts
170
- ctxt.reset_error
171
- ctxt.index, ctxt.result = ind, result
172
- return true if p._parse(ctxt)
173
- return false unless visible(ctxt, ind)
174
- err = Failures.add_error(err, ctxt.error)
552
+
553
+ class NotParser < LookAheadSensitiveParser # :nodoc:
554
+ def initialize(parser, msg, la = 1)
555
+ super(la)
556
+ @parser, @msg, @name = parser, msg, "~#{parser.name}"
557
+ end
558
+ def _parse ctxt
559
+ ind = ctxt.index
560
+ if @parser._parse ctxt
561
+ ctxt.index = ind
562
+ return ctxt.expecting(@msg)
563
+ end
564
+ return ctxt.retn(nil) if visible(ctxt, ind)
565
+ return false
566
+ end
567
+ def withLookahead(n)
568
+ NotParser.new(@parser, @msg, n)
569
+ end
570
+ def not()
571
+ @parser
175
572
  end
176
- ctxt.error = err
177
- return false
178
573
  end
179
- def withLookahead(n)
180
- PlusParser.new(@alts, n)
574
+
575
+ class ExpectParser < Parser # :nodoc:
576
+ def initialize(parser, msg)
577
+ super()
578
+ @parser, @msg, @name = parser, msg, msg
579
+ end
580
+ def _parse ctxt
581
+ ind = ctxt.index
582
+ return true if @parser._parse ctxt
583
+ return false unless ind == ctxt.index
584
+ ctxt.expecting(@msg)
585
+ end
181
586
  end
182
- def plus other
183
- PlusParser.new(@alts.dup << other, @lookahead).setName(name)
587
+
588
+ class PlusParser < LookAheadSensitiveParser # :nodoc:
589
+ def initialize(alts, la = 1)
590
+ super(la)
591
+ @alts = alts
592
+ end
593
+ def _parse ctxt
594
+ ind, result, err = ctxt.index, ctxt.result, ctxt.error
595
+ for p in @alts
596
+ ctxt.reset_error
597
+ ctxt.index, ctxt.result = ind, result
598
+ return true if p._parse(ctxt)
599
+ return false unless visible(ctxt, ind)
600
+ err = Failures.add_error(err, ctxt.error)
601
+ end
602
+ ctxt.error = err
603
+ return false
604
+ end
605
+ def withLookahead(n)
606
+ PlusParser.new(@alts, n)
607
+ end
608
+ def plus other
609
+ PlusParser.new(@alts.dup << other, @lookahead).setName(name)
610
+ end
184
611
  end
185
- def_sig :plus, Parser
186
- end
187
612
 
188
613
 
189
- class AltParser < LookAheadSensitiveParser
190
- def initialize(alts, la = 1)
191
- super(la)
192
- @alts, @lookahead = alts, la
614
+ class AltParser < LookAheadSensitiveParser # :nodoc:
615
+ def initialize(alts, la = 1)
616
+ super(la)
617
+ @alts, @lookahead = alts, la
618
+ end
619
+ def _parse ctxt
620
+ ind, result, err = ctxt.index, ctxt.result, ctxt.error
621
+ err_ind, err_pos = -1, -1
622
+ for p in @alts
623
+ ctxt.reset_error
624
+ ctxt.index, ctxt.result = ind, result
625
+ return true if p._parse(ctxt)
626
+ if ctxt.error.index > err_pos
627
+ err, err_ind, err_pos = ctxt.error, ctxt.index, ctxt.error.index
628
+ end
629
+ end
630
+ ctxt.index, ctxt.error = err_ind, err
631
+ return false
632
+ end
633
+ def withLookahead(n)
634
+ AltParser.new(@alts, n)
635
+ end
636
+ def | other
637
+ AltParser.new(@alts.dup << autobox_parser(other)).setName(name)
638
+ end
193
639
  end
194
- def _parse ctxt
195
- ind, result, err = ctxt.index, ctxt.result, ctxt.error
196
- err_ind, err_pos = -1, -1
197
- for p in @alts
198
- ctxt.reset_error
199
- ctxt.index, ctxt.result = ind, result
200
- return true if p._parse(ctxt)
201
- if ctxt.error.index > err_pos
202
- err, err_ind, err_pos = ctxt.error, ctxt.index, ctxt.error.index
640
+
641
+
642
+ class BestParser < Parser # :nodoc:
643
+ init :alts, :longer
644
+ def _parse ctxt
645
+ best_result, best_ind = nil, -1
646
+ err_ind, err_pos = -1, -1
647
+ ind, result, err = ctxt.index, ctxt.result, ctxt.error
648
+ for p in @alts
649
+ ctxt.reset_error
650
+ ctxt.index, ctxt.result = ind, result
651
+ if p._parse(ctxt)
652
+ err, now_ind = nil, ctxt.index
653
+ if best_ind == -1 || (now_ind != best_ind && @longer == (now_ind > best_ind))
654
+ best_result, best_ind = ctxt.result, now_ind
655
+ end
656
+ elsif best_ind < 0 # no good match found yet.
657
+ if ctxt.error.index > err_pos
658
+ err_ind, err_pos = ctxt.index, ctxt.error.index
659
+ end
660
+ err = Failures.add_error(err, ctxt.error)
661
+ end
662
+ end
663
+ if best_ind >= 0
664
+ ctxt.index = best_ind
665
+ return ctxt.retn(best_result)
666
+ else
667
+ ctxt.error, ctxt.index = err, err_ind
668
+ return false
203
669
  end
204
670
  end
205
- ctxt.index, ctxt.error = err_ind, err
206
- return false
207
671
  end
208
- def withLookahead(n)
209
- AltParser.new(@alts, n)
672
+
673
+ class BoundParser < Parser # :nodoc:
674
+ init :parser, :proc
675
+ def _parse ctxt
676
+ return false unless @parser._parse(ctxt)
677
+ @proc.call(ctxt.result)._parse ctxt
678
+ end
210
679
  end
211
- def | other
212
- AltParser.new(@alts.dup << autobox_parser(other)).setName(name)
680
+
681
+ class BoundnParser < Parser # :nodoc:
682
+ init :parser, :proc
683
+ def _parse ctxt
684
+ return false unless @parser._parse(ctxt)
685
+ @proc.call(*ctxt.result)._parse ctxt
686
+ end
213
687
  end
214
- end
215
688
 
689
+ class MapParser < Parser # :nodoc:
690
+ init :parser, :proc
691
+ def _parse ctxt
692
+ return false unless @parser._parse(ctxt)
693
+ ctxt.result = @proc.call(ctxt.result)
694
+ true
695
+ end
696
+ end
697
+
698
+ class MapnParser < Parser # :nodoc:
699
+ init :parser, :proc
700
+ def _parse ctxt
701
+ return false unless @parser._parse(ctxt)
702
+ ctxt.result = @proc.call(*ctxt.result)
703
+ true
704
+ end
705
+ end
216
706
 
217
- class BestParser < Parser
218
- init :alts, :longer
219
- def _parse ctxt
220
- best_result, best_ind = nil, -1
221
- err_ind, err_pos = -1, -1
222
- ind, result, err = ctxt.index, ctxt.result, ctxt.error
223
- for p in @alts
224
- ctxt.reset_error
225
- ctxt.index, ctxt.result = ind, result
226
- if p._parse(ctxt)
227
- err, now_ind = nil, ctxt.index
228
- if best_ind == -1 || (now_ind != best_ind && @longer == (now_ind > best_ind))
229
- best_result, best_ind = ctxt.result, now_ind
707
+ class SequenceParser < Parser # :nodoc:
708
+ init :parsers, :proc
709
+ def _parse ctxt
710
+ if @proc.nil?
711
+ for p in @parsers
712
+ return false unless p._parse(ctxt)
230
713
  end
231
- elsif best_ind < 0 # no good match found yet.
232
- if ctxt.error.index > err_pos
233
- err_ind, err_pos = ctxt.index, ctxt.error.index
714
+ else
715
+ results = []
716
+ for p in @parsers
717
+ return false unless p._parse(ctxt)
718
+ results << ctxt.result
234
719
  end
235
- err = Failures.add_error(err, ctxt.error)
720
+ ctxt.retn(@proc.call(*results))
236
721
  end
722
+ return true
237
723
  end
238
- if best_ind >= 0
239
- ctxt.index = best_ind
240
- return ctxt.retn(best_result)
241
- else
242
- ctxt.error, ctxt.index = err, err_ind
243
- return false
724
+ def seq(other, &block)
725
+ SequenceParser.new(@parsers.dup << other, &block)
244
726
  end
245
727
  end
246
- end
247
728
 
248
- class BoundParser < Parser
249
- init :parser, :proc
250
- def _parse ctxt
251
- return false unless @parser._parse(ctxt)
252
- @proc.call(ctxt.result)._parse ctxt
729
+ class FollowedParser < Parser # :nodoc:
730
+ init :p1, :p2
731
+ def _parse ctxt
732
+ return false unless @p1._parse ctxt
733
+ result = ctxt.result
734
+ return false unless @p2._parse ctxt
735
+ ctxt.retn(result)
736
+ end
253
737
  end
254
- end
255
738
 
256
- class BoundnParser < Parser
257
- init :parser, :proc
258
- def _parse ctxt
259
- return false unless @parser._parse(ctxt)
260
- @proc.call(*ctxt.result)._parse ctxt
739
+ class SatisfiesParser < Parser # :nodoc:
740
+ init :pred, :expected
741
+ def _parse ctxt
742
+ elem = nil
743
+ if ctxt.eof || !@pred.call(elem = ctxt.current)
744
+ return ctxt.expecting(@expected)
745
+ end
746
+ ctxt.next
747
+ ctxt.retn elem
748
+ end
261
749
  end
262
- end
263
750
 
264
- class MapParser < Parser
265
- init :parser, :proc
266
- def _parse ctxt
267
- return false unless @parser._parse(ctxt)
268
- ctxt.result = @proc.call(ctxt.result)
269
- true
751
+ class AnyParser < Parser # :nodoc:
752
+ def _parse ctxt
753
+ return ctxt.expecting if ctxt.eof
754
+ result = ctxt.current
755
+ ctxt.next
756
+ ctxt.retn result
757
+ end
270
758
  end
271
- end
272
759
 
273
- class MapnParser < Parser
274
- init :parser, :proc
275
- def _parse ctxt
276
- return false unless @parser._parse(ctxt)
277
- ctxt.result = @proc.call(*ctxt.result)
278
- true
760
+ class EofParser < Parser # :nodoc:
761
+ init :msg
762
+ def _parse ctxt
763
+ return true if ctxt.eof
764
+ return ctxt.expecting(@msg)
765
+ end
279
766
  end
280
- end
281
767
 
282
- class SequenceParser < Parser
283
- init :parsers, :proc
284
- def _parse ctxt
285
- if @proc.nil?
286
- for p in @parsers
287
- return false unless p._parse(ctxt)
768
+ class RegexpParser < Parser # :nodoc:
769
+ init :ptn, :msg
770
+ def _parse ctxt
771
+ scanner = ctxt.scanner
772
+ result = scanner.check @ptn
773
+ if result.nil?
774
+ ctxt.expecting(@msg)
775
+ else
776
+ ctxt.advance(scanner.matched_size)
777
+ ctxt.retn(result)
288
778
  end
289
- else
290
- results = []
291
- for p in @parsers
292
- return false unless p._parse(ctxt)
293
- results << ctxt.result
779
+ end
780
+ end
781
+
782
+ class AreParser < Parser # :nodoc:
783
+ init :vals, :msg
784
+ def _parse ctxt
785
+ if @vals.length > ctxt.available
786
+ return ctxt.expecting(@msg)
294
787
  end
295
- ctxt.retn(@proc.call(*results))
296
- end
297
- return true
298
- end
299
- def seq(other, &block)
300
- # TypeChecker.check_arg_type Parser, other, :seq
301
- SequenceParser.new(@parsers.dup << other, &block)
302
- end
303
- def_sig :seq, Parser
304
- end
305
-
306
- class FollowedParser < Parser
307
- init :p1, :p2
308
- def _parse ctxt
309
- return false unless @p1._parse ctxt
310
- result = ctxt.result
311
- return false unless @p2._parse ctxt
312
- ctxt.retn(result)
313
- end
314
- end
315
-
316
- class SatisfiesParser < Parser
317
- init :pred, :expected
318
- def _parse ctxt
319
- elem = nil
320
- if ctxt.eof || !@pred.call(elem = ctxt.current)
321
- return ctxt.expecting(@expected)
322
- end
323
- ctxt.next
324
- ctxt.retn elem
325
- end
326
- end
327
-
328
- class AnyParser < Parser
329
- def _parse ctxt
330
- return ctxt.expecting if ctxt.eof
331
- result = ctxt.current
332
- ctxt.next
333
- ctxt.retn result
334
- end
335
- end
336
-
337
- class EofParser < Parser
338
- init :msg
339
- def _parse ctxt
340
- return true if ctxt.eof
341
- return ctxt.expecting(@msg)
342
- end
343
- end
344
-
345
- class RegexpParser < Parser
346
- init :ptn, :msg
347
- def _parse ctxt
348
- scanner = ctxt.scanner
349
- result = scanner.check @ptn
350
- if result.nil?
351
- ctxt.expecting(@msg)
352
- else
353
- ctxt.advance(scanner.matched_size)
354
- ctxt.retn(result)
788
+ cur = 0
789
+ for cur in (0...@vals.length)
790
+ if @vals[cur] != ctxt.peek(cur)
791
+ return ctxt.expecting(@msg)
792
+ end
793
+ end
794
+ ctxt.advance(@vals.length)
795
+ ctxt.retn @vals
355
796
  end
356
797
  end
357
- end
358
798
 
359
- class AreParser < Parser
360
- init :vals, :msg
361
- def _parse ctxt
362
- if @vals.length > ctxt.available
363
- return ctxt.expecting(@msg)
799
+ class StringCaseInsensitiveParser < Parser # :nodoc:
800
+ init :str, :msg
801
+ def _downcase c
802
+ case when c.ord >= ?A.ord && c.ord <= ?Z.ord then (c.ord + (?a.ord - ?A.ord)).chr else c end
364
803
  end
365
- cur = 0
366
- for cur in (0...@vals.length)
367
- if @vals[cur] != ctxt.peek(cur)
804
+ private :_downcase
805
+
806
+ def _parse ctxt
807
+ if @str.length > ctxt.available
368
808
  return ctxt.expecting(@msg)
369
809
  end
810
+ cur = 0
811
+ for cur in (0...@str.length)
812
+ if _downcase(@str[cur]) != _downcase(ctxt.peek(cur))
813
+ return ctxt.expecting(@msg)
814
+ end
815
+ end
816
+ result = ctxt.src[ctxt.index, @str.length]
817
+ ctxt.advance(@str.length)
818
+ ctxt.retn result
370
819
  end
371
- ctxt.advance(@vals.length)
372
- ctxt.retn @vals
373
820
  end
374
- end
375
821
 
376
- class StringCaseInsensitiveParser < Parser
377
- init :str, :msg
378
- def _downcase c
379
- case when c.ord >= ?A.ord && c.ord <= ?Z.ord then (c.ord + (?a.ord - ?A.ord)).chr else c end
822
+ class FragmentParser < Parser # :nodoc:
823
+ init :parser
824
+ def _parse ctxt
825
+ ind = ctxt.index
826
+ return false unless @parser._parse ctxt
827
+ ctxt.retn(ctxt.src[ind, ctxt.index - ind])
828
+ end
380
829
  end
381
- private :_downcase
382
830
 
383
- def _parse ctxt
384
- if @str.length > ctxt.available
385
- return ctxt.expecting(@msg)
831
+ class TokenParser < Parser # :nodoc:
832
+ init :symbol, :parser
833
+ def _parse ctxt
834
+ ind = ctxt.index
835
+ return false unless @parser._parse ctxt
836
+ raw = ctxt.result
837
+ raw = ctxt.src[ind, ctxt.index - ind] unless raw.kind_of? String
838
+ ctxt.retn(Token.new(@symbol, raw, ind))
386
839
  end
387
- cur = 0
388
- for cur in (0...@str.length)
389
- if _downcase(@str[cur]) != _downcase(ctxt.peek(cur))
390
- return ctxt.expecting(@msg)
391
- end
840
+ end
841
+
842
+ class NestedParser < Parser # :nodoc:
843
+ init :parser1, :parser2
844
+ def _parse ctxt
845
+ ind = ctxt.index
846
+ return false unless @parser1._parse ctxt
847
+ _run_nested(ind, ctxt, ctxt.result, @parser2)
392
848
  end
393
- result = ctxt.src[ctxt.index, @str.length]
394
- ctxt.advance(@str.length)
395
- ctxt.retn result
396
- end
397
- end
398
-
399
- class FragmentParser < Parser
400
- init :parser
401
- def _parse ctxt
402
- ind = ctxt.index
403
- return false unless @parser._parse ctxt
404
- ctxt.retn(ctxt.src[ind, ctxt.index - ind])
405
- end
406
- end
407
-
408
- class TokenParser < Parser
409
- init :symbol, :parser
410
- def _parse ctxt
411
- ind = ctxt.index
412
- return false unless @parser._parse ctxt
413
- raw = ctxt.result
414
- raw = ctxt.src[ind, ctxt.index - ind] unless raw.kind_of? String
415
- ctxt.retn(Token.new(@symbol, raw, ind))
416
- end
417
- end
418
-
419
- class NestedParser < Parser
420
- init :parser1, :parser2
421
- def _parse ctxt
422
- ind = ctxt.index
423
- return false unless @parser1._parse ctxt
424
- _run_nested(ind, ctxt, ctxt.result, @parser2)
425
- end
426
- private
427
- def _run_nested(start, ctxt, src, parser)
428
- ctxt.error = nil
429
- new_ctxt = nil
430
- if src.kind_of? String
431
- new_ctxt = ParseContext.new(src)
432
- return true if _run_parser parser, ctxt, new_ctxt
433
- ctxt.index = start + new_ctxt.index
434
- elsif src.kind_of? Array
435
- new_ctxt = ParseContext.new(src)
436
- return true if _run_parser parser, ctxt, new_ctxt
437
- ctxt.index = start + _get_index(new_ctxt) unless new_ctxt.eof
438
- else
439
- new_ctxt = ParseContext.new([src])
440
- return true if _run_parser parser, ctxt, new_ctxt
441
- ctxt.index = ind unless new_ctxt.eof
442
- end
443
- ctxt.error.index = ctxt.index
444
- false
445
- end
446
- def _get_index ctxt
447
- cur = ctxt.current
448
- return cur.index if cur.respond_to? :index
449
- ctxt.index
450
- end
451
- def _run_parser parser, old_ctxt, new_ctxt
452
- if parser._parse new_ctxt
453
- old_ctxt.result = new_ctxt.result
454
- true
455
- else
456
- old_ctxt.error = new_ctxt.error
849
+ private
850
+ def _run_nested(start, ctxt, src, parser)
851
+ ctxt.error = nil
852
+ new_ctxt = nil
853
+ if src.kind_of? String
854
+ new_ctxt = ParseContext.new(src)
855
+ return true if _run_parser parser, ctxt, new_ctxt
856
+ ctxt.index = start + new_ctxt.index
857
+ elsif src.kind_of? Array
858
+ new_ctxt = ParseContext.new(src)
859
+ return true if _run_parser parser, ctxt, new_ctxt
860
+ ctxt.index = start + _get_index(new_ctxt) unless new_ctxt.eof
861
+ else
862
+ new_ctxt = ParseContext.new([src])
863
+ return true if _run_parser parser, ctxt, new_ctxt
864
+ ctxt.index = ind unless new_ctxt.eof
865
+ end
866
+ ctxt.error.index = ctxt.index
457
867
  false
458
868
  end
869
+ def _get_index ctxt
870
+ cur = ctxt.current
871
+ return cur.index if cur.respond_to? :index
872
+ ctxt.index
873
+ end
874
+ def _run_parser parser, old_ctxt, new_ctxt
875
+ if parser._parse new_ctxt
876
+ old_ctxt.result = new_ctxt.result
877
+ true
878
+ else
879
+ old_ctxt.error = new_ctxt.error
880
+ false
881
+ end
882
+ end
459
883
  end
460
- end
461
884
 
462
- class WatchParser < Parser
463
- init :proc
464
- def _parse ctxt
465
- @proc.call(ctxt.result)
466
- true
885
+ class WatchParser < Parser # :nodoc:
886
+ init :proc
887
+ def _parse ctxt
888
+ @proc.call(ctxt.result)
889
+ true
890
+ end
467
891
  end
468
- end
469
892
 
470
- class WatchnParser < Parser
471
- init :proc
472
- def _parse ctxt
473
- @proc.call(*ctxt.result)
474
- true
893
+ class WatchnParser < Parser # :nodoc:
894
+ init :proc
895
+ def _parse ctxt
896
+ @proc.call(*ctxt.result)
897
+ true
898
+ end
475
899
  end
476
- end
477
900
 
478
- class MapCurrentParser < Parser
479
- init :proc
480
- def _parse ctxt
481
- ctxt.result = @proc.call(ctxt.result)
482
- true
901
+ class MapCurrentParser < Parser # :nodoc:
902
+ init :proc
903
+ def _parse ctxt
904
+ ctxt.result = @proc.call(ctxt.result)
905
+ true
906
+ end
483
907
  end
484
- end
485
908
 
486
- class MapnCurrentParser < Parser
487
- init :proc
488
- def _parse ctxt
489
- ctxt.result = @proc.call(*ctxt.result)
490
- true
909
+ class MapnCurrentParser < Parser # :nodoc:
910
+ init :proc
911
+ def _parse ctxt
912
+ ctxt.result = @proc.call(*ctxt.result)
913
+ true
914
+ end
491
915
  end
492
- end
493
916
 
494
- class Repeat_Parser < Parser
495
- init :parser, :times
496
- def _parse ctxt
497
- @times.times do
498
- return false unless @parser._parse ctxt
917
+ class Repeat_Parser < Parser # :nodoc:
918
+ init :parser, :times
919
+ def _parse ctxt
920
+ @times.times do
921
+ return false unless @parser._parse ctxt
922
+ end
923
+ return true
499
924
  end
500
- return true
501
925
  end
502
- end
503
926
 
504
- class RepeatParser < Parser
505
- init :parser, :times
506
- def _parse ctxt
507
- result = []
508
- @times.times do
509
- return false unless @parser._parse ctxt
510
- result << ctxt.result
927
+ class RepeatParser < Parser # :nodoc:
928
+ init :parser, :times
929
+ def _parse ctxt
930
+ result = []
931
+ @times.times do
932
+ return false unless @parser._parse ctxt
933
+ result << ctxt.result
934
+ end
935
+ return ctxt.retn(result)
511
936
  end
512
- return ctxt.retn(result)
513
937
  end
514
- end
515
938
 
516
- class Many_Parser < Parser
517
- init :parser, :least
518
- def _parse ctxt
519
- @least.times do
520
- return false unless @parser._parse ctxt
521
- end
522
- while true
523
- ind = ctxt.index
524
- if @parser._parse ctxt
525
- return true if ind == ctxt.index # infinite loop
526
- next
939
+ class Many_Parser < Parser # :nodoc:
940
+ init :parser, :least
941
+ def _parse ctxt
942
+ @least.times do
943
+ return false unless @parser._parse ctxt
944
+ end
945
+ while true
946
+ ind = ctxt.index
947
+ if @parser._parse ctxt
948
+ return true if ind == ctxt.index # infinite loop
949
+ next
950
+ end
951
+ return ind == ctxt.index
527
952
  end
528
- return ind == ctxt.index
529
953
  end
530
954
  end
531
- end
532
955
 
533
- class ManyParser < Parser
534
- init :parser, :least
535
- def _parse ctxt
536
- result = []
537
- @least.times do
538
- return false unless @parser._parse ctxt
539
- result << ctxt.result
540
- end
541
- while true
542
- ind = ctxt.index
543
- if @parser._parse ctxt
956
+ class ManyParser < Parser # :nodoc:
957
+ init :parser, :least
958
+ def _parse ctxt
959
+ result = []
960
+ @least.times do
961
+ return false unless @parser._parse ctxt
544
962
  result << ctxt.result
545
- return ctxt.retn(result) if ind == ctxt.index # infinite loop
546
- next
547
963
  end
548
- if ind == ctxt.index
549
- return ctxt.retn(result)
550
- else
551
- return false
964
+ while true
965
+ ind = ctxt.index
966
+ if @parser._parse ctxt
967
+ result << ctxt.result
968
+ return ctxt.retn(result) if ind == ctxt.index # infinite loop
969
+ next
970
+ end
971
+ if ind == ctxt.index
972
+ return ctxt.retn(result)
973
+ else
974
+ return false
975
+ end
552
976
  end
553
977
  end
554
978
  end
555
- end
556
979
 
557
- class Some_Parser < Parser
558
- init :parser, :least, :max
559
- def _parse ctxt
560
- @least.times { return false unless @parser._parse ctxt }
561
- (@least...@max).each do
562
- ind = ctxt.index
563
- if @parser._parse ctxt
564
- return true if ind == ctxt.index # infinite loop
565
- next
980
+ class Some_Parser < Parser # :nodoc:
981
+ init :parser, :least, :max
982
+ def _parse ctxt
983
+ @least.times { return false unless @parser._parse ctxt }
984
+ (@least...@max).each do
985
+ ind = ctxt.index
986
+ if @parser._parse ctxt
987
+ return true if ind == ctxt.index # infinite loop
988
+ next
989
+ end
990
+ return ind == ctxt.index
566
991
  end
567
- return ind == ctxt.index
992
+ return true
568
993
  end
569
- return true
570
994
  end
571
- end
572
995
 
573
- class SomeParser < Parser
574
- init :parser, :least, :max
575
- def _parse ctxt
576
- result = []
577
- @least.times do
578
- return false unless @parser._parse ctxt
579
- result << ctxt.result
580
- end
581
- (@least...@max).each do
582
- ind = ctxt.index
583
- if @parser._parse ctxt
996
+ class SomeParser < Parser # :nodoc:
997
+ init :parser, :least, :max
998
+ def _parse ctxt
999
+ result = []
1000
+ @least.times do
1001
+ return false unless @parser._parse ctxt
584
1002
  result << ctxt.result
585
- return ctxt.retn(result) if ind == ctxt.index # infinite loop
586
- next
587
1003
  end
588
- if ind == ctxt.index
589
- return ctxt.retn(result)
590
- else
591
- return false
1004
+ (@least...@max).each do
1005
+ ind = ctxt.index
1006
+ if @parser._parse ctxt
1007
+ result << ctxt.result
1008
+ return ctxt.retn(result) if ind == ctxt.index # infinite loop
1009
+ next
1010
+ end
1011
+ if ind == ctxt.index
1012
+ return ctxt.retn(result)
1013
+ else
1014
+ return false
1015
+ end
592
1016
  end
1017
+ return ctxt.retn(result)
593
1018
  end
594
- return ctxt.retn(result)
595
1019
  end
596
- end
597
1020
 
598
- class OneParser < Parser
599
- def _parse _ctxt
600
- true
1021
+ class OneParser < Parser # :nodoc:
1022
+ def _parse _ctxt
1023
+ true
1024
+ end
601
1025
  end
602
- end
603
1026
 
604
- class ZeroParser < Parser
605
- def _parse ctxt
606
- return ctxt.failure
1027
+ class ZeroParser < Parser # :nodoc:
1028
+ def _parse ctxt
1029
+ return ctxt.failure
1030
+ end
607
1031
  end
608
- end
609
1032
 
610
- class GetIndexParser < Parser
611
- def _parse ctxt
612
- ctxt.retn(ctxt.index)
1033
+ class GetIndexParser < Parser # :nodoc:
1034
+ def _parse ctxt
1035
+ ctxt.retn(ctxt.index)
1036
+ end
613
1037
  end
614
- end
615
- class SetIndexParser < Parser
616
- init :index
617
- def _parse ctxt
618
- ctxt.index = @index
1038
+ class SetIndexParser < Parser # :nodoc:
1039
+ init :index
1040
+ def _parse ctxt
1041
+ ctxt.index = @index
1042
+ end
619
1043
  end
620
- end
621
1044
 
622
- Nil = ValueParser.new(nil)
1045
+ Nil = ValueParser.new(nil) # :nodoc:
623
1046
 
624
1047
  end # module