File: repeat.rb

package info (click to toggle)
ruby-rsec 0.4.2-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 272 kB
  • sloc: ruby: 2,130; lisp: 13; makefile: 3
file content (90 lines) | stat: -rw-r--r-- 1,961 bytes parent folder | download | duplicates (3)
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