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 17 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 28 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 46 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 84 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 126 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 137 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 151 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 162 def word pattern, &p parser = Rsec.make_parser pattern # TODO check pattern type Pattern[/\b#{parser.some}\b/].map p end