Class: Walrus::Grammar::ParsletRepetition

Inherits:
ParsletCombination show all
Defined in:
lib/walrus/grammar/parslet_repetition.rb

Direct Known Subclasses

ParsletRepetitionDefault

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods inherited from ParsletCombination

#to_parseable

Methods included from Memoizing

#check_left_recursion, #memoizing_parse

Methods included from ParsletCombining

#&, #>>, #and?, #and_predicate, #choice, #memoizing_parse, #merge, #not!, #not_predicate, #omission, #one_or_more, #optional, #repeat, #repeat_with_default, #repetition, #repetition_with_default, #sequence, #skip, #zero_or_more, #zero_or_one, #|

Constructor Details

#initialize(parseable, min, max = nil) ⇒ ParsletRepetition

Raises an ArgumentError if parseable or min is nil.

Raises:

  • (ArgumentError)


25
26
27
28
29
30
31
# File 'lib/walrus/grammar/parslet_repetition.rb', line 25

def initialize(parseable, min, max = nil)
  raise ArgumentError if parseable.nil?
  raise ArgumentError if min.nil?
  @parseable = parseable
  self.min = min
  self.max = max
end

Instance Attribute Details

#hashObject (readonly)

Returns the value of attribute hash.



22
23
24
# File 'lib/walrus/grammar/parslet_repetition.rb', line 22

def hash
  @hash
end

Instance Method Details

#eql?(other) ⇒ Boolean

Returns:

  • (Boolean)


75
76
77
# File 'lib/walrus/grammar/parslet_repetition.rb', line 75

def eql?(other)
  other.instance_of? ParsletRepetition and @min == other.min and @max == other.max and @parseable.eql? other.parseable
end

#parse(string, options = {}) ⇒ Object

Raises:

  • (ArgumentError)


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
# File 'lib/walrus/grammar/parslet_repetition.rb', line 33

def parse(string, options = {})
  raise ArgumentError if string.nil?
  state                         = ParserState.new(string, options)
  catch :ZeroWidthParseSuccess do             # a zero-width match is grounds for immediate abort
    while @max.nil? or state.length < @max    # try forever if max is nil; otherwise keep trying while match count < max
      begin
        parsed = @parseable.memoizing_parse(state.remainder, state.options)
        state.parsed(parsed)
      rescue SkippedSubstringException => e
        state.skipped(e)
      rescue ParseError => e # failed, will try to skip; save original error in case skipping fails
        if options.has_key?(:skipping_override)
          skipping_parslet = options[:skipping_override]
        elsif options.has_key?(:skipping)
          skipping_parslet = options[:skipping]
        else
          skipping_parslet = nil
        end
        break if skipping_parslet.nil?
        begin
          parsed = skipping_parslet.memoizing_parse(state.remainder, state.options) # guard against self references (possible infinite recursion) here?
          state.skipped(parsed)
          redo                                  # skipping succeeded, try to redo
        rescue ParseError
          break                                 # skipping didn't help either, give up
        end
      end
    end          
  end
  
  # now assess whether our tries met the requirements
  if state.length == 0 and @min == 0 # success (special case)
    throw :ZeroWidthParseSuccess
  elsif state.length < @min          # matches < min (failure)
    raise ParseError.new('required %d matches but obtained %d while parsing "%s"' % [@min, state.length, string],
                         :line_end    => state.options[:line_end],    :column_end   => state.options[:column_end])
  else                              # success (general case)
    state.results                   # returns multiple matches as an array, single matches as a single object
  end
  
end