rparsec2 1.1.0

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.
@@ -0,0 +1,23 @@
1
+ module RParsec
2
+
3
+ class ParserMonad
4
+ def fail msg
5
+ FailureParser.new(msg)
6
+ end
7
+
8
+ def value v
9
+ return Nil if v.nil?
10
+ ValueParser.new(v);
11
+ end
12
+
13
+ def bind(v, &proc)
14
+ return v unless proc
15
+ BoundParser.new(v, proc);
16
+ end
17
+
18
+ def mplus(p1, p2)
19
+ PlusParser.new([p1, p2]);
20
+ end
21
+ end
22
+
23
+ end # module
@@ -0,0 +1,624 @@
1
+ require 'rparsec/parser'
2
+
3
+ module RParsec
4
+
5
+ class FailureParser < Parser
6
+ init :msg
7
+ def _parse ctxt
8
+ return ctxt.failure(@msg)
9
+ end
10
+ end
11
+
12
+ class ValueParser < Parser
13
+ init :value
14
+ def _parse ctxt
15
+ ctxt.retn @value
16
+ end
17
+ end
18
+
19
+ class LazyParser < Parser
20
+ init :block
21
+ def _parse ctxt
22
+ @block.call._parse ctxt
23
+ end
24
+ end
25
+
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
36
+
37
+ class << self
38
+ private
39
+
40
+ def get_first_element(err)
41
+ while err.kind_of?(Array)
42
+ err = err[0]
43
+ end
44
+ err
45
+ end
46
+
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
52
+ end
53
+ end
54
+ end
55
+
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
68
+
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
77
+ end
78
+ return ctxt.retn(@symbol) if interrupted
79
+ ok
80
+ end
81
+ end
82
+
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
95
+
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
103
+ end
104
+ def atomize
105
+ self
106
+ end
107
+ end
108
+
109
+ class LookAheadSensitiveParser < Parser
110
+ def initialize(la = 1)
111
+ super()
112
+ @lookahead = la
113
+ end
114
+ def visible(ctxt, n)
115
+ ctxt.index - n < @lookahead
116
+ 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)
121
+ end
122
+ def not(msg = "#{self} unexpected")
123
+ NotParser.new(self, msg, @lookahead)
124
+ end
125
+ end
126
+
127
+ class NotParser < LookAheadSensitiveParser
128
+ def initialize(parser, msg, la = 1)
129
+ super(la)
130
+ @parser, @msg, @name = parser, msg, "~#{parser.name}"
131
+ end
132
+ def _parse ctxt
133
+ ind = ctxt.index
134
+ if @parser._parse ctxt
135
+ ctxt.index = ind
136
+ return ctxt.expecting(@msg)
137
+ 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
+ end
147
+ end
148
+
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)
159
+ end
160
+ end
161
+
162
+ class PlusParser < LookAheadSensitiveParser
163
+ def initialize(alts, la = 1)
164
+ super(la)
165
+ @alts = alts
166
+ 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)
175
+ end
176
+ ctxt.error = err
177
+ return false
178
+ end
179
+ def withLookahead(n)
180
+ PlusParser.new(@alts, n)
181
+ end
182
+ def plus other
183
+ PlusParser.new(@alts.dup << other, @lookahead).setName(name)
184
+ end
185
+ def_sig :plus, Parser
186
+ end
187
+
188
+
189
+ class AltParser < LookAheadSensitiveParser
190
+ def initialize(alts, la = 1)
191
+ super(la)
192
+ @alts, @lookahead = alts, la
193
+ 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
203
+ end
204
+ end
205
+ ctxt.index, ctxt.error = err_ind, err
206
+ return false
207
+ end
208
+ def withLookahead(n)
209
+ AltParser.new(@alts, n)
210
+ end
211
+ def | other
212
+ AltParser.new(@alts.dup << autobox_parser(other)).setName(name)
213
+ end
214
+ end
215
+
216
+
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
230
+ 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
234
+ end
235
+ err = Failures.add_error(err, ctxt.error)
236
+ end
237
+ 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
244
+ end
245
+ end
246
+ end
247
+
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
253
+ end
254
+ end
255
+
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
261
+ end
262
+ end
263
+
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
270
+ end
271
+ end
272
+
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
279
+ end
280
+ end
281
+
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)
288
+ end
289
+ else
290
+ results = []
291
+ for p in @parsers
292
+ return false unless p._parse(ctxt)
293
+ results << ctxt.result
294
+ 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)
355
+ end
356
+ end
357
+ end
358
+
359
+ class AreParser < Parser
360
+ init :vals, :msg
361
+ def _parse ctxt
362
+ if @vals.length > ctxt.available
363
+ return ctxt.expecting(@msg)
364
+ end
365
+ cur = 0
366
+ for cur in (0...@vals.length)
367
+ if @vals[cur] != ctxt.peek(cur)
368
+ return ctxt.expecting(@msg)
369
+ end
370
+ end
371
+ ctxt.advance(@vals.length)
372
+ ctxt.retn @vals
373
+ end
374
+ end
375
+
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
380
+ end
381
+ private :_downcase
382
+
383
+ def _parse ctxt
384
+ if @str.length > ctxt.available
385
+ return ctxt.expecting(@msg)
386
+ 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
392
+ 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
457
+ false
458
+ end
459
+ end
460
+ end
461
+
462
+ class WatchParser < Parser
463
+ init :proc
464
+ def _parse ctxt
465
+ @proc.call(ctxt.result)
466
+ true
467
+ end
468
+ end
469
+
470
+ class WatchnParser < Parser
471
+ init :proc
472
+ def _parse ctxt
473
+ @proc.call(*ctxt.result)
474
+ true
475
+ end
476
+ end
477
+
478
+ class MapCurrentParser < Parser
479
+ init :proc
480
+ def _parse ctxt
481
+ ctxt.result = @proc.call(ctxt.result)
482
+ true
483
+ end
484
+ end
485
+
486
+ class MapnCurrentParser < Parser
487
+ init :proc
488
+ def _parse ctxt
489
+ ctxt.result = @proc.call(*ctxt.result)
490
+ true
491
+ end
492
+ end
493
+
494
+ class Repeat_Parser < Parser
495
+ init :parser, :times
496
+ def _parse ctxt
497
+ @times.times do
498
+ return false unless @parser._parse ctxt
499
+ end
500
+ return true
501
+ end
502
+ end
503
+
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
511
+ end
512
+ return ctxt.retn(result)
513
+ end
514
+ end
515
+
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
527
+ end
528
+ return ind == ctxt.index
529
+ end
530
+ end
531
+ end
532
+
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
544
+ result << ctxt.result
545
+ return ctxt.retn(result) if ind == ctxt.index # infinite loop
546
+ next
547
+ end
548
+ if ind == ctxt.index
549
+ return ctxt.retn(result)
550
+ else
551
+ return false
552
+ end
553
+ end
554
+ end
555
+ end
556
+
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
566
+ end
567
+ return ind == ctxt.index
568
+ end
569
+ return true
570
+ end
571
+ end
572
+
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
584
+ result << ctxt.result
585
+ return ctxt.retn(result) if ind == ctxt.index # infinite loop
586
+ next
587
+ end
588
+ if ind == ctxt.index
589
+ return ctxt.retn(result)
590
+ else
591
+ return false
592
+ end
593
+ end
594
+ return ctxt.retn(result)
595
+ end
596
+ end
597
+
598
+ class OneParser < Parser
599
+ def _parse _ctxt
600
+ true
601
+ end
602
+ end
603
+
604
+ class ZeroParser < Parser
605
+ def _parse ctxt
606
+ return ctxt.failure
607
+ end
608
+ end
609
+
610
+ class GetIndexParser < Parser
611
+ def _parse ctxt
612
+ ctxt.retn(ctxt.index)
613
+ end
614
+ end
615
+ class SetIndexParser < Parser
616
+ init :index
617
+ def _parse ctxt
618
+ ctxt.index = @index
619
+ end
620
+ end
621
+
622
+ Nil = ValueParser.new(nil)
623
+
624
+ end # module
@@ -0,0 +1,43 @@
1
+ require 'rparsec/misc'
2
+
3
+ module RParsec
4
+
5
+ #
6
+ # Represents a token during lexical analysis.
7
+ #
8
+ class Token
9
+ extend DefHelper
10
+
11
+ def_ctor :kind, :text, :index
12
+
13
+ #
14
+ # The type of the token
15
+ #
16
+ attr_reader :kind
17
+
18
+ #
19
+ # The text of the matched range
20
+ #
21
+ attr_reader :text
22
+
23
+ #
24
+ # The starting index of the matched range
25
+ #
26
+ attr_reader :index
27
+
28
+ #
29
+ # The length of the token.
30
+ #
31
+ def length
32
+ @text.length
33
+ end
34
+
35
+ #
36
+ # String representation of the token.
37
+ #
38
+ def to_s
39
+ "#{@kind}: #{@text}"
40
+ end
41
+ end
42
+
43
+ end # module
data/lib/rparsec.rb ADDED
@@ -0,0 +1,7 @@
1
+ %w{
2
+ parsers operators keywords expressions
3
+ }.each {|lib| require "rparsec/#{lib}"}
4
+
5
+ module RParsec
6
+ VERSION = "1.1.0"
7
+ end