lib/cannonbol/cannonbol.rb in cannonbol-1.3.0 vs lib/cannonbol/cannonbol.rb in cannonbol-2.0.0

- old
+ new

@@ -1,60 +1,60 @@ module Cannonbol - + class MatchFailed < Exception; end - + class MatchString < String - + attr_reader :captured attr_reader :match_start attr_reader :match_end - + def initialize(string, match_start, match_end, captured) @cannonbol_string = string @match_start = match_start @match_end = match_end @captured = captured.dup super(@match_end < 0 ? "" : string[@match_start..@match_end]) - end - + end + def replace_match_with(s) before_match = "" before_match = @cannonbol_string[0..@match_start-1] if @match_start > 0 after_match = @cannonbol_string[@match_end+1..-1] || "" before_match + s + after_match end - + end - + class Needle - + attr_reader :cursor attr_reader :string attr_accessor :captures attr_accessor :match_failed attr_accessor :ignore_case - + def initialize(string) @string = string end - + def thread(pattern, opts = {}, &match_block) @captures = {} anchor = opts[:anchor] raise_error = opts[:raise_error] replace_with = opts[:replace_match_with] - ignore_case = opts[:ignore_case] + ignore_case = opts[:ignore_case] | opts[:insensitive] @cursor = -1 match = nil begin while !match and !match_failed and @cursor < @string.length-1 @cursor += 1 @starting_character = nil @success_blocks = [] @ignore_case = ignore_case match = pattern._match?(self) - break if !match and anchor + break if !match and anchor end rescue MatchFailed end if match @success_blocks.each(&:call) @@ -67,194 +67,206 @@ elsif replace_with match = match.replace_match_with(replace_with) end match end - + def capture(name, value) @captures[name.to_sym] = value if name value end - - + + def remaining_string @string[@cursor..-1] end - + def push(length, &success_block) thread_state = [@starting_character, @cursor, @success_blocks.dup, @ignore_case] @starting_character ||= @cursor @cursor += length @success_blocks << success_block if success_block thread_state end - + def pull(thread_state) @starting_character, @cursor, @success_blocks, @ignore_case = thread_state if thread_state nil end - + end - + module Operators - + def _match?(needle, *args, &block) return if needle.match_failed __match?(needle, *args, &block) end - - def match?(s, opts = {}, &match_block) + + def matches?(s, opts = {}, &match_block) Needle.new(s).thread(self, opts, &match_block) end - + def |(pattern) Choose.new(self, pattern) end - + def &(pattern) Concat.new(self, pattern) end - - def -@ + + def insensitive CaseSensitiveOff.new(self) - end + end def capture?(opts = {}, &block) OnSuccess.new(self, opts, &block) end - + def capture!(opts = {}, &block) OnMatch.new(self, opts, &block) end - + + def self.included(base) + base.alias_method :match?, :matches? unless base.method_defined? :match? + base.alias_method :-@, :insensitive unless base.method_defined? :-@ + end end - - class Pattern - + + module CompatibilityAdapter + def self.included(base) + base.alias_method :match?, :matches? + base.alias_method :-@, :insensitive + end + end + + class Pattern + include Operators - + + def __match?(needle) [] end - + end - + class Choose < Pattern - + def __match?(needle, i = 0, s = []) while i < @params.length s = @params[i]._match?(needle, *s) return [i, s] if s s = [] i += 1 end nil end - + def initialize(p1, p2) @params = [p1, p2] end - + end - + class Concat < Pattern - + def __match?(needle, i = 0, s = []) while i < @params.length and i >= 0 s[i] = @params[i]._match?(needle, *(s[i] || [])) i = s[i] ? i+1 : i-1 end [i-1, s] if i == @params.length end - + def initialize(p1, p2) @params = [p1, p2] end - + end - + class CaseSensitiveOff < Pattern - + def initialize(pattern) @pattern = pattern - end - + end + def __match?(needle, s=[]) ignore_case = needle.ignore_case needle.ignore_case = true s = @pattern._match?(needle, *s) needle.ignore_case = ignore_case return [s] if s end - + end - + class OnSuccess < Pattern - + def initialize(pattern, opts, &block) if opts.class == Hash if opts.first @capture_name = opts.first.first @initial_capture_value = opts.first.last - end + end else @capture_name = opts end @pattern = pattern @block = block end - + def __match?(needle, thread_state = nil, starting_cursor = nil, s=[]) needle.pull(thread_state) starting_cursor ||= needle.cursor if s = @pattern._match?(needle, *s) ending_cursor = needle.cursor-1 push = needle.push(0) do match_string = MatchString.new(needle.string, starting_cursor, ending_cursor, needle.captures) - capture_value = @capture_name && (needle.captures.has_key?(@capture_name) ? needle.captures[@capture_name] : @initial_capture_value) + capture_value = @capture_name && (needle.captures.has_key?(@capture_name) ? needle.captures[@capture_name] : @initial_capture_value) if @block - match_string = @block.call(match_string, ending_cursor+1, capture_value) + match_string = @block.call(match_string, ending_cursor+1, capture_value) elsif capture_value.class == Array match_string = capture_value + [match_string] end needle.capture(@capture_name, match_string) end [ push, starting_cursor, s ] end end - + end - + class OnMatch < OnSuccess - + def __match?(needle, starting_cursor = nil, s=[]) starting_cursor ||= needle.cursor if s = @pattern._match?(needle, *s) match_string = MatchString.new(needle.string, starting_cursor, needle.cursor-1, needle.captures) - capture_value = @capture_name && (needle.captures.has_key?(@capture_name) ? needle.captures[@capture_name] : @initial_capture_value) + capture_value = @capture_name && (needle.captures.has_key?(@capture_name) ? needle.captures[@capture_name] : @initial_capture_value) match_string = @block.call(match_string, needle.cursor, capture_value) if @block needle.capture(@capture_name, match_string) [starting_cursor, s] end end - + end - + class Match < Pattern - + def initialize(sub_pattern_or_name = nil, &block) if block @block = block elsif sub_pattern_or_name and sub_pattern_or_name.class == Symbol @name = sub_pattern_or_name elsif sub_pattern_or_name and sub_pattern_or_name.respond_to? "_match?" - @pattern = sub_pattern_or_name + @pattern = sub_pattern_or_name elsif sub_pattern_or_name and sub_pattern_or_name.respond_to? "to_s" @pattern = sub_pattern_or_name.to_s end - end - + end + def __match?(needle, pattern = nil, s = []) pattern ||= if @block @block.call elsif @name needle.captures[@name] || "" @@ -263,219 +275,219 @@ end existing_captures = needle.captures.dup s = pattern._match?(needle, *s) needle.captures = needle.captures.merge(existing_captures) [pattern, s] if s - end - + end + end - + class Rem < Pattern - + def __match?(needle, thread_state = nil) if thread_state needle_pull(thread_state) else [needle.push(needle.string.length-needle.cursor)] - end + end end - + end - + class Arb < Pattern - + def __match?(needle, match_length = 0, thread_state = nil) needle.pull(thread_state) - if needle.remaining_string.length >= match_length + if needle.remaining_string.length >= match_length thread_state = needle.push(match_length) match_length += 1 [match_length, thread_state] end end - + end - + class ParameterizedPattern < Pattern - + def initialize(opts = nil, &block) if opts.class == Hash if opts.first @param_name = opts.first.first @initial_param_value = opts.first.last - end + end else @initial_param_value = opts end @block = block end - + def self.parameter(name, &post_processor) @post_processor = post_processor define_method(name) do |needle| value = (@param_name && needle.captures.has_key?(@param_name)) ? needle.captures[@param_name] : @initial_param_value value = @block.call(value) if @block - needle.capture(@param_name, value) + needle.capture(@param_name, value) value = post_processor.call(value) if @post_processor value end end - + end - + class Len < ParameterizedPattern - + parameter :len - + def __match?(needle, thread_state = nil) if thread_state needle.pull(thread_state) else len_temp = len(needle) [needle.push(len_temp)] if needle.remaining_string.length >= len_temp end - + end - + end - + class Pos < ParameterizedPattern - + parameter :pos - + def __match?(needle, matched = nil) return [true] if needle.cursor == pos(needle) and !matched - end - - end - + end + + end + class RPos < ParameterizedPattern - + parameter :pos - + def __match?(needle, matched = nil) return [true] if needle.string.length-needle.cursor == pos(needle) and !matched - end - + end + end - + class Tab < ParameterizedPattern - + parameter :pos - + def __match?(needle, thread_state = nil) - + if thread_state needle.pull(thread_state) else len = pos(needle) - needle.cursor - [needle.push(len)] if len >= 0 and needle.remaining_string.length >= len + [needle.push(len)] if len >= 0 and needle.remaining_string.length >= len end end - + end - + class RTab < ParameterizedPattern - + parameter :pos - + def __match?(needle, thread_state = nil) if thread_state needle.pull(thread_state) else - len = (needle.remaining_string.length - pos(needle)) + len = (needle.remaining_string.length - pos(needle)) [needle.push(len)] if len >= 0 and needle.remaining_string.length >= len end end - + end - + class Any < ParameterizedPattern - + parameter :chars, &:split - + def __match?(needle, thread_state = nil) if thread_state needle.pull(thread_state) elsif chars(needle).include? needle.remaining_string[0..0] [needle.push(1)] end end - + end - + class NotAny < ParameterizedPattern - + parameter :chars, &:split - + def __match?(needle, thread_state = nil) if thread_state needle.pull(thread_state) elsif !(chars(needle).include? needle.remaining_string[0..0]) [needle.push(1)] end end - - end - + + end + class Span < ParameterizedPattern - + parameter :chars, &:split - + def __match?(needle, match_length = nil, thread_state = nil) unless match_length the_chars, match_length = chars(needle), 0 while needle.remaining_string.length > match_length and the_chars.include? needle.remaining_string[match_length..match_length] match_length += 1 - end + end end needle.pull(thread_state) - if match_length > 0 + if match_length > 0 thread_state = needle.push(match_length) match_length -= 1 [match_length, thread_state] end end - + end - + class Break < ParameterizedPattern - + parameter :chars, &:split - + def __match?(needle, thread_state = nil) if thread_state needle.pull(thread_state) else the_chars, len = chars(needle), 0 while needle.remaining_string.length > len and !(the_chars.include? needle.remaining_string[len..len]) len += 1 - end + end [needle.push(len)] - end - end - - end + end + end - + end + + class BreakX < ParameterizedPattern - + parameter :chars, &:split - + def __match?(needle, len = 0, thread_state = nil) needle.pull(thread_state) the_chars = chars(needle) while needle.remaining_string.length > len and !(the_chars.include? needle.remaining_string[len..len]) len += 1 - end + end [len+1, needle.push(len)] if needle.remaining_string.length >= len - end - - end - + end + + end + class Arbno < Match - + def __match?(needle, pattern = nil, s = [[]]) return if s.length == 0 if pattern existing_captures = needle.captures.dup s[-1] = pattern._match?(needle, *(s.last)) @@ -489,31 +501,31 @@ else pattern = @pattern end end [pattern, s] - end - + end + end - + class FailPat < Pattern - + def __match?(needle) - end - + end + end - + class Abort < Pattern - + def __match?(needle) raise MatchFailed - end - + end + end - + class Fence < Match - + def __match?(needle, on_backtrack = nil) if on_backtrack == :fail_match needle.match_failed = true return nil elsif on_backtrack == :return_nil @@ -526,43 +538,43 @@ pattern = @pattern else return [:fail_match] end return [:return_nil] if pattern._match?(needle) - end - - end - + end + + end + class Succeed < Pattern def _match?(needle, thread_state = nil) needle.pull(thread_state) [needle.push(0)] end end - end class String - + include Cannonbol::Operators - + def __match?(needle, thread_state = nil) + if thread_state needle.pull(thread_state) - elsif self.length == 0 or - (!needle.ignore_case and needle.remaining_string[0..self.length-1] == self) or + elsif self.length == 0 or + (!needle.ignore_case and needle.remaining_string[0..self.length-1] == self) or (needle.ignore_case and needle.remaining_string[0..self.length-1].upcase == self.upcase) [needle.push(self.length)] end end - + end class Regexp - + include Cannonbol::Operators - + def __match?(needle, thread_state = nil) if RUBY_ENGINE == 'opal' options = "" options += "m" if `#{self}.multiline` options += "g" if `#{self}.global` @@ -575,104 +587,105 @@ needle.pull(thread_state) elsif m = @cannonbol_regex.match(needle.remaining_string) [needle.push(m[0].length)] end end - + end + if RUBY_ENGINE == 'opal' - + class Proc - + def parameters /.*function[^(]*\(([^)]*)\)/.match(`#{self}.toString()`)[1].split(",").collect { |param| [:req, param.strip.to_sym]} end - - end - + + end + end module Enumerable - + def match_any - if self.first + if self.first self[1..-1].inject(self.first) { |memo, item| memo | item } else FAIL end - end - + end + def match_all self.inject("") { |memo, item| memo & item } - end - + end + end - + class Object - + REM = Cannonbol::Rem.new - + ARB = Cannonbol::Arb.new - + FAIL = Cannonbol::FailPat.new - + ABORT = Cannonbol::Abort.new - + FENCE = Cannonbol::Fence.new - + SUCCEED = Cannonbol::Succeed.new - + def LEN(p={}, &block) Cannonbol::Len.new(p, &block) end - + def POS(p=nil, &block) Cannonbol::Pos.new(p, &block) - end - + end + def RPOS(p=nil, &block) Cannonbol::RPos.new(p, &block) - end - + end + def TAB(p=nil, &block) Cannonbol::Tab.new(p, &block) end - + def RTAB(p=nil, &block) Cannonbol::RTab.new(p, &block) end - + def ANY(p=nil, &block) Cannonbol::Any.new(p, &block) - end - + end + def NOTANY(p=nil, &block) Cannonbol::NotAny.new(p, &block) end - + def SPAN(p=nil, &block) Cannonbol::Span.new(p, &block) end - + def BREAK(p=nil, &block) Cannonbol::Break.new(p, &block) - end - + end + def BREAKX(p=nil, &block) Cannonbol::BreakX.new(p, &block) - end - + end + def MATCH(p=nil, &block) Cannonbol::Match.new(p, &block) - end - + end + def ARBNO(p=nil, &block) Cannonbol::Arbno.new(p, &block) - end - + end + def FENCE(p=nil, &block) Cannonbol::Fence.new(p, &block) end - -end \ No newline at end of file + +end