lib/ebnf/peg/parser.rb in ebnf-2.1.0 vs lib/ebnf/peg/parser.rb in ebnf-2.1.1

- old
+ new

@@ -73,12 +73,10 @@ # If unset, the terminal rule is used for matching. # @param [Hash] options # @option options [Hash{String => String}] :map ({}) # A mapping from terminals, in lower-case form, to # their canonical value - # @option options [Boolean] :unescape - # Cause strings and codepoints to be unescaped. # @yield [value, prod] # @yieldparam [String] value # The scanned terminal value. # @yieldparam [Symbol] prod # A symbol indicating the production which referenced this terminal @@ -267,11 +265,12 @@ # # @param [String] node Relevant location associated with message # @param [String] message Error string # @param [Hash{Symbol => Object}] options # @option options [URI, #to_s] :production - # @option options [Token] :token + # @option options [Boolean] :raise abort furhter processing + # @option options [Array] :backtrace state where error occured # @see #debug def error(node, message, **options) lineno = options[:lineno] || (scanner.lineno if scanner) m = "ERROR " m += "[line: #{lineno}] " if lineno @@ -280,11 +279,15 @@ m += ", production = #{options[:production].inspect}" if options[:production] @error_log << m unless @recovering @recovering = true debug(node, m, level: 3, **options) if options[:raise] || @options[:validate] - raise Error.new(m, lineno: lineno, rest: options[:rest], production: options[:production]) + raise Error.new(m, + lineno: lineno, + rest: options[:rest], + production: options[:production], + backtrace: options[:backtrace]) end end ## # Warning information, used as level `2` logger messages. @@ -363,29 +366,31 @@ def onStart(prod) handler = self.class.start_handlers[prod] @productions << prod debug("#{prod}(:start)", "", lineno: (scanner.lineno if scanner), - pos: (scanner.pos if scanner), - depth: (depth + 1)) {"#{prod}, pos: #{scanner ? scanner.pos : '?'}, rest: #{scanner ? scanner.rest[0..20].inspect : '?'}"} + pos: (scanner.pos if scanner) + ) do + "#{prod}, pos: #{scanner ? scanner.pos : '?'}, rest: #{scanner ? scanner.rest[0..20].inspect : '?'}" + end if handler # Create a new production data element, potentially allowing handler # to customize before pushing on the @prod_data stack - data = {} + data = {_production: prod} begin self.class.eval_with_binding(self) { handler.call(data, @parse_callback) } rescue ArgumentError, Error => e - error("start", "#{e.class}: #{e.message}", production: prod) + error("start", "#{e.class}: #{e.message}", production: prod, backtrace: e.backtrace) @recovering = false end @prod_data << data 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 << {} + @prod_data << {_production: prod} end return self.class.start_options.fetch(prod, {}) # any options on this production end # Finish of production @@ -395,25 +400,27 @@ def onFinish(result) #puts "prod_data(f): " + @prod_data.inspect prod = @productions.last handler, clear_packrat = self.class.production_handlers[prod] data = @prod_data.pop if handler || self.class.start_handlers[prod] + error("finish", + "prod_data production mismatch: expected #{prod.inspect}, got #{data[:_production].inspect}", + production: prod, prod_data: @prod_data) if data && prod != data[:_production] if handler && !@recovering && result != :unmatched # Pop production data element from stack, potentially allowing handler to use it result = begin self.class.eval_with_binding(self) { handler.call(result, data, @parse_callback) } rescue ArgumentError, Error => e - error("finish", "#{e.class}: #{e.message}", production: prod) + error("finish", "#{e.class}: #{e.message}", production: prod, backtrace: e.backtrace) @recovering = false end end - progress("#{prod}(:finish)", "", - depth: (depth + 1), - lineno: (scanner.lineno if scanner), - level: result == :unmatched ? 0 : 1) do + debug("#{prod}(:finish)", "", + lineno: (scanner.lineno if scanner), + level: result == :unmatched ? 0 : 1) do "#{result.inspect}@(#{scanner ? scanner.pos : '?'}), rest: #{scanner ? scanner.rest[0..20].inspect : '?'}" end self.clear_packrat if clear_packrat @productions.pop result @@ -431,15 +438,15 @@ value = begin self.class.eval_with_binding(self) { handler.call(value, parentProd, @parse_callback) } rescue ArgumentError, Error => e - error("terminal", "#{e.class}: #{e.message}", value: value, production: prod) + error("terminal", "#{e.class}: #{e.message}", value: value, production: prod, backtrace: e.backtrace) @recovering = false end end progress("#{prod}(:terminal)", "", - depth: (depth + 2), + depth: (depth + 1), lineno: (scanner.lineno if scanner), level: value == :unmatched ? 0 : 1) do "#{value.inspect}@(#{scanner ? scanner.pos : '?'})" end value