class EBNF::Parser

Attributes

ast[R]

Abstract syntax tree from parse

@return [Array<EBNF::Rule>]

Public Class Methods

new(input, **options, &block) click to toggle source

## Parser invocation. On start, yield ourselves if a block is given, otherwise, return this parser instance

@param [#read, to_s] input @param [Hash{Symbol => Object}] options @option options [Boolean] :level

Trace level. 0(debug), 1(info), 2(warn), 3(error).

@return [EBNFParser]

# File lib/ebnf/parser.rb, line 265
def initialize(input, **options, &block)
  # If the `level` option is set, instantiate a logger for collecting trace information.
  if options.has_key?(:level)
    options[:logger] = Logger.new(STDERR)
    options[:logger].level = options[:level]
    options[:logger].formatter = lambda {|severity, datetime, progname, msg| "#{severity} #{msg}\n"}
  end

  # Read input, if necessary, which will be used in a Scanner.
  @input = input.respond_to?(:read) ? input.read : input.to_s

  parsing_terminals = false
  @ast = []
  parse(@input, :ebnf, EBNFMeta::RULES,
                       # Use an optimized Regexp for whitespace
                       whitespace: EBNF::Terminals::PASS,
                       **options
  ) do |context, *data|
    rule = case context
    when :terminals
      # After parsing `@terminals`
      # This changes the state of the parser to treat subsequent rules as terminals.
      parsing_terminals = true
      rule = EBNF::Rule.new(nil, nil, data.first, kind: :terminals)
    when :pass
      # After parsing `@pass`
      # This defines a specific rule for whitespace.
      rule = EBNF::Rule.new(nil, nil, data.first, kind: :pass)
    when :rule
      # A rule which has already been turned into a `Rule` object.
      rule = data.first
      rule.kind = :terminal if parsing_terminals
      rule
    end
    @ast << rule if rule
  end
rescue EBNF::PEG::Parser::Error => e
  raise SyntaxError, e.message
end