class Hammer::ParserBuilder

Attributes

parsers[R]

Public Class Methods

new() click to toggle source
# File lib/hammer/parser_builder.rb, line 21
def initialize
  @parsers = []
end

Private Class Methods

define_parser(name, options = {}) click to toggle source

Defines a parser constructor with the given name.

# File lib/hammer/parser_builder.rb, line 64
def self.define_parser(name, options = {})
  define_method name do |*args|
    # TODO: This is wrong!! Needs to accept a block for nested parsers!
    @parsers << Hammer::Parser.send(name, *args)
    return self
  end
end

Public Instance Methods

action(&block) click to toggle source

modifies previous parser

# File lib/hammer/parser_builder.rb, line 56
def action(&block)
  parser = @parsers.last
  raise RuntimeError, 'need a parser before action' if parser.nil?
  @parsers << Hammer::Parser.action(parser, &block)
  return self
end
build() click to toggle source
# File lib/hammer/parser_builder.rb, line 25
def build
  if @parsers.length > 1
    Hammer::Parser.sequence(*@parsers)
  else
    @parsers.first
  end
end
call(parser) click to toggle source
# File lib/hammer/parser_builder.rb, line 50
def call(parser)
  @parsers << parser
  return self
end
choice(*parsers, &block) click to toggle source
# File lib/hammer/parser_builder.rb, line 42
def choice(*parsers, &block)
  if block_given?
    parsers += Docile.dsl_eval(ParserBuilder.new, &block).parsers
  end
  @parsers << Hammer::Parser.choice(*parsers)
  return self
end
indirect() click to toggle source

At least indirect must return the parser instead of the builder, so it can be stored in a variable. Other possible solution:

Make indirect take a name parameter, and use the name to bind it later.
Example:
  p = Hammer::Parser.build { indirect(:the_name) }
  p.bind(:the_name, inner_parser)
(store names and parsers in hash in the builder,
 when building merge hashes from sub builders and store everything in the resulting sequence or choice.
 make Parser#bind take and optional symbol. if it is given, the name is looked up in the table.)

TODO:

Think about this more.
Do we need to be able to build parsers by chaining function calls? DSL should be sufficient.
If yes, the parser methods in this class should not return "self", but the Hammer::Parser object they create.
# File lib/hammer/parser_builder.rb, line 116
def indirect
  parser = Hammer::Parser.indirect
  @parsers << parser
  return parser
end
sequence(*parsers, &block) click to toggle source

can call it either as ParserBuiler.new.sequence(parser1, parser2, parser3) or as Parser.build { sequence { call parser1; call parser2; call parser3 } }

# File lib/hammer/parser_builder.rb, line 36
def sequence(*parsers, &block)
  @parsers += parsers
  @parsers << Docile.dsl_eval(ParserBuilder.new, &block).build if block_given?
  return self
end