rparsec2 1.2.1 → 1.3.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.
Files changed (59) hide show
  1. checksums.yaml +4 -4
  2. data/lib/rparsec/alt_parser.rb +38 -0
  3. data/lib/rparsec/any_parser.rb +12 -0
  4. data/lib/rparsec/are_parser.rb +20 -0
  5. data/lib/rparsec/atom_parser.rb +16 -0
  6. data/lib/rparsec/best_parser.rb +44 -0
  7. data/lib/rparsec/bound_parser.rb +11 -0
  8. data/lib/rparsec/boundn_parser.rb +11 -0
  9. data/lib/rparsec/catch_parser.rb +17 -0
  10. data/lib/rparsec/context.rb +5 -3
  11. data/lib/rparsec/{misc.rb → def_helper.rb} +5 -8
  12. data/lib/rparsec/eof_parser.rb +11 -0
  13. data/lib/rparsec/error.rb +8 -12
  14. data/lib/rparsec/expect_parser.rb +18 -0
  15. data/lib/rparsec/expressions.rb +5 -19
  16. data/lib/rparsec/failure_parser.rb +10 -0
  17. data/lib/rparsec/failures.rb +31 -0
  18. data/lib/rparsec/followed_parser.rb +13 -0
  19. data/lib/rparsec/fragment_parser.rb +12 -0
  20. data/lib/rparsec/functor_mixin.rb +10 -31
  21. data/lib/rparsec/get_index_parser.rb +9 -0
  22. data/lib/rparsec/keywords.rb +9 -9
  23. data/lib/rparsec/lazy_parser.rb +10 -0
  24. data/lib/rparsec/locator.rb +9 -5
  25. data/lib/rparsec/look_ahead_sensitive_parser.rb +46 -0
  26. data/lib/rparsec/many__parser.rb +20 -0
  27. data/lib/rparsec/many_parser.rb +27 -0
  28. data/lib/rparsec/map_current_parser.rb +11 -0
  29. data/lib/rparsec/map_parser.rb +12 -0
  30. data/lib/rparsec/mapn_current_parser.rb +11 -0
  31. data/lib/rparsec/mapn_parser.rb +12 -0
  32. data/lib/rparsec/nested_parser.rb +47 -0
  33. data/lib/rparsec/not_parser.rb +27 -0
  34. data/lib/rparsec/one_parser.rb +9 -0
  35. data/lib/rparsec/operator_table.rb +29 -63
  36. data/lib/rparsec/parser.rb +14 -20
  37. data/lib/rparsec/parser_monad.rb +4 -17
  38. data/lib/rparsec/parsers.rb +52 -626
  39. data/lib/rparsec/peek_parser.rb +16 -0
  40. data/lib/rparsec/plus_parser.rb +32 -0
  41. data/lib/rparsec/regexp_parser.rb +17 -0
  42. data/lib/rparsec/repeat__parser.rb +13 -0
  43. data/lib/rparsec/repeat_parser.rb +15 -0
  44. data/lib/rparsec/satisfies_parser.rb +15 -0
  45. data/lib/rparsec/sequence_parser.rb +25 -0
  46. data/lib/rparsec/set_index_parser.rb +10 -0
  47. data/lib/rparsec/some__parser.rb +19 -0
  48. data/lib/rparsec/some_parser.rb +28 -0
  49. data/lib/rparsec/string_case_insensitive_parser.rb +26 -0
  50. data/lib/rparsec/throw_parser.rb +10 -0
  51. data/lib/rparsec/token.rb +9 -28
  52. data/lib/rparsec/token_parser.rb +14 -0
  53. data/lib/rparsec/value_parser.rb +10 -0
  54. data/lib/rparsec/watch_parser.rb +11 -0
  55. data/lib/rparsec/watchn_parser.rb +11 -0
  56. data/lib/rparsec/zero_parser.rb +9 -0
  57. data/lib/rparsec.rb +1 -1
  58. metadata +52 -7
  59. data/lib/rparsec/id_monad.rb +0 -19
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 4561cdd86a68228d3d19811f6d8cf77a2664c21c61fac3b368035d6be7d55df3
4
- data.tar.gz: bc34dfa71df4b91c505b6a27d5d3b23c3f6acc6c2542d77cebad140d78b670a9
3
+ metadata.gz: ce59ff665a46de4f47bc1cc49a0b6eba80901a691ed5d24b66309857cf01dbac
4
+ data.tar.gz: 3d015234cac23f1f2320d9ffdd44ac5b0cdc8308b20b1690d613dd881b7791ae
5
5
  SHA512:
