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