lib/ebnf/peg/parser.rb in ebnf-2.0.0 vs lib/ebnf/peg/parser.rb in ebnf-2.1.0
- old
+ new
@@ -49,10 +49,11 @@
end
# DSL for creating terminals and productions
module ClassMethods
def start_handlers; (@start_handlers ||= {}); end
+ def start_options; (@start_hoptions ||= {}); end
def production_handlers; (@production_handlers ||= {}); end
def terminal_handlers; (@terminal_handlers ||= {}); end
def terminal_regexps; (@terminal_regexps ||= {}); end
##
@@ -95,21 +96,26 @@
# current production. Block is called in an evaluation block from
# the enclosing parser.
#
# @param [Symbol] term
# The rule name
+ # @param [Hash{Symbol => Object}] options
+ # Options which are returned from {Parser#onStart}.
+ # @option options [Boolean] :as_hash (false)
+ # If the production is a `seq`, causes the value to be represented as a single hash, rather than an array of individual hashes for each sub-production. Note that this is not always advisable due to the possibility of repeated productions within the sequence.
# @yield [data, block]
# @yieldparam [Hash] data
# A Hash defined for the current production, during :start
# may be initialized with data to pass to further productions,
# during :finish, it contains data placed by earlier productions
# @yieldparam [Proc] block
# Block passed to initialization for yielding to calling parser.
# Should conform to the yield specs for #initialize
# Yield to generate a triple
- def start_production(term, &block)
+ def start_production(term, **options, &block)
start_handlers[term] = block
+ start_options[term] = options.freeze
end
##
# Defines a production called when production of associated
# non-terminals has completed
@@ -202,10 +208,11 @@
# Take whitespace from options, a named rule, a `pass` rule, a rule named :WS, or a default
@whitespace = case options[:whitespace]
when Regexp then options[:whitespace]
when Symbol then @rules[options[:whitespace]]
+ else options[:whitespace]
end ||
@rules.values.detect(&:pass?) ||
/(?:\s|(?:#[^x][^\n\r]*))+/m.freeze
@options = options.dup
@@ -327,23 +334,34 @@
# @param [Array<String>] args Relevant location associated with message
# @param [Hash] options
# @option options [Integer] :depth
# Recursion depth for indenting output
# @yieldreturn [String] additional string appended to `message`.
- def debug(*args)
+ def debug(*args, &block)
return unless @options[:logger]
options = args.last.is_a?(Hash) ? args.pop : {}
lineno = options[:lineno] || (scanner.lineno if scanner)
level = options.fetch(:level, 0)
-
depth = options[:depth] || self.depth
- args << yield if block_given?
- @options[:logger].add(level, "[#{lineno}]" + (" " * depth) + args.join(" "))
+
+ if self.respond_to?(:log_debug)
+ level = [:debug, :info, :warn, :error, :fatal][level]
+ log_debug(*args, **options.merge(level: level, lineno: lineno, depth: depth), &block)
+ elsif @options[:logger].respond_to?(:add)
+ args << yield if block_given?
+ @options[:logger].add(level, "[#{lineno}]" + (" " * depth) + args.join(" "))
+ elsif @options[:logger].respond_to?(:<<)
+ args << yield if block_given?
+ @options[:logger] << "[#{lineno}]" + (" " * depth) + args.join(" ")
+ end
end
# Start for production
# Adds data avoiable during the processing of the production
+ #
+ # @return [Hash] composed of production options. Currently only `as_hash` is supported.
+ # @see ClassMethods#start_production
def onStart(prod)
handler = self.class.start_handlers[prod]
@productions << prod
debug("#{prod}(:start)", "",
lineno: (scanner.lineno if scanner),
@@ -365,9 +383,10 @@
elsif self.class.production_handlers[prod]
# Make sure we push as many was we pop, even if there is no
# explicit start handler
@prod_data << {}
end
+ return self.class.start_options.fetch(prod, {}) # any options on this production
end
# Finish of production
#
# @param [Object] result parse result