class Parsby

Constants

VERSION

Attributes

label[W]

Public Class Methods

new(label = nil, &b) click to toggle source

Initialize parser with optional label argument, and parsing block. The parsing block is given an IO as argument, and its result is the result when parsing.

# File lib/parsby.rb, line 606
def initialize(label = nil, &b)
  self.label = label if label
  @parser = b
end

Public Instance Methods

%(name) click to toggle source

Set the label and return self.

# File lib/parsby.rb, line 709
def %(name)
  self.label = name
  self
end
*(n) click to toggle source

p * n, runs parser p n times, grouping results in an array.

# File lib/parsby.rb, line 684
def *(n)
  Parsby.new "(#{label} * #{n})" do |c|
    n.times.map { parse c }
  end
end
+(p) click to toggle source

x + y does + on the results of x and y. This is mostly meant to be used with arrays, but it would work with numbers and strings too.

# File lib/parsby.rb, line 692
def +(p)
  group(self, p)
    .fmap {|(x, y)| x + y }
    .tap {|r| r.label = "(#{label} + #{p.label})" }
end
<(p) click to toggle source

x < y runs parser x then y and returns x.

# File lib/parsby.rb, line 659
def <(p)
  ~splicer.start do |m|
    m.end(self).then {|r| m.end(p).then { pure r } }
  end % "(#{label} < #{p.label})"
end
<<(p) click to toggle source

xs << x appends result of parser x to list result of parser xs.

# File lib/parsby.rb, line 699
def <<(p)
  Parsby.new "(#{label} << #{p.label})" do |c|
    x = parse c
    y = p.parse c
    # like x << y, but without modifying x.
    x + [y]
  end
end
>(p) click to toggle source

x > y runs parser x then y and returns y.

# File lib/parsby.rb, line 666
def >(p)
  self.then { p } % "(#{label} > #{p.label})"
end
fmap(&b) click to toggle source

Like map for arrays, this lets you work with the value “inside” the parser, i.e. the result.

Example:

decimal.fmap {|x| x + 1}.parse("2")
=> 3
# File lib/parsby.rb, line 721
def fmap(&b)
  Parsby.new "#{label}.fmap" do |c|
    b.call parse c
  end
end
label() click to toggle source

The parser's label. It's an “unknown” token by default.

# File lib/parsby.rb, line 597
def label
  @label || "unknown"
end
parse(src) click to toggle source

Parse a String or IO object.

# File lib/parsby.rb, line 612
def parse(src)
  ctx = src.is_a?(Context) ? src : Context.new(src)
  parsed_range = ParsedRange.new(ctx.bio.pos, ctx.bio.pos, label)
  ctx.parsed_ranges << parsed_range if ctx.parsed_ranges
  parent_parsed_range = ctx.parsed_ranges
  ctx.parsed_ranges = parsed_range
  begin
    r = @parser.call ctx
  rescue ExpectationFailed => e
    ctx.parsed_ranges.end = ctx.bio.pos
    ctx.parsed_ranges.failed = true
    ctx.bio.restore_to ctx.parsed_ranges.start
    raise
  else
    ctx.parsed_ranges.end = ctx.bio.pos
    r
  ensure
    # Keep the root one for use in ExceptionFailed#message
    if parent_parsed_range
      ctx.parsed_ranges = parent_parsed_range
    end
  end
end
peek(src) click to toggle source

Parses without consuming input.

# File lib/parsby.rb, line 637
def peek(src)
  ctx = src.is_a?(Context) ? src : Context.new(src)
  starting_pos = ctx.bio.pos
  begin
    parse ctx
  ensure
    ctx.bio.restore_to starting_pos
  end
end
that_fail(p)
Alias for: that_fails
that_fails(p) click to toggle source

x.that_fails(y) will try y, fail if y succeeds, or parse with x if y fails.

Example:

decimal.that_fails(string("10")).parse "3"
=> 3
decimal.that_fails(string("10")).parse "10"
Parsby::ExpectationFailed: line 1:
  10
  \/ expected: (not "10")
# File lib/parsby.rb, line 762
def that_fails(p)
  Parsby.new "#{label}.that_fails(#{p.label})" do |c|
    orig_pos = c.bio.pos
    begin
      r = p.parse c.bio
    rescue Error
      c.bio.restore_to orig_pos
      parse c.bio
    else
      raise ExpectationFailed.new c
    end
  end
end
Also aliased as: that_fail
then(&b) click to toggle source

Pass result of self parser to block to construct the next parser.

For example, instead of writing:

Parsby.new do |c|
  x = foo.parse c
  bar(x).parse c
end

you can write:

foo.then {|x| bar x }

This is analogous to Parsec's >>= operator in Haskell, where you could write:

foo >>= bar
# File lib/parsby.rb, line 744
def then(&b)
  Parsby.new "#{label}.then" do |c|
    b.call(parse(c)).parse(c)
  end
end
|(p) click to toggle source

x | y tries y if x fails.

# File lib/parsby.rb, line 648
def |(p)
  Parsby.new "(#{self.label} | #{p.label})" do |c|
    begin
      parse c
    rescue Error
      p.parse c
    end
  end
end
~() click to toggle source
# File lib/parsby.rb, line 670
def ~
  Parsby.new "(~ #{label})" do |c|
    begin
      parse c
    ensure
      c.parsed_ranges.children[0].splice_self!
      if c.parsed_ranges.parent
        c.parsed_ranges.splice_self!
      end
    end
  end
end