6
- metadata.gz: a9731ba718453a5814d896bccc2221b7473c577a16a62b710fe4e723225ea616c3067022e7e7cd902d217d290c9f47553184de4197a0421dd2b3d96418f6ccad
7
- data.tar.gz: 89b2f4f0678b636570d6eb9d3b7ac0ac83555c64036a3ae9031c74df068a7603d028770bda66960c0933fa517a4c2b63249b772b18e4abae9f7b0523b3d8e49b
6
+ metadata.gz: 9be2831196854dee89ffd21ffc6850520b0d9b204314475039acd274241e5ad4db7286c2bef4a7a576c1c9e003050b94c574607a9b0947a13018742de7afa296
7
+ data.tar.gz: 300af123c05ac025a9f3294a6c628e05cf60b1551b1f9036a14598426e9cb720ee41506658ceacc7edad28cabb3fa5b721a5b30cc9e2ed7589766329b3668fdd
@@ -0,0 +1,38 @@
1
+ require "rparsec/look_ahead_sensitive_parser"
2
+
3
+ module RParsec
4
+ class AltParser < LookAheadSensitiveParser # :nodoc:
5
+ def initialize(alts, la = 1)
6
+ super(la)
7
+ @alts = alts
8
+ @lookahead = la
9
+ end
10
+ def _parse ctxt
11
+ ind = ctxt.index
12
+ result = ctxt.result
13
+ err = ctxt.error
14
+ err_ind = -1
15
+ err_pos = -1
16
+ for p in @alts
17
+ ctxt.reset_error
18
+ ctxt.index = ind
19
+ ctxt.result = result
20
+ return true if p._parse(ctxt)
21
+ if ctxt.error.index > err_pos
22
+ err = ctxt.error
23
+ err_ind = ctxt.index
24
+ err_pos = ctxt.error.index
25
+ end
26
+ end
27
+ ctxt.index = err_ind
28
+ ctxt.error = err
29
+ return false
30
+ end
31
+ def withLookahead(n)
32
+ AltParser.new(@alts, n)
33
+ end
34
+ def | other
35
+ AltParser.new(@alts.dup << autobox_parser(other)).tap { |p| p.name = name }
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,12 @@
1
+ require "rparsec/parser"
2
+
3
+ module RParsec
4
+ class AnyParser < Parser # :nodoc:
5
+ def _parse ctxt
6
+ return ctxt.expecting if ctxt.eof
7
+ result = ctxt.current
8
+ ctxt.next
9
+ ctxt.retn result
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,20 @@
1
+ require "rparsec/parser"
2
+
3
+ module RParsec
4
+ class AreParser < Parser # :nodoc:
5
+ init :vals, :msg
6
+ def _parse ctxt
7
+ if @vals.length > ctxt.available
8
+ return ctxt.expecting(@msg)
9
+ end
10
+ cur = 0
11
+ for cur in (0...@vals.length)
12
+ if @vals[cur] != ctxt.peek(cur)
13
+ return ctxt.expecting(@msg)
14
+ end
15
+ end
16
+ ctxt.advance(@vals.length)
17
+ ctxt.retn @vals
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,16 @@
1
+ require "rparsec/parser"
2
+
3
+ module RParsec
4
+ class AtomParser < Parser # :nodoc:
5
+ init :parser
6
+ def _parse ctxt
7
+ ind = ctxt.index
8
+ return true if @parser._parse ctxt
9
+ ctxt.index = ind
10
+ return false
11
+ end
12
+ def atomize
13
+ self
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,44 @@
1
+ require "rparsec/parser"
2
+ require "rparsec/failures"
3
+
4
+ module RParsec
5
+ class BestParser < Parser # :nodoc:
6
+ init :alts, :longer
7
+ def _parse ctxt
8
+ best_result = nil
9
+ best_ind = -1
10
+ err_ind = -1
11
+ err_pos = -1
12
+ ind = ctxt.index
13
+ result = ctxt.result
14
+ err = ctxt.error
15
+ for p in @alts
16
+ ctxt.reset_error
17
+ ctxt.index = ind
18
+ ctxt.result = result
19
+ if p._parse(ctxt)
20
+ err = nil
21
+ now_ind = ctxt.index
22
+ if best_ind == -1 || (now_ind != best_ind && @longer == (now_ind > best_ind))
23
+ best_result = ctxt.result
24
+ best_ind = now_ind
25
+ end
26
+ elsif best_ind < 0 # no good match found yet.
27
+ if ctxt.error.index > err_pos
28
+ err_ind = ctxt.index
29
+ err_pos = ctxt.error.index
30
+ end
31
+ err = Failures.add_error(err, ctxt.error)
32
+ end
33
+ end
34
+ if best_ind >= 0
35
+ ctxt.index = best_ind
36
+ return ctxt.retn(best_result)
37
+ else
38
+ ctxt.error = err
39
+ ctxt.index = err_ind
40
+ return false
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,11 @@
1
+ require "rparsec/parser"
2
+
3
+ module RParsec
4
+ class BoundParser < Parser # :nodoc:
5
+ init :parser, :proc
6
+ def _parse ctxt
7
+ return false unless @parser._parse(ctxt)
8
+ @proc.call(ctxt.result)._parse ctxt
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ require "rparsec/parser"
2
+
3
+ module RParsec
4
+ class BoundnParser < Parser # :nodoc:
5
+ init :parser, :proc
6
+ def _parse ctxt
7
+ return false unless @parser._parse(ctxt)
8
+ @proc.call(*ctxt.result)._parse ctxt
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,17 @@
1
+ require "rparsec/parser"
2
+
3
+ module RParsec
4
+ class CatchParser < Parser # :nodoc:
5
+ init :symbol, :parser
6
+ def _parse ctxt
7
+ interrupted = true
8
+ ok = false
9
+ catch @symbol do
10
+ ok = @parser._parse(ctxt)
11
+ interrupted = false
12
+ end
13
+ return ctxt.retn(@symbol) if interrupted
14
+ ok
15
+ end
16
+ end
17
+ end
@@ -5,11 +5,13 @@ require 'strscan'
5
5
  module RParsec
