Class: Walrus::Grammar::ParsletChoice
- Inherits:
-
ParsletCombination
- Object
- ParsletCombination
- Walrus::Grammar::ParsletChoice
- Defined in:
- lib/walrus/grammar/parslet_choice.rb
Instance Attribute Summary collapse
-
#hash ⇒ Object
readonly
Returns the value of attribute hash.
Instance Method Summary collapse
- #eql?(other) ⇒ Boolean
-
#initialize(left, right, *others) ⇒ ParsletChoice
constructor
Either parameter may be a Parslet or a ParsletCombination.
-
#parse(string, options = {}) ⇒ Object
First tries to parse the left option, falling back and trying the right option and then the any subsequent options in the others instance variable on failure.
-
#|(next_parslet) ⇒ Object
Override so that alternatives are appended to an existing sequence: Consider the following example: A | B This constitutes a single choice: (A | B) If we then make this a three-element sequence: A | B | C We are effectively creating an nested sequence containing the original sequence and an additional element: ((A | B) | C) Although such a nested sequence is correctly parsed it is not as architecturally clean as a single sequence without nesting: (A | B | C) This method allows us to use the architecturally cleaner format.
Methods inherited from ParsletCombination
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(left, right, *others) ⇒ ParsletChoice
Either parameter may be a Parslet or a ParsletCombination. Neither parmeter may be nil.
26 27 28 29 30 31 |
# File 'lib/walrus/grammar/parslet_choice.rb', line 26 def initialize(left, right, *others) raise ArgumentError if left.nil? raise ArgumentError if right.nil? @alternatives = [left, right] + others update_hash end |
Instance Attribute Details
#hash ⇒ Object (readonly)
Returns the value of attribute hash.
22 23 24 |
# File 'lib/walrus/grammar/parslet_choice.rb', line 22 def hash @hash end |
Instance Method Details
#eql?(other) ⇒ Boolean
94 95 96 97 98 99 100 101 102 |
# File 'lib/walrus/grammar/parslet_choice.rb', line 94 def eql?(other) return false if not other.instance_of? ParsletChoice other_alternatives = other.alternatives return false if @alternatives.length != other_alternatives.length for i in 0..(@alternatives.length - 1) return false unless @alternatives[i].eql? other_alternatives[i] end true end |
#parse(string, options = {}) ⇒ Object
First tries to parse the left option, falling back and trying the right option and then the any subsequent options in the others instance variable on failure. If no options successfully complete parsing then an ParseError is raised. Any zero-width parse successes thrown by alternative parsers will flow on to a higher level.
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 91 92 |
# File 'lib/walrus/grammar/parslet_choice.rb', line 51 def parse(string, = {}) raise ArgumentError if string.nil? error = nil # for error reporting purposes will track which parseable gets farthest to the right before failing left_recursion = nil # will also track any left recursion that we detect @alternatives.each do |parseable| begin result = parseable.memoizing_parse(string, ) # successful parse if left_recursion and left_recursion.continuation # and we have a continuation continuation = left_recursion.continuation # continuations are once-only, one-way tickets left_recursion = nil # set this to nil so as not to call it again without meaning to continuation.call(result) # so jump back to where we were before end return result rescue LeftRecursionException => e left_recursion = e # TODO: # it's not enough to just catch this kind of exception and remember the last one # may need to accumulate these in an array # consider the example rule: # :a, :a & :b | :a & :c | :a & :d | :b # the first option will raise a LeftRecursionException # the next option will raise for the same reason # the third likewise # finally we get to the fourth option, the first which might succeed # at that point we should have three continuations # we should try the first, falling back to the second and third if necessary # on successfully retrying, need to start all over again and try all the options again, just in case further recursion is possible # so it is quite complicated # the question is, is it more complicated than the other ways of getting right-associativity into Walrus-generated parsers? rescue ParseError => e if error.nil? error = e else error = e unless error.rightmost?(e) end end end raise ParseError.new('no valid alternatives while parsing "%s" (%s)' % [string, error.to_s], :line_end => error.line_end, :column_end => error.column_end) # should generally report the rightmost error end |
#|(next_parslet) ⇒ Object
Override so that alternatives are appended to an existing sequence: Consider the following example:
A | B
This constitutes a single choice:
(A | B)
If we then make this a three-element sequence:
A | B | C
We are effectively creating an nested sequence containing the original sequence and an additional element:
((A | B) | C)
Although such a nested sequence is correctly parsed it is not as architecturally clean as a single sequence without nesting:
(A | B | C)
This method allows us to use the architecturally cleaner format.
46 47 48 |
# File 'lib/walrus/grammar/parslet_choice.rb', line 46 def |(next_parslet) append(next_parslet) end |