class ParserCombinator

Constants

ParserCombinatorError
VERSION

Attributes

parser_name[R]
parser_proc[R]
status_handler[R]

Public Class Methods

binopl(parser, op_proc_parser) click to toggle source
# File lib/parser_combinator.rb, line 292
def self.binopl(parser, op_proc_parser)
  rest = proc{|a|
    op_proc_parser >> proc{|f|
      parser >> proc{|b|
        rest.call(f.call(a, b))
      }} | ok(a)
  }
  parser >> proc{|a|
    rest.call(a)
  }
end
binopl_fail(parser, op_proc_parser) click to toggle source
# File lib/parser_combinator.rb, line 304
def self.binopl_fail(parser, op_proc_parser)
  rest = proc{|a|
    op_proc_parser >> proc{|f|
      parser >> proc{|b|
        rest.call(f.call(a, b))
      }} ^ ok(a)
  }
  parser >> proc{|a|
    rest.call(a)
  }
end
discardl(parser1, parser2) click to toggle source
# File lib/parser_combinator.rb, line 281
def self.discardl(parser1, parser2)
  parser1 >> proc{parser2}
end
discardr(parser1, parser2) click to toggle source
# File lib/parser_combinator.rb, line 285
def self.discardr(parser1, parser2)
  parser1 >> proc{|x|
    parser2 >> proc{
      ok(x)
    }}
end
either(parser1, parser2) click to toggle source
# File lib/parser_combinator.rb, line 193
def self.either(parser1, parser2)
  new{|i|
    case result1 = parser1.parse(i)
    when Fail
      parser2.parse(i)
    when Ok
      result1
    else
      raise "error"
    end
  }
end
either_fail(parser1, parser2) click to toggle source
# File lib/parser_combinator.rb, line 206
def self.either_fail(parser1, parser2)
  new{|i|
    case result1 = parser1.parse(i)
    when Fail
      if result1.status == nil
        parser2.parse(i)
      else
        result1
      end
    when Ok
      result1
    else
      raise "error"
    end
  }
end
end_of_input() click to toggle source
# File lib/parser_combinator.rb, line 227
def self.end_of_input
  new{|i| i.size == 0 ? Ok.new(nil, i) : Fail.new}
end
fail(status=nil) click to toggle source
# File lib/parser_combinator.rb, line 176
def self.fail(status=nil)
  new{|i| Fail.new(status)}
end
item() click to toggle source
# File lib/parser_combinator.rb, line 223
def self.item
  new{|i| i.size == 0 ? Fail.new : Ok.new(i.head, i.rest)}
end
many(parser, separator_parser=ok(nil)) click to toggle source
# File lib/parser_combinator.rb, line 255
def self.many(parser, separator_parser=ok(nil))
  many1(parser, separator_parser) | ok([])
end
many1(parser, separator_parser=ok(nil)) click to toggle source
# File lib/parser_combinator.rb, line 259
def self.many1(parser, separator_parser=ok(nil))
  parser >> proc{|x|
     many(separator_parser > parser) >> proc{|xs|
      ok([x] + xs)
    }}
end
many1_fail(parser, separator_parser=ok(nil)) click to toggle source
# File lib/parser_combinator.rb, line 274
def self.many1_fail(parser, separator_parser=ok(nil))
  parser >> proc{|x|
    many_fail(separator_parser > parser) >> proc{|xs|
      ok([x] + xs)
    }}
end
many_fail(parser, separator_parser=ok(nil)) click to toggle source
# File lib/parser_combinator.rb, line 270
def self.many_fail(parser, separator_parser=ok(nil))
  many1_fail(parser, separator_parser) ^ ok([])
end
new(status_handler=proc{nil}, name=nil, &proc) click to toggle source
# File lib/parser_combinator.rb, line 101
def initialize(status_handler=proc{nil}, name=nil, &proc)
  @status_handler = status_handler
  @parser_name = name
  @parser_proc = proc
end
ok(object) click to toggle source

CoreCombinator


# File lib/parser_combinator.rb, line 172
def self.ok(object)
  new{|i| Ok.new(object, i)}
end
opt(parser) click to toggle source
# File lib/parser_combinator.rb, line 251
def self.opt(parser)
  parser.map{|x| [x]} | ok([])