6
6
 
7
7
  class ParseContext # :nodoc:
8
- attr_reader :error, :src, :index, :result
9
- attr_writer :error, :index, :result
8
+ attr_reader :src
9
+ attr_accessor :error, :index, :result
10
10
 
11
11
  def initialize(src, index=0, error=nil)
12
- @src, @index, @error = src, index, error
12
+ @src = src
13
+ @index = index
14
+ @error = error
13
15
  @scanner = nil
14
16
  end
15
17
 
@@ -6,18 +6,15 @@ module RParsec
6
6
  # Helpers for defining ctor.
7
7
  #
8
8
  module DefHelper # :nodoc:
9
- def def_ctor(*vars)
9
+ def def_readable(*vars)
10
+ attr_reader(*vars)
11
+
10
12
  define_method(:initialize) do |*params|
11
- vars.each_with_index do |var, i|
12
- instance_variable_set("@" + var.to_s, params[i])
13
+ vars.zip(params) do |var, param|
14
+ instance_variable_set("@#{var}", param)
13
15
  end
14
16
  end
15
17
  end
16
-
17
- def def_readable(*vars)
18
- attr_reader(*vars)
19
- def_ctor(*vars)
20
- end
21
18
  end
22
19
 
23
20
  end # module
@@ -0,0 +1,11 @@
1
+ require "rparsec/parser"
2
+
3
+ module RParsec
4
+ class EofParser < Parser # :nodoc:
5
+ init :msg
6
+ def _parse ctxt
7
+ return true if ctxt.eof
8
+ return ctxt.expecting(@msg)
9
+ end
10
+ end
11
+ end
data/lib/rparsec/error.rb CHANGED
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'rparsec/misc'
3
+ require 'rparsec/def_helper'
4
4
 
5
5
  module RParsec
6
6
 
@@ -11,21 +11,17 @@ module RParsec
11
11
 
12
12
  class Failure # :nodoc:
13
13
  def initialize(ind, input, message = nil)
14
- @index, @input, @msg = ind, input, message
14
+ @index = ind
15
+ @input = input
16
+ @msg = message
15
17
  end
16
18
 
