lib/jkf/parser/base.rb in jkf-0.5.0 vs lib/jkf/parser/base.rb in jkf-0.5.1

- old
+ new

@@ -1,118 +1,104 @@ -module Jkf::Parser - # Base of Parser - class Base - # start parse - # - # @param [String] input - # - # @return [Hash] JKF - def parse(input) - @input = input.clone +require 'strscan' - @current_pos = 0 - @reported_pos = 0 - @cached_pos = 0 - @cached_pos_details = { line: 1, column: 1, seenCR: false } - @max_fail_pos = 0 - @max_fail_expected = [] - @silent_fails = 0 +module Jkf + module Parser + # Base of Parser + class Base + # start parse + # + # @param [String] input + # + # @return [Hash] JKF + def parse(input) + @scanner = StringScanner.new(input.dup) + @reported_pos = 0 + @max_fail_pos = 0 - @result = parse_root + @result = parse_root - if success? && @current_pos == @input.size - return @result - else - fail(type: "end", description: "end of input") if failed? && @current_pos < input.size - raise ParseError + if success? && @scanner.eos? + @result + else + record_failure(type: 'end', description: 'end of input') if failed? && @scanner.pos < input.size + raise ParseError + end end - end - protected + protected - def success? - @result != :failed - end + def success? + @result != :failed + end - def failed?; !success?; end + def failed?; !success?; end - # match regexp - def match_regexp(reg) - ret = nil - if matched = reg.match(@input[@current_pos]) - ret = matched.to_s - @current_pos += ret.size - else - ret = :failed - fail(type: "class", value: reg.inspect, description: reg.inspect) if @silent_fails == 0 + def match_regexp(reg) + matched = @scanner.scan(reg) + unless matched + record_failure(type: 'class', value: reg.inspect, description: reg.inspect) + return :failed + end + matched end - ret - end - # match string - def match_str(str) - ret = nil - if @input[@current_pos, str.size] == str - ret = str - @current_pos += str.size - else - ret = :failed - fail(type: "literal", value: str, description: "\"#{str}\"") if @slient_fails == 0 + def match_str(str) + matched = @scanner.scan(str) + unless matched + record_failure(type: 'literal', value: str, description: str.inspect) + return :failed + end + matched end - ret - end - # match space - def match_space - match_str(" ") - end + # match space + def match_space + match_str(' ') + end - # match space one or more - def match_spaces - stack = [] - matched = match_space - while matched != :failed - stack << matched + # match space one or more + def match_spaces + stack = [] matched = match_space + while matched != :failed + stack << matched + matched = match_space + end + stack end - stack - end - # match digit - def match_digit - match_regexp(/^\d/) - end + # match digit + def match_digit + match_regexp(/\d/) + end - # match digits - def match_digits - stack = [] - matched = match_digit - while matched != :failed - stack << matched + # match digits + def match_digits + stack = [] matched = match_digit + while matched != :failed + stack << matched + matched = match_digit + end + stack end - stack - end - # match digit one ore more - def match_digits! - matched = match_digits - if matched.empty? - :failed - else - matched + # match digit one ore more + def match_digits! + matched = match_digits + if matched.empty? + :failed + else + matched + end end - end - # record failure - def fail(expected) - return if @current_pos < @max_fail_pos + def record_failure(expected) + return if @scanner.pos < @max_fail_pos - if @current_pos > @max_fail_pos - @max_fail_pos = @current_pos - @max_fail_expected = [] - end + return unless @scanner.pos > @max_fail_pos - @max_fail_expected << expected + @max_fail_pos = @scanner.pos + end end end end