Class: Pegparse::ParserCore
- Inherits:
-
Object
- Object
- Pegparse::ParserCore
- Included in:
- BiopRuleChain
- Defined in:
- lib/pegparse/parser_core.rb
Overview
Parser base class (core mechanism for backtracking)
Direct Known Subclasses
Instance Attribute Summary collapse
-
#start_rule_symbol ⇒ Symbol
start rule symbol used by parse().
Class Method Summary collapse
-
.rule(method_sym) ⇒ Symbol
Wrap method as nonterminal symbol rule.
- .wrap_with_trace_method(method_sym) ⇒ Object
Instance Method Summary collapse
- #backtrack ⇒ Object
- #backtrack_position_to(pos) ⇒ Object
-
#best_errors ⇒ Array
parse error info.
-
#borrow_next_line(&block) ⇒ Object
Temporarily change scanner position to next line(use for here-document) area consumed by block becomes non-matchable().
-
#borrowed_area ⇒ Object
match to borrowed area.
-
#choice(*alter_procs) ⇒ Object
Try to match some candidates in order.
- #eos? ⇒ Boolean
-
#init_context(scanner_or_context) ⇒ Object
initialize inner state.
-
#initialize(scanner_or_context) ⇒ ParserCore
constructor
A new instance of ParserCore.
-
#one_or_more(&block) ⇒ Array<Object>
Try to match in loop.
-
#optional(str_or_regexp = nil, &block) ⇒ String, Object
Match with pattern or block.
-
#parse(scanner_or_context = nil, rule: nil) ⇒ Object
Start parse.
-
#peek(str_or_regexp = nil, &block) ⇒ String, Object
Check whether matching will success or not.
-
#read(str_or_regexp) ⇒ String
Match with pattern.
- #save_error(reason) ⇒ Object
-
#zero_or_more(&block) ⇒ Array<Object>
Try to match in loop.
Constructor Details
#initialize(scanner_or_context) ⇒ ParserCore
10 11 12 |
# File 'lib/pegparse/parser_core.rb', line 10 def initialize(scanner_or_context) init_context(scanner_or_context) if scanner_or_context end |
Instance Attribute Details
#start_rule_symbol ⇒ Symbol
start rule symbol used by parse()
7 8 9 |
# File 'lib/pegparse/parser_core.rb', line 7 def start_rule_symbol @start_rule_symbol end |
Class Method Details
.rule(method_sym) ⇒ Symbol
Wrap method as nonterminal symbol rule.
168 169 170 171 |
# File 'lib/pegparse/parser_core.rb', line 168 def self.rule(method_sym) self.wrap_with_trace_method(method_sym) method_sym end |
.wrap_with_trace_method(method_sym) ⇒ Object
151 152 153 154 155 156 157 158 159 160 161 162 163 |
# File 'lib/pegparse/parser_core.rb', line 151 def self.wrap_with_trace_method(method_sym) original_method_sym = ('original_' + method_sym.to_s).to_sym unless self.method_defined?(original_method_sym) self.alias_method original_method_sym, method_sym self.define_method(method_sym) do |*args| @context.rule_stack.push [@context.scanner.pos, method_sym] ret = self.__send__(original_method_sym, *args) return ret ensure @context.rule_stack.pop end end end |
Instance Method Details
#backtrack ⇒ Object
147 148 149 |
# File 'lib/pegparse/parser_core.rb', line 147 def backtrack() throw :backtrack end |
#backtrack_position_to(pos) ⇒ Object
50 51 52 53 |
# File 'lib/pegparse/parser_core.rb', line 50 def backtrack_position_to(pos) @context.scanner.pos = pos @context.borrowed_areas.backtracked(pos) end |
#best_errors ⇒ Array
parse error info
57 58 59 60 61 62 63 |
# File 'lib/pegparse/parser_core.rb', line 57 def best_errors @context.errors.best_errors.map{|error| error.map{|rule| [ @context.line_counter.position(rule.pos), rule.reason ] } } end |
#borrow_next_line(&block) ⇒ Object
Temporarily change scanner position to next line(use for here-document) area consumed by block becomes non-matchable().
212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 |
# File 'lib/pegparse/parser_core.rb', line 212 def borrow_next_line(&block) mark_pos = @context.scanner.pos if @context.borrowed_areas.borrowed_area_end_pos borrowed_start_pos = @context.borrowed_areas.borrowed_area_end_pos else read(/.*\n/) borrowed_start_pos = @context.scanner.pos end @context.scanner.pos = borrowed_start_pos ret = block.call borrowed_end_pos = @context.scanner.pos @context.scanner.pos = mark_pos @context.borrowed_areas.add_area(Pegparse::BorrowedArea.new( marker_pos: mark_pos, start_pos: borrowed_start_pos, end_pos: borrowed_end_pos, )) return ret end |
#borrowed_area ⇒ Object
match to borrowed area
233 234 235 236 237 238 239 240 241 242 |
# File 'lib/pegparse/parser_core.rb', line 233 def borrowed_area if area = @context.borrowed_areas.conflicted_area(@context.scanner.pos) if area.start_pos == @context.scanner.pos ret = @context.scanner.peek(area.end_pos - area.start_pos) @context.scanner.pos = area.end_pos return ret end end backtrack() end |
#choice(*alter_procs) ⇒ Object
Try to match some candidates in order. (PEG’s choice operator) Backtrack if all match failed.
178 179 180 181 182 183 184 |
# File 'lib/pegparse/parser_core.rb', line 178 def choice(*alter_procs) alter_procs.each do |alter_proc| ret = optional{ alter_proc.call() } return ret if ret end backtrack() end |
#eos? ⇒ Boolean
42 43 44 |
# File 'lib/pegparse/parser_core.rb', line 42 def eos? @context.scanner.eos? end |
#init_context(scanner_or_context) ⇒ Object
initialize inner state
15 16 17 18 19 20 21 |
# File 'lib/pegparse/parser_core.rb', line 15 def init_context(scanner_or_context) if scanner_or_context.is_a? Pegparse::ParserContext @context = scanner_or_context else @context = Pegparse::ParserContext.new(scanner_or_context) end end |
#one_or_more(&block) ⇒ Array<Object>
Try to match in loop. Backtrack if no loop succeeded.
200 201 202 203 204 205 206 207 208 |
# File 'lib/pegparse/parser_core.rb', line 200 def one_or_more(&block) ret = [block.call()] while true val = optional { block.call() } break unless val ret << val end return ret end |
#optional(str_or_regexp = nil, &block) ⇒ String, Object
Match with pattern or block. Returns nil if match failed.
124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 |
# File 'lib/pegparse/parser_core.rb', line 124 def optional(str_or_regexp = nil, &block) raise ArgumentError if str_or_regexp && block raise ArgumentError if !str_or_regexp && !block if block bk_pos = @context.scanner.pos ret = nil catch(:backtrack) do @context.rule_stack.push [@context.scanner.pos, :optional] ret = block.call() return ret ensure @context.rule_stack.pop end backtrack_position_to(bk_pos) return nil end ret = peek(str_or_regexp) @context.scanner.pos += ret.bytesize if ret return ret end |
#parse(scanner_or_context = nil, rule: nil) ⇒ Object
Start parse
27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
# File 'lib/pegparse/parser_core.rb', line 27 def parse(scanner_or_context = nil, rule: nil) raise ArgumentError if !scanner_or_context && !@context raise ArgumentError if !rule && !@start_rule_symbol init_context(scanner_or_context) if scanner_or_context current_start_rule_symbol = rule || @start_rule_symbol ret = nil catch(:backtrack) do ret = __send__(current_start_rule_symbol) end @context.errors.clear_errors if eos? return ret end |
#peek(str_or_regexp = nil, &block) ⇒ String, Object
Check whether matching will success or not.
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 93 94 95 96 97 98 99 100 101 102 103 104 105 |
# File 'lib/pegparse/parser_core.rb', line 68 def peek(str_or_regexp = nil, &block) raise ArgumentError if str_or_regexp && block raise ArgumentError if !str_or_regexp && !block if block bk_pos = @context.scanner.pos ret = nil catch(:backtrack) do ret = block.call() end backtrack_position_to(bk_pos) return ret end if str_or_regexp.is_a?(String) if @context.scanner.match?(str_or_regexp) @context.line_counter.memo(@context.scanner.pos, str_or_regexp) if @context.borrowed_areas.conflicted_area(@context.scanner.pos + str_or_regexp.bytesize - 1) return nil end return str_or_regexp else return nil end end if str_or_regexp.is_a?(Regexp) if (size = @context.scanner.match?(str_or_regexp)) str = @context.scanner.peek(size) @context.line_counter.memo(@context.scanner.pos, str) if @context.borrowed_areas.conflicted_area(@context.scanner.pos + size - 1) return nil end return str end return nil end raise ArgumentError end |
#read(str_or_regexp) ⇒ String
Match with pattern. Backtrack if match failed.
110 111 112 113 114 115 116 117 118 119 |
# File 'lib/pegparse/parser_core.rb', line 110 def read(str_or_regexp) raise ArgumentError unless str_or_regexp ret = peek(str_or_regexp) if ret @context.scanner.pos += ret.bytesize return ret end save_error(str_or_regexp) backtrack() end |
#save_error(reason) ⇒ Object
46 47 48 |
# File 'lib/pegparse/parser_core.rb', line 46 def save_error(reason) @context.errors.save_error(@context.scanner.pos, @context.rule_stack, reason) end |
#zero_or_more(&block) ⇒ Array<Object>
Try to match in loop. Returns [] even no loop succeeded.
188 189 190 191 192 193 194 195 196 |
# File 'lib/pegparse/parser_core.rb', line 188 def zero_or_more(&block) ret = [] while true val = optional { block.call() } break unless val ret << val end return ret end |