17
- attr_reader :index, :input
18
- attr_writer :index
19
+ attr_reader :input
20
+ attr_accessor :index
19
21
 
20
- def msg
21
- return @msg.to_s
22
- end
23
-
24
- Precedence = 100
22
+ def msg = @msg.to_s
25
23
  end
26
24
 
27
- class Expected < Failure # :nodoc:
28
- Precedence = 100
29
- end
25
+ Expected = Class.new(Failure) # :nodoc:
30
26
 
31
27
  end # module
@@ -0,0 +1,18 @@
1
+ require "rparsec/parser"
2
+
3
+ module RParsec
4
+ class ExpectParser < Parser # :nodoc:
5
+ def initialize(parser, msg)
6
+ super()
7
+ @parser = parser
8
+ @msg = msg
9
+ @name = msg
10
+ end
11
+ def _parse ctxt
12
+ ind = ctxt.index
13
+ return true if @parser._parse ctxt
14
+ return false unless ind == ctxt.index
15
+ ctxt.expecting(@msg)
16
+ end
17
+ end
18
+ end
@@ -50,25 +50,11 @@ module RParsec
50
50
  end
51
51
 
52
52
  def apply_operator(term, op, kind, delim)
53
- term, op = ignore_rest(term, delim), ignore_rest(op, delim)
54
- # we could use send here,
55
- # but explicit case stmt is more straight forward and less coupled with names.
56
- # performance might be another benefit,
57
- # though it is not clear whether meta-code is indeed slower than regular ones at all.
58
- case kind
59
- when :prefix
60
- term.prefix(op)
61
- when :postfix
62
- term.postfix(op)
63
- when :infixl
64
- term.infixl(op)
65
- when :infixr
66
- term.infixr(op)
67
- when :infixn
68
- term.infixn(op)
69
- else
70
- raise ArgumentError, "unknown associativity: #{kind}"
71
- end
53
+ Associativities.include?(kind) or raise ArgumentError, "unknown associativity: #{kind}"
54
+
55
+ term = ignore_rest(term, delim)
56
+ op = ignore_rest(op, delim)
57
+ term.send(kind, op)
72
58
  end
73
59
 
74
60
  def ignore_rest(parser, delim)
@@ -0,0 +1,10 @@
1
+ require "rparsec/parser"
2
+
3
+ module RParsec
4
+ class FailureParser < Parser # :nodoc:
5
+ init :msg
6
+ def _parse ctxt
7
+ return ctxt.failure(@msg)
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,31 @@
1
+ module RParsec
2
+ class Failures # :nodoc:
3
+ def self.add_error(err, e)
4
+ return e if err.nil?
5
+ return err if e.nil?
6
+ cmp = compare_error(err, e)
7
+ return err if cmp > 0
8
+ return e if cmp < 0
9
+ err
10
+ end
11
+
12
+ class << self
13
+ private
14
+
15
+ def get_first_element(err)
16
+ while err.kind_of?(Array)
17
+ err = err[0]
18
+ end
19
+ err
20
+ end
21
+
22
+ def compare_error(e1, e2)
23
+ e1 = get_first_element(e1)
24
+ e2 = get_first_element(e2)
25
+ return -1 if e1.index < e2.index
26
+ return 1 if e1.index > e2.index
27
+ 0
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,13 @@
1
+ require "rparsec/parser"
2
+
3
+ module RParsec
4
+ class FollowedParser < Parser # :nodoc:
5
+ init :p1, :p2
6
+ def _parse ctxt
7
+ return false unless @p1._parse ctxt
8
+ result = ctxt.result
9
+ return false unless @p2._parse ctxt
10
+ ctxt.retn(result)
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,12 @@
1
+ require "rparsec/parser"
2
+
3
+ module RParsec
4
+ class FragmentParser < Parser # :nodoc:
5
+ init :parser
6
+ def _parse ctxt
7
+ ind = ctxt.index
8
+ return false unless @parser._parse ctxt
9
+ ctxt.retn(ctxt.src[ind, ctxt.index - ind])
10
+ end
11
+ end
12
+ end
@@ -9,27 +9,20 @@ module RParsec
9
9
  # Create a +Proc+, which expects the two parameters in the reverse
10
10
  # order of +self+.
11
11
  #
12
- def flip
13
- Functors.flip(&self)
14
- end
12
+ def flip = Functors.flip(&self)
15
13
 
