module Rsec::Helpers


these are not callable from a parser

Public Instance Methods

lazy(&p) click to toggle source

@ desc.helper

Lazy parser is constructed when parsing starts. It is useful to reference a parser not defined yet

@ example

parser = lazy{future}
future = 'jim'.r
assert_equal 'jim', parser.parse '12323'
# File lib/rsec/helpers.rb, line 16
def lazy &p
  raise ArgumentError, 'lazy() requires a block' unless p
  Lazy[p]
end
one_of(str, &p) click to toggle source

@ desc.helper

Parses one of chars in str

@ example

multiplicative = one_of '*/%'
assert_equal '/', multiplicative.parse '/'
assert_equal Rsec::INVALID, actualmultiplicative.parse '+'
# File lib/rsec/helpers.rb, line 27
def one_of str, &p
  Rsec.assert_type str, String
  raise ArgumentError, 'str len should > 0' if str.empty?
  one_of_klass =
    if (str.bytesize == str.size) and Rsec.const_defined?(:OneOfByte)
      # for C-ext

      OneOfByte
    else
      OneOf
    end
  one_of_klass[str.dup.freeze].map p
end
one_of_(str, &p) click to toggle source

@ desc.helper

See also #one_of#, with leading and trailing optional breakable spaces

@ example

additive = one_of_('+-')
assert_equal '+', additive.parse('  +')
# File lib/rsec/helpers.rb, line 45
def one_of_ str, &p
  Rsec.assert_type str, String
  raise ArgumentError, 'str len should > 0' if str.empty?
  raise ArgumentError, 'str should be ascii' unless str.bytesize == str.size
  raise ArgumentError, 'str should not contain space' if str =~ /\s/
  spaced_one_of_klass =
    if (str.bytesize == str.size) and Rsec.const_defined?(:OneOfByte_)
      # for C-ext

      OneOfByte_
    else
      OneOf_
    end
  spaced_one_of_klass[str.dup.freeze].map p
end
prim(type, options={}) click to toggle source

@ desc.helper

Primitive parser, returns nil if overflow or underflow.
There can be an optional '+' or '-' at the beginning of string except unsinged_int32 | unsinged_int64.
type =
  :double |
  :hex_double |
  :int32 |
  :int64 |
  :unsigned_int32 |
  :unsigned_int64
options:
  :allowed_sign => '+' | '-' | '' | '+-' (default '+-')
  :allowed_signs => (same as :allowed_sign)
  :base => integer only (default 10)

@ example

p = prim :double
assert_equal 1.23, p.parse('1.23')
p = prim :double, allowed_sign: '-'
assert_equal 1.23, p.parse('1.23')
assert_equal -1.23, p.parse('-1.23')
assert_equal Rsec::INVALID, p.parse('+1.23')
p = prim :int32, base: 36
assert_equal 49713, p.parse('12cx')
# File lib/rsec/helpers.rb, line 83
def prim type, options={}, &p
  base = options[:base]
  if [:double, :hex_double].index base
    raise 'Floating points does not allow :base'
  end
  base ||= 10
  Rsec.assert_type base, Integer
  unless (2..36).include? base
    raise RangeError, ":base should be in 2..36, but got #{base}"
  end
  
  sign_strategy = \
    case (options[:allowed_sign] or options[:allowed_signs])
    when nil, '+-', '-+'; 3
    when '+'; 2
    when '-'; 1
    when ''; 0
    else raise "allowed_sign should be one of nil, '', '+', '-', '+-', '-+'"
    end

  parser = \
    case type
    when :double; PDouble.new sign_strategy, false # decimal

    when :hex_double; raise "Removed because Ruby 1.9.3 removed float from hex" # PDouble.new sign_strategy, true # hex

    when :int32;  PInt32.new sign_strategy, base
    when :int64;  PInt64.new sign_strategy, base
    when :unsigned_int32;
      raise 'unsigned int not allow - sign' if options[:allowed_signs] =~ /-/
      PUnsignedInt32.new sign_strategy, base
    when :unsigned_int64;
      raise 'unsigned int not allow - sign' if options[:allowed_signs] =~ /-/
      PUnsignedInt64.new sign_strategy, base
    else
      raise "Invalid primitive type #{type}"
    end
  parser.map p
end
seq(*xs, &p) click to toggle source

@ desc.helper

Sequence parser

@ example

assert_equal ['a', 'b', 'c'], actualseq('a', 'b', 'c').parse('abc')
# File lib/rsec/helpers.rb, line 125
def seq *xs, &p
  xs.map! {|x| Rsec.make_parser x }
  Seq[xs].map p
end
seq_(*xs, &p) click to toggle source

@ desc.helper

Sequence parser with skippable pattern(or parser)
option
  :skip default= /\s*/

@ example

assert_equal ['a', 'b', 'c'], actualseq_('a', 'b', 'c', skip: ',').parse('a,b,c')
# File lib/rsec/helpers.rb, line 136
def seq_ *xs, &p
  skipper = 
    if (xs.last.is_a? Hash)
      xs.pop[:skip]
    end
  skipper = skipper ? Rsec.make_parser(skipper) : /\s*/.r
  xs.map! {|x| Rsec.make_parser x }
  first, *rest = xs
  raise 'sequence should not be empty' unless first
  Seq_[first, rest, skipper].map p
end
symbol(pattern, skip=/\s*/, &p) click to toggle source

@ desc.helper

A symbol is something wrapped with optional space
# File lib/rsec/helpers.rb, line 150
def symbol pattern, skip=/\s*/, &p
  pattern = Rsec.make_parser pattern
  skip = Rsec.try_skip_pattern Rsec.make_parser skip
  SeqOne[[skip, pattern, skip], 1].map p
end
word(pattern, &p) click to toggle source

@ desc.helper

A word is wrapped with word boundaries

@ example

assert_equal ['yes', '3'], seq('yes', '3').parse('yes3')
assert_equal INVALID, seq(word('yes'), '3').parse('yes3')
# File lib/rsec/helpers.rb, line 161
def word pattern, &p
  parser = Rsec.make_parser pattern
  # TODO check pattern type

  Pattern[/\b#{parser.some}\b/].map p
end