lib/cannonbol.rb in cannonbol-1.1.0 vs lib/cannonbol.rb in cannonbol-1.3.0
- old
+ new
@@ -1,678 +1,9 @@
-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
-
- 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
-
+require_relative 'cannonbol/cannonbol'
+require_relative 'cannonbol/version'
+unless RUBY_ENGINE == 'opal'
+ begin
+ require 'opal'
+ Opal.append_path File.expand_path('..', __FILE__).untaint
+ rescue LoadError
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]
- @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
- end
- rescue MatchFailed
- end
- if match
- @success_blocks.each(&:call)
- match = MatchString.new(@string, @starting_character || @cursor, @cursor-1, @captures)
- else
- raise MatchFailed if raise_error
- end
- if match_block
- match = match_block.call(*([match] + (match_block.parameters[1..-1] || []).collect { |param| @captures[param[1].to_sym] }))
- 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)
- Needle.new(s).thread(self, opts, &match_block)
- end
-
- def |(pattern)
- Choose.new(self, pattern)
- end
-
- def &(pattern)
- Concat.new(self, pattern)
- end
-
- def -@
- CaseSensitiveOff.new(self)
- end
-
- def capture?(opts = {}, &block)
- OnSuccess.new(self, opts, &block)
- end
-
- def capture!(opts = {}, &block)
- OnMatch.new(self, opts, &block)
- 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
-
- def __match?(needle, thread=nil, s=[])
- needle.pull(thread)
- thread = needle.push(0)
- needle.ignore_case = true
- s = @pattern._match?(needle, *s)
- return [thread, 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
- 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)
- if @block
- 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)
- 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
- elsif sub_pattern_or_name and sub_pattern_or_name.respond_to? "to_s"
- @pattern = sub_pattern_or_name.to_s
- end
- end
-
- def __match?(needle, pattern = nil, s = [])
- pattern ||= if @block
- @block.call
- elsif @name
- needle.captures[@name] || ""
- else
- @pattern
- end
- existing_captures = needle.captures.dup
- s = pattern._match?(needle, *s)
- needle.captures = needle.captures.merge(existing_captures)
- [pattern, s] if s
- 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
-
- class Arb < Pattern
-
- def __match?(needle, match_length = 0, thread_state = nil)
- needle.pull(thread_state)
- 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
- 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)
- 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
-
- class RPos < ParameterizedPattern
-
- parameter :pos
-
- def __match?(needle, matched = nil)
- return [true] if needle.string.length-needle.cursor == pos(needle) and !matched
- 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
- 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))
- [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
-
- 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
- needle.pull(thread_state)
- 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
- [needle.push(len)]
- 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
- [len+1, needle.push(len)] if needle.remaining_string.length >= len
- 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))
- s = s[-1] ? s + [[]] : s[0..-2]
- needle.captures = needle.captures.merge(existing_captures)
- else
- if @block
- pattern = @block.call
- elsif @name
- pattern = needle.captures[@name] || ""
- else
- pattern = @pattern
- end
- end
- [pattern, s]
- end
-
- end
-
- class FailPat < Pattern
-
- def __match?(needle)
- end
-
- end
-
- class Abort < Pattern
-
- def __match?(needle)
- raise MatchFailed
- 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
- return nil
- elsif @block
- pattern = @block.call
- elsif @name
- pattern = needle.captures[@name] || ""
- elsif @pattern
- pattern = @pattern
- else
- return [:fail_match]
- end
- return [:return_nil] if pattern._match?(needle)
- 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
- (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 defined? Opal
- options = ""
- options += "m" if `#{self}.multiline`
- options += "g" if `#{self}.global`
- options += "i" if needle.ignore_case or `#{self}.ignoreCase`
- else
- options = self.options | (needle.ignore_case ? Regexp::IGNORECASE : 0)
- end
- @cannonbol_regex ||= Regexp.new("^#{self.source}", options )
- if thread_state
- needle.pull(thread_state)
- elsif m = @cannonbol_regex.match(needle.remaining_string)
- [needle.push(m[0].length)]
- end
- end
-
-end
-
-if defined? Opal
-
- class Proc
-
- def parameters
- /.*function[^(]*\(([^)]*)\)/.match(`#{self}.toString()`)[1].split(",").collect { |param| [:req, param.strip.to_sym]}
- end
-
- end
-
-end
-
-module Enumerable
-
- def match_any
- if self.first
- self[1..-1].inject(self.first) { |memo, item| memo | item }
- else
- FAIL
- end
- end
-
- def match_all
- self.inject("") { |memo, item| memo & item }
- 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
-
- def RPOS(p=nil, &block)
- Cannonbol::RPos.new(p, &block)
- 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
-
- 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
-
- def BREAKX(p=nil, &block)
- Cannonbol::BreakX.new(p, &block)
- end
-
- def MATCH(p=nil, &block)
- Cannonbol::Match.new(p, &block)
- end
-
- def ARBNO(p=nil, &block)
- Cannonbol::Arbno.new(p, &block)
- end
-
- def FENCE(p=nil, &block)
- Cannonbol::Fence.new(p, &block)
- end
-
end
\ No newline at end of file