16
14
  #
17
15
  # Create a +Proc+, when called, the parameter is first passed into
18
16
  # +other+, +self+ is called in turn with the return value from
19
17
  # +other+.
20
18
  #
21
- def compose(other)
22
- Functors.compose(self, other)
23
- end
24
-
19
+ def compose(other) = Functors.compose(self, other)
25
20
  alias << compose
26
21
 
27
22
  #
28
23
  # <tt>a >> b</tt> is equivalent to <tt>b << a</tt>. See also #<<.
29
24
  #
30
- def >>(other)
31
- other << self
32
- end
25
+ def >>(other) = other << self
33
26
 
34
27
  #
35
28
  # Create a Proc that's curriable.
@@ -47,9 +40,7 @@ module RParsec
47
40
  # See the "functor_test.rb"
48
41
  [Proc, Method].each do |klass|
49
42
  refine klass do
50
- def curry(ary = arity)
51
- Functors.curry(ary, &self)
52
- end
43
+ def curry(ary = arity) = Functors.curry(ary, &self)
53
44
  end
54
45
  end
55
46
 
@@ -61,42 +52,30 @@ module RParsec
61
52
  # the hood to perform the actual job when currying is done. +ary+
62
53
  # explicitly specifies the number of parameters to curry.
63
54
  #
64
- def reverse_curry(ary = arity)
65
- Functors.reverse_curry(ary, &self)
66
- end
55
+ def reverse_curry(ary = arity) = Functors.reverse_curry(ary, &self)
67
56
 
68
57
  #
69
58
  # Uncurry a curried closure.
70
59
  #
71
- def uncurry
72
- Functors.uncurry(&self)
73
- end
60
+ def uncurry = Functors.uncurry(&self)
74
61
 
75
62
  #
76
63
  # Uncurry a reverse curried closure.
77
64
  #
78
- def reverse_uncurry
79
- Functors.reverse_uncurry(&self)
80
- end
65
+ def reverse_uncurry = Functors.reverse_uncurry(&self)
81
66
 
82
67
  #
83
68
  # Create a +Proc+, when called, repeatedly call +self+ for +n+
84
69
  # times. The same arguments are passed to each invocation.
85
70
  #
86
- def repeat(n)
87
- Functors.repeat(n, &self)
88
- end
89
- #
71
+ def repeat(n) = Functors.repeat(n, &self)
72
+ alias * repeat
90
73
 
91
74
  # Create a +Proc+, when called, repeatedly call +self+ for +n+
92
75
  # times. At each iteration, return value from the previous
93
76
  # iteration is used as parameter.
94
77
  #
95
- def power(n)
96
- Functors.power(n, &self)
97
- end
98
-
78
+ def power(n) = Functors.power(n, &self)
99
79
  alias ** power
100
- alias * repeat
101
80
  end
102
81
  end
@@ -0,0 +1,9 @@
1
+ require 'rparsec/parser'
2
+
3
+ module RParsec
4
+ class GetIndexParser < Parser # :nodoc:
5
+ def _parse ctxt
6
+ ctxt.retn(ctxt.index)
7
+ end
8
+ end
9
+ end
@@ -25,9 +25,7 @@ module RParsec
25
25
  #
26
26
  # Do we lex case sensitively?
27
27
  #
28
- def case_sensitive?
29
- @case_sensitive
30
- end
28
+ def case_sensitive? = @case_sensitive
31
29
 
32
30
  #
33
31
  # To create an instance that lexes the given keywords case
@@ -57,7 +55,9 @@ module RParsec
57
55
 
58
56
  # scanner has to return a string
59
57
  def initialize(words, case_sensitive, default_lexer, keyword_symbol, &block)
60
- @default_lexer, @case_sensitive, @keyword_symbol = default_lexer, case_sensitive, keyword_symbol
58
+ @default_lexer = default_lexer
59
+ @case_sensitive = case_sensitive
60
+ @keyword_symbol = keyword_symbol
61
61
  # this guarantees that we have copy of the words array and all the word strings.
62
62
  words = copy_words(words, case_sensitive)
63
63
  @name_map = {}
@@ -94,21 +94,21 @@ module RParsec
94
94
 
95
95
  def make_lexer(default_lexer, word_map)
96
96
  default_lexer.map do |tok|
