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.
- checksums.yaml +4 -4
- data/lib/rparsec/context.rb +80 -78
- data/lib/rparsec/error.rb +21 -18
- data/lib/rparsec/expressions.rb +75 -163
- data/lib/rparsec/functor_mixin.rb +102 -0
- data/lib/rparsec/functors.rb +151 -255
- data/lib/rparsec/id_monad.rb +13 -11
- data/lib/rparsec/keywords.rb +95 -93
- data/lib/rparsec/locator.rb +27 -25
- data/lib/rparsec/misc.rb +14 -97
- data/lib/rparsec/monad.rb +53 -50
- data/lib/rparsec/operator_table.rb +89 -0
- data/lib/rparsec/operators.rb +85 -81
- data/lib/rparsec/parser.rb +397 -819
- data/lib/rparsec/parser_monad.rb +18 -16
- data/lib/rparsec/parsers.rb +922 -499
- data/lib/rparsec/token.rb +32 -30
- data/lib/rparsec.rb +7 -4
- metadata +11 -3
data/lib/rparsec/parsers.rb
CHANGED
@@ -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
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
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
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
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
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
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
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
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
|
-
|
38
|
-
|
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
|
-
|
41
|
-
|
42
|
-
|
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
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
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
|
-
#
|
58
|
-
#
|
59
|
-
|
60
|
-
|
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
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
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
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
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
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
return
|
101
|
-
|
102
|
-
|
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
|
-
|
105
|
-
|
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
|
110
|
-
|
111
|
-
|
112
|
-
|
438
|
+
class ValueParser < Parser # :nodoc:
|
439
|
+
init :value
|
440
|
+
def _parse ctxt
|
441
|
+
ctxt.retn @value
|
442
|
+
end
|
113
443
|
end
|
114
|
-
|
115
|
-
|
444
|
+
|
445
|
+
class LazyParser < Parser # :nodoc:
|
446
|
+
init :block
|
447
|
+
def _parse ctxt
|
448
|
+
@block.call._parse ctxt
|
449
|
+
end
|
116
450
|
end
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
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
|
-
|
123
|
-
|
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
|
128
|
-
|
129
|
-
|
130
|
-
|
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
|
-
|
133
|
-
|
134
|
-
|
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
|
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
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
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
|
163
|
-
|
164
|
-
|
165
|
-
|
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
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
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
|
-
|
180
|
-
|
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
|
-
|
183
|
-
|
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
|
-
|
191
|
-
|
192
|
-
|
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
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
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
|
-
|
209
|
-
|
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
|
-
|
212
|
-
|
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
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
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
|
-
|
232
|
-
|
233
|
-
|
714
|
+
else
|
715
|
+
results = []
|
716
|
+
for p in @parsers
|
717
|
+
return false unless p._parse(ctxt)
|
718
|
+
results << ctxt.result
|
234
719
|
end
|
235
|
-
|
720
|
+
ctxt.retn(@proc.call(*results))
|
236
721
|
end
|
722
|
+
return true
|
237
723
|
end
|
238
|
-
|
239
|
-
|
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
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
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
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
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
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
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
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
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
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
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
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
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
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
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
|
360
|
-
|
361
|
-
|
362
|
-
|
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
|
-
|
366
|
-
|
367
|
-
|
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
|
377
|
-
|
378
|
-
|
379
|
-
|
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
|
-
|
384
|
-
|
385
|
-
|
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
|
-
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
|
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
|
-
|
394
|
-
ctxt
|
395
|
-
|
396
|
-
|
397
|
-
|
398
|
-
|
399
|
-
|
400
|
-
|
401
|
-
|
402
|
-
|
403
|
-
|
404
|
-
|
405
|
-
|
406
|
-
|
407
|
-
|
408
|
-
|
409
|
-
|
410
|
-
|
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
|
-
|
464
|
-
|
465
|
-
|
466
|
-
|
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
|
-
|
472
|
-
|
473
|
-
|
474
|
-
|
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
|
-
|
480
|
-
|
481
|
-
|
482
|
-
|
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
|
-
|
488
|
-
|
489
|
-
|
490
|
-
|
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
|
-
|
496
|
-
|
497
|
-
|
498
|
-
|
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
|
-
|
506
|
-
|
507
|
-
|
508
|
-
|
509
|
-
|
510
|
-
|
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
|
-
|
518
|
-
|
519
|
-
|
520
|
-
|
521
|
-
|
522
|
-
|
523
|
-
|
524
|
-
|
525
|
-
|
526
|
-
|
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
|
-
|
535
|
-
|
536
|
-
|
537
|
-
|
538
|
-
|
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
|
-
|
549
|
-
|
550
|
-
|
551
|
-
|
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
|
-
|
559
|
-
|
560
|
-
|
561
|
-
|
562
|
-
|
563
|
-
|
564
|
-
|
565
|
-
|
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
|
992
|
+
return true
|
568
993
|
end
|
569
|
-
return true
|
570
994
|
end
|
571
|
-
end
|
572
995
|
|
573
|
-
class SomeParser < Parser
|
574
|
-
|
575
|
-
|
576
|
-
|
577
|
-
|
578
|
-
|
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
|
-
|
589
|
-
|
590
|
-
|
591
|
-
|
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
|
-
|
600
|
-
|
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
|
-
|
606
|
-
|
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
|
-
|
612
|
-
|
1033
|
+
class GetIndexParser < Parser # :nodoc:
|
1034
|
+
def _parse ctxt
|
1035
|
+
ctxt.retn(ctxt.index)
|
1036
|
+
end
|
613
1037
|
end
|
614
|
-
|
615
|
-
|
616
|
-
|
617
|
-
|
618
|
-
|
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
|