1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90
|
module Rsec
# the content appears 1 or 0 time
class Maybe < Unary
def _parse ctx
save = ctx.pos
res = some._parse ctx
if INVALID[res]
ctx.pos = save
[]
else
[res]
end
end
end
# repeat from range.begin.abs to range.end.abs <br/>
# note: range's max should always be > 0<br/>
# see also helpers
class RepeatRange
include Parser
def self.[] base, range
self.new base, range
end
def initialize base, range
@base = base
@at_least = range.min.abs
@optional = range.max - @at_least
end
def _parse ctx
rp_node = []
@at_least.times do
res = @base._parse ctx
return INVALID if INVALID[res]
rp_node.push res
end
@optional.times do
save = ctx.pos
res = @base._parse ctx
if INVALID[res]
ctx.pos = save
break
end
rp_node.push res
end
rp_node
end
end
# matches exactly n.abs times repeat<br/>
class RepeatN < Struct.new(:base, :n)
include Parser
def _parse ctx
n.times.inject([]) do |rp_node|
res = base._parse ctx
return INVALID if INVALID[res]
rp_node.push res
end
end
end
# repeat at least n.abs times <- [n, inf) <br/>
class RepeatAtLeastN < Struct.new(:base, :n)
include Parser
def _parse ctx
rp_node = []
n.times do
res = base._parse(ctx)
return INVALID if INVALID[res]
rp_node.push res
end
# note this may be an infinite action
# returns if the pos didn't change
loop do
save = ctx.pos
res = base._parse ctx
if (INVALID[res] or ctx.pos == save)
ctx.pos = save
break
end
rp_node.push res
end
rp_node
end
end
end
|