97
- text, ind = tok.text, tok.index
97
+ text = tok.text
98
+ ind = tok.index
98
99
  key = canonical_name(text)
99
100
  my_symbol = word_map[key]
100
- case when my_symbol.nil? then tok
101
- else Token.new(my_symbol, text, ind) end
101
+ my_symbol.nil? ? tok : Token.new(my_symbol, text, ind)
102
102
  end
103
103
  end
104
104
 
105
105
  def canonical_name(name)
106
- case when @case_sensitive then name else name.downcase end
106
+ @case_sensitive ? name : name.downcase
107
107
  end
108
108
 
109
109
  def copy_words(words, case_sensitive)
110
110
  words.map do |w|
111
- case when case_sensitive then w.dup else w.downcase end
111
+ case_sensitive ? w.dup : w.downcase
112
112
  end
113
113
  end
114
114
  end
@@ -0,0 +1,10 @@
1
+ require "rparsec/parser"
2
+
3
+ module RParsec
4
+ class LazyParser < Parser # :nodoc:
5
+ init :block
6
+ def _parse ctxt
7
+ @block.call._parse ctxt
8
+ end
9
+ end
10
+ end
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'rparsec/misc'
3
+ require 'rparsec/def_helper'
4
4
 
5
5
  module RParsec
6
6
 
@@ -13,12 +13,14 @@ module RParsec
13
13
 
14
14
  def locate(ind)
15
15
  return _locateEof if ind >= code.length
16
- line, col = 1, 1
16
+ line = 1
17
+ col = 1
17
18
  return line, col if ind <= 0
18
19
  for i in (0...ind)
19
20
  c = code[i]
20
21
  if c == LF
21
- line, col = line + 1, 1
22
+ line = line + 1
23
+ col = 1
22
24
  else
23
25
  col = col + 1
24
26
  end
@@ -27,10 +29,12 @@ module RParsec
27
29
  end
28
30
 
29
31
  def _locateEof
30
- line, col = 1, 1
32
+ line = 1
33
+ col = 1
31
34
  code.each_byte do |c|
32
35
  if c == LF.ord
33
- line, col = line + 1, 1
36
+ line = line + 1
37
+ col = 1
34
38
  else
35
39
  col = col + 1
36
40
  end
@@ -0,0 +1,46 @@
1
+ require "rparsec/parser"
2
+
3
+ module RParsec
4
+ class LookAheadSensitiveParser < Parser # :nodoc:
5
+ def initialize(la = 1)
6
+ super()
7
+ @lookahead = la
8
+ end
9
+ def visible(ctxt, n)
10
+ ctxt.index - n < @lookahead
11
+ end
12
+ def lookahead(n)
13
+ raise ArgumentError, "lookahead number #{n} should be positive" unless n > 0
14
+ return self if n == @lookahead
15
+ withLookahead(n)
16
+ end
17
+ def not(msg = "#{self} unexpected")
18
+ NotParser.new(self, msg, @lookahead)
19
+ end
20
+ end
21
+
22
+ # Define here to avoid circular loadings.
23
+ class NotParser < LookAheadSensitiveParser # :nodoc:
24
+ def initialize(parser, msg, la = 1)
25
+ super(la)
26
+ @parser = parser
27
+ @msg = msg
28
+ @name = "~#{parser.name}"
29
+ end
30
+ def _parse ctxt
31
+ ind = ctxt.index
32
+ if @parser._parse ctxt
33
+ ctxt.index = ind
34
+ return ctxt.expecting(@msg)
35
+ end
36
+ return ctxt.retn(nil) if visible(ctxt, ind)
37
+ return false
38
+ end
39
+ def withLookahead(n)
40
+ NotParser.new(@parser, @msg, n)
41
+ end
42
+ def not()
43
+ @parser
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,20 @@
1
+ require "rparsec/parser"
2
+
3
+ module RParsec
4
+ class Many_Parser < Parser # :nodoc:
5
+ init :parser, :least
6
+ def _parse ctxt
7
+ @least.times do
8
+ return false unless @parser._parse ctxt
9
+ end
10
+ while true
11
+ ind = ctxt.index
12
+ if @parser._parse ctxt
13
+ return true if ind == ctxt.index # infinite loop
14
+ next
15
+ end
16
+ return ind == ctxt.index
17
+ end
18
+ end
19
+ end
20
+ end