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.
- checksums.yaml +4 -4
- data/lib/rparsec/alt_parser.rb +38 -0
- data/lib/rparsec/any_parser.rb +12 -0
- data/lib/rparsec/are_parser.rb +20 -0
- data/lib/rparsec/atom_parser.rb +16 -0
- data/lib/rparsec/best_parser.rb +44 -0
- data/lib/rparsec/bound_parser.rb +11 -0
- data/lib/rparsec/boundn_parser.rb +11 -0
- data/lib/rparsec/catch_parser.rb +17 -0
- data/lib/rparsec/context.rb +5 -3
- data/lib/rparsec/{misc.rb → def_helper.rb} +5 -8
- data/lib/rparsec/eof_parser.rb +11 -0
- data/lib/rparsec/error.rb +8 -12
- data/lib/rparsec/expect_parser.rb +18 -0
- data/lib/rparsec/expressions.rb +5 -19
- data/lib/rparsec/failure_parser.rb +10 -0
- data/lib/rparsec/failures.rb +31 -0
- data/lib/rparsec/followed_parser.rb +13 -0
- data/lib/rparsec/fragment_parser.rb +12 -0
- data/lib/rparsec/functor_mixin.rb +10 -31
- data/lib/rparsec/get_index_parser.rb +9 -0
- data/lib/rparsec/keywords.rb +9 -9
- data/lib/rparsec/lazy_parser.rb +10 -0
- data/lib/rparsec/locator.rb +9 -5
- data/lib/rparsec/look_ahead_sensitive_parser.rb +46 -0
- data/lib/rparsec/many__parser.rb +20 -0
- data/lib/rparsec/many_parser.rb +27 -0
- data/lib/rparsec/map_current_parser.rb +11 -0
- data/lib/rparsec/map_parser.rb +12 -0
- data/lib/rparsec/mapn_current_parser.rb +11 -0
- data/lib/rparsec/mapn_parser.rb +12 -0
- data/lib/rparsec/nested_parser.rb +47 -0
- data/lib/rparsec/not_parser.rb +27 -0
- data/lib/rparsec/one_parser.rb +9 -0
- data/lib/rparsec/operator_table.rb +29 -63
- data/lib/rparsec/parser.rb +14 -20
- data/lib/rparsec/parser_monad.rb +4 -17
- data/lib/rparsec/parsers.rb +52 -626
- data/lib/rparsec/peek_parser.rb +16 -0
- data/lib/rparsec/plus_parser.rb +32 -0
- data/lib/rparsec/regexp_parser.rb +17 -0
- data/lib/rparsec/repeat__parser.rb +13 -0
- data/lib/rparsec/repeat_parser.rb +15 -0
- data/lib/rparsec/satisfies_parser.rb +15 -0
- data/lib/rparsec/sequence_parser.rb +25 -0
- data/lib/rparsec/set_index_parser.rb +10 -0
- data/lib/rparsec/some__parser.rb +19 -0
- data/lib/rparsec/some_parser.rb +28 -0
- data/lib/rparsec/string_case_insensitive_parser.rb +26 -0
- data/lib/rparsec/throw_parser.rb +10 -0
- data/lib/rparsec/token.rb +9 -28
- data/lib/rparsec/token_parser.rb +14 -0
- data/lib/rparsec/value_parser.rb +10 -0
- data/lib/rparsec/watch_parser.rb +11 -0
- data/lib/rparsec/watchn_parser.rb +11 -0
- data/lib/rparsec/zero_parser.rb +9 -0
- data/lib/rparsec.rb +1 -1
- metadata +52 -7
- data/lib/rparsec/id_monad.rb +0 -19
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ce59ff665a46de4f47bc1cc49a0b6eba80901a691ed5d24b66309857cf01dbac
|
4
|
+
data.tar.gz: 3d015234cac23f1f2320d9ffdd44ac5b0cdc8308b20b1690d613dd881b7791ae
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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,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,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
|
data/lib/rparsec/context.rb
CHANGED
@@ -5,11 +5,13 @@ require 'strscan'
|
|
5
5
|
module RParsec
|
6
6
|
|
7
7
|
class ParseContext # :nodoc:
|
8
|
-
attr_reader :
|
9
|
-
|
8
|
+
attr_reader :src
|
9
|
+
attr_accessor :error, :index, :result
|
10
10
|
|
11
11
|
def initialize(src, index=0, error=nil)
|
12
|
-
@src
|
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
|
9
|
+
def def_readable(*vars)
|
10
|
+
attr_reader(*vars)
|
11
|
+
|
10
12
|
define_method(:initialize) do |*params|
|
11
|
-
vars.
|
12
|
-
instance_variable_set("
|
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
|
data/lib/rparsec/error.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require 'rparsec/
|
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
|
14
|
+
@index = ind
|
15
|
+
@input = input
|
16
|
+
@msg = message
|
15
17
|
end
|
16
18
|
|
17
|
-
attr_reader :
|
18
|
-
|
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
|
-
|
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
|
data/lib/rparsec/expressions.rb
CHANGED
@@ -50,25 +50,11 @@ module RParsec
|
|
50
50
|
end
|
51
51
|
|
52
52
|
def apply_operator(term, op, kind, delim)
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
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,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
|
@@ -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
|
-
|
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
|
data/lib/rparsec/keywords.rb
CHANGED
@@ -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
|
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
|
97
|
+
text = tok.text
|
98
|
+
ind = tok.index
|
98
99
|
key = canonical_name(text)
|
99
100
|
my_symbol = word_map[key]
|
100
|
-
|
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
|
-
|
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
|
-
|
111
|
+
case_sensitive ? w.dup : w.downcase
|
112
112
|
end
|
113
113
|
end
|
114
114
|
end
|
data/lib/rparsec/locator.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require 'rparsec/
|
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
|
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
|
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
|
32
|
+
line = 1
|
33
|
+
col = 1
|
31
34
|
code.each_byte do |c|
|
32
35
|
if c == LF.ord
|
33
|
-
line
|
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
|