Class: Walrat::ParsletSequence
- Inherits:
-
ParsletCombination
- Object
- ParsletCombination
- Walrat::ParsletSequence
- Defined in:
- lib/walrat/parslet_sequence.rb
Direct Known Subclasses
Constant Summary collapse
- SKIP_FIRST =
true
- NO_SKIP =
false
Instance Attribute Summary collapse
-
#hash ⇒ Object
readonly
Returns the value of attribute hash.
Instance Method Summary collapse
-
#&(next_parslet) ⇒ Object
Override so that sequences are appended to an existing sequence: Consider the following example:.
- #eql?(other) ⇒ Boolean
-
#initialize(first, second, *others) ⇒ ParsletSequence
constructor
first and second may not be nil.
- #parse(string, options = {}) ⇒ Object
- #parse_common(skip_first, string, options = {}) ⇒ Object
- #parse_remainder(string, options = {}) ⇒ Object
-
#recurse(state) ⇒ Object
Left-recursion helper.
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(first, second, *others) ⇒ ParsletSequence
first and second may not be nil.
30 31 32 33 34 35 |
# File 'lib/walrat/parslet_sequence.rb', line 30 def initialize first, second, *others raise ArgumentError if first.nil? raise ArgumentError if second.nil? @components = [first, second] + others update_hash end |
Instance Attribute Details
#hash ⇒ Object (readonly)
Returns the value of attribute hash.
27 28 29 |
# File 'lib/walrat/parslet_sequence.rb', line 27 def hash @hash end |
Instance Method Details
#&(next_parslet) ⇒ Object
Override so that sequences are appended to an existing sequence: Consider the following example:
A & B
This constitutes a single sequence:
(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 produces unwanted nesting in the results because instead of returning a one-dimensional array of results:
[a, b, c]
It returns a nested array:
[[a, b], c]
The solution to this unwanted nesting is to allowing appending to an existing sequence by using the private “append” method.
This ensures that:
A & B & C
Translates to a single sequence:
(A & B & C)
And a single, uni-dimensional results array:
[a, b, c]
79 80 81 |
# File 'lib/walrat/parslet_sequence.rb', line 79 def &(next_parslet) append next_parslet end |
#eql?(other) ⇒ Boolean
200 201 202 203 204 205 206 207 208 |
# File 'lib/walrat/parslet_sequence.rb', line 200 def eql?(other) return false if not other.instance_of? ParsletSequence other_components = other.components return false if @components.length != other_components.length for i in 0..(@components.length - 1) return false unless @components[i].eql? other_components[i] end true end |
#parse(string, options = {}) ⇒ Object
86 87 88 |
# File 'lib/walrat/parslet_sequence.rb', line 86 def parse string, = {} parse_common NO_SKIP, string, end |
#parse_common(skip_first, string, options = {}) ⇒ Object
94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 |
# File 'lib/walrat/parslet_sequence.rb', line 94 def parse_common skip_first, string, = {} raise ArgumentError if string.nil? state = ParserState.new(string, ) last_caught = nil # keep track of the last kind of throw to be caught left_recursion = false # keep track of whether left recursion was detected @components.each_with_index do |parseable, index| if index == 0 # for first component only if skip_first next end begin check_left_recursion(parseable, ) rescue LeftRecursionException => e left_recursion = true continuation = nil value = callcc { |c| continuation = c } if value == continuation # first time that we're here e.continuation = continuation # pack continuation into exception raise e # and propagate else grammar = state.[:grammar] rule_name = state.[:rule_name] state.parsed grammar.wrap(value, rule_name) next end end end catch :ProcessNextComponent do catch :NotPredicateSuccess do catch :AndPredicateSuccess do catch :ZeroWidthParseSuccess do begin parsed = parseable.memoizing_parse state.remainder, state. 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 .has_key?(:skipping_override) skipping_parslet = [:skipping_override] elsif .has_key?(:skipping) skipping_parslet = [:skipping] else skipping_parslet = nil end raise e if skipping_parslet.nil? # no skipper defined, raise original error begin # guard against self references (possible infinite recursion) here? parsed = skipping_parslet.memoizing_parse state.remainder, state. state.skipped(parsed) redo # skipping succeeded, try to redo rescue ParseError raise e # skipping didn't help either, raise original error end end last_caught = nil # can't use "next" here because it would only break out of # innermost "do" rather than continuing the iteration throw :ProcessNextComponent end last_caught = :ZeroWidthParseSuccess throw :ProcessNextComponent end last_caught = :AndPredicateSuccess throw :ProcessNextComponent end last_caught = :NotPredicateSuccess end end if left_recursion results = recurse(state) else results = state.results end return results if skip_first if results.respond_to? :empty? and results.empty? and last_caught throw last_caught else results end end |
#parse_remainder(string, options = {}) ⇒ Object
90 91 92 |
# File 'lib/walrat/parslet_sequence.rb', line 90 def parse_remainder string, = {} parse_common SKIP_FIRST, string, end |
#recurse(state) ⇒ Object
Left-recursion helper
184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 |
# File 'lib/walrat/parslet_sequence.rb', line 184 def recurse state return state.results if state.remainder == '' # further recursion is not possible new_state = ParserState.new state.remainder, state. last_successful_result = nil while state.remainder != '' begin new_results = parse_remainder new_state.remainder, new_state. new_state.parsed new_results last_successful_result = ArrayResult[last_successful_result || state.results, new_results] rescue ParseError break end end last_successful_result || state.results end |