end
opt_fail(parser) click to toggle source
# File lib/parser_combinator.rb, line 266
def self.opt_fail(parser)
  parser.map{|x| [x]} ^ ok([])
end
parser(name, &proc) click to toggle source

Memorization DSL suport (for recursive grammer)


# File lib/parser_combinator.rb, line 319
def self.parser(name, &proc)
  @cache ||= {}
  spcls = class << self; self end
  spcls.send(:define_method, name) do |*args|
    key = [name, args]
    if @cache[key]
      return @cache[key]
    else
      status_handler = proc{ raise "this is never-called proc (status_handler)" }
      parser_proc = proc{ raise "this is never-called proc (parser_proc)" }
      @cache[key] = self.new(proc{|*args| status_handler.call(*args)}){|*args| parser_proc.call(*args)}
      generated_parser = proc.call(*args)
      parser_proc = generated_parser.parser_proc
      status_handler = generated_parser.status_handler
      return @cache[key]
    end
  end
end
sat(&item_cond_proc) click to toggle source
# File lib/parser_combinator.rb, line 231
def self.sat(&item_cond_proc)
  item >> proc{|i|
    item_cond_proc.call(i.item) ? ok(i) : fail
  }
end
seq(*parsers) click to toggle source

UtilCombinator


# File lib/parser_combinator.rb, line 240
def self.seq(*parsers)
  if parsers.size == 0
    ok(ParsedSeq.empty)
  else
    parsers.first >> proc{|x|
      seq(*parsers.drop(1)) >> proc{|xs|
        ok(xs.cons(x, parsers.first.parser_name))
      }}
  end
end
so_then(parser, &continuation_proc) click to toggle source
# File lib/parser_combinator.rb, line 180
def self.so_then(parser, &continuation_proc)
  new{|i|
    case result = parser.parse(i)
    when Fail
      result
    when Ok
      continuation_proc.call(result.parsed).parse(result.rest)
    else
      raise "error"
    end
  }
end

Public Instance Methods

<(other) click to toggle source
# File lib/parser_combinator.rb, line 165
def <(other)
  self.class.discardr(self, other)
end
>(other) click to toggle source
# File lib/parser_combinator.rb, line 161
def >(other)
  self.class.discardl(self, other)
end
>>(proc) click to toggle source
# File lib/parser_combinator.rb, line 149
def >>(proc)
  self.class.so_then(self, &proc)
end
^(other) click to toggle source
# File lib/parser_combinator.rb, line 157
def ^(other)
  self.class.either_fail(self, other)
end
map(&mapping) click to toggle source
# File lib/parser_combinator.rb, line 145
def map(&mapping)
  self >> proc{|x| self.class.ok(mapping.call(x))}
end
name(new_name) click to toggle source
# File lib/parser_combinator.rb, line 141
def name(new_name)
  self.class.new(@status_handler, new_name, &parser_proc)
end
onfail(message=nil, ifnotyet=false, &status_handler) click to toggle source
# File lib/parser_combinator.rb, line 123
def onfail(message=nil, ifnotyet=false, &status_handler)
  raise "Only eihter message or fail_handler can be specified" if message && status_handler
  if message
    onfail{|items, status| status == nil ? StandardFailStatus.new(message, items) : status}
  elsif status_handler
    self.class.new(status_handler, @parser_name, &parser_proc)
  else
    self
  end
end
onparse(&proc) click to toggle source
# File lib/parser_combinator.rb, line 134
def onparse(&proc)
  self.class.new(@status_handler, @parser_name) do |*args|
    proc.call(*args)
    @parser_proc.call(*args)
  end
end
parse(items) click to toggle source
# File lib/parser_combinator.rb, line 107
def parse(items)
  result = @parser_proc.call(items)
  case result
  when Fail
    if  @status_handler.call(items, result.status) != nil
      result.class.new(@status_handler.call(items, result.status))
    else
      result
    end
  when Ok
    result
  else
    raise "parsed object is #{result.inspect}/#{result.class}"
  end
end
|(other) click to toggle source
# File lib/parser_combinator.rb, line 153
def |(other)
  self.class.either(self, other)
end