lib/ebnf/base.rb in ebnf-1.1.2 vs lib/ebnf/base.rb in ebnf-1.1.3

- old
+ new

@@ -115,23 +115,23 @@ # Parse the string or file input generating an abstract syntax tree # in S-Expressions (similar to SPARQL SSE) # # @param [#read, #to_s] input # @param [Hash{Symbol => Object}] options - # @option options [Boolean, Array] :debug - # Output debug information to an array or STDOUT. - # @option options [Symbol] :format (:ebnf) + # @param [Symbol] :format (:ebnf) # Format of input, one of :ebnf, or :sxp - def initialize(input, options = {}) - @options = {format: :ebnf}.merge(options) + # @option options [Boolean, Array] :debug + # Output debug information to an array or $stdout. + def initialize(input, format: :ebnf, **options) + @options = options.dup @lineno, @depth, @errors = 1, 0, [] terminal = false @ast = [] input = input.respond_to?(:read) ? input.read : input.to_s - case @options[:format] + case format when :sxp require 'sxp' unless defined?(SXP) @ast = SXP::Reader::Basic.read(input).map {|e| Rule.from_sxp(e)} when :ebnf scanner = StringScanner.new(input) @@ -142,11 +142,11 @@ when /^@terminals/ # Switch mode to parsing terminals terminal = true when /^@pass\s*(.*)$/m expr = expression($1).first - rule = Rule.new(nil, nil, expr, kind: :pass) + rule = Rule.new(nil, nil, expr, kind: :pass, ebnf: self) rule.orig = expr @ast << rule else rule = depth {ruleParts(r)} @@ -154,11 +154,11 @@ rule.orig = r @ast << rule end end else - raise "unknown input format #{options[:format].inspect}" + raise "unknown input format #{format.inspect}" end end # Iterate over each rule or terminal, except empty # @param [:termina, :rule] kind @@ -192,31 +192,31 @@ ## # Output Ruby parser files # # @param [IO, StringIO] output - # @param [Hash{Symbol => Object}] options - # @option options [String] :grammarFile - def to_ruby(output = STDOUT, options = {}) - unless output == STDOUT + # @param [String] :grammarFile + # @param [String] :mod_name ('Branch') + def to_ruby(output = $stdout, grammarFile: nil, mod_name: 'Branch') + unless output == $stdout output.puts "# This file is automatically generated by #{__FILE__}" - output.puts "# BRANCH derived from #{options[:grammarFile]}" if options[:grammarFile] + output.puts "# BRANCH derived from #{grammarFile}" if grammarFile unless self.errors.empty? output.puts "# Note, tables completed with errors, may need to be resolved manually:" #output.puts "# #{pp.conflicts.map{|c| c.join("\n# ")}.join("\n# ")}" end - output.puts "module #{options.fetch(:mod_name, 'Branch')}" + output.puts "module #{mod_name}" output.puts " START = #{self.start.inspect}" output.puts end self.outputTable(output, 'BRANCH', self.branch, 1) self.outputTable(output, 'TERMINALS', self.terminals, 1) self.outputTable(output, 'FIRST', self.first, 1) self.outputTable(output, 'FOLLOW', self.follow, 1) self.outputTable(output, 'CLEANUP', self.cleanup, 1) self.outputTable(output, 'PASS', [self.pass], 1) if self.pass - unless output == STDOUT + unless output == $stdout output.puts "end" end end def dup @@ -236,23 +236,23 @@ ## # Write out syntax tree as Turtle # @param [String] prefix for language # @param [String] ns URI for language # @return [String] - def to_ttl(prefix, ns) + def to_ttl(prefix = nil, ns = "http://example.org/") unless ast.empty? [ "@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>.", "@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#>.", - "@prefix #{prefix}: <#{ns}>.", + ("@prefix #{prefix}: <#{ns}>." if prefix), "@prefix : <#{ns}>.", "@prefix re: <http://www.w3.org/2000/10/swap/grammar/regex#>.", "@prefix g: <http://www.w3.org/2000/10/swap/grammar/ebnf#>.", "", ":language rdfs:isDefinedBy <>; g:start :#{ast.first.id}.", "", - ] + ].compact end.join("\n") + ast.sort.map(&:to_ttl).join("\n") end @@ -262,24 +262,22 @@ @depth -= 1 ret end # Progress output, less than debugging - def progress(*args) + def progress(*args, **options) return unless @options[:progress] || @options[:debug] - options = args.last.is_a?(Hash) ? args.pop : {} depth = options[:depth] || @depth args << yield if block_given? message = "#{args.join(': ')}" str = "[#{@lineno}]#{' ' * depth}#{message}" @options[:debug] << str if @options[:debug].is_a?(Array) $stderr.puts(str) if @options[:progress] || @options[:debug] == true end # Error output - def error(*args) - options = args.last.is_a?(Hash) ? args.pop : {} + def error(*args, **options) depth = options[:depth] || @depth args << yield if block_given? message = "#{args.join(': ')}" @errors << message str = "[#{@lineno}]#{' ' * depth}#{message}" @@ -296,12 +294,11 @@ # # @overload debug(message) # @param [String] message ("") # # @yieldreturn [String] added to message - def debug(*args) + def debug(*args, **options) return unless @options[:debug] - options = args.last.is_a?(Hash) ? args.pop : {} depth = options[:depth] || @depth args << yield if block_given? message = "#{args.join(': ')}" str = "[#{@lineno}]#{' ' * depth}#{message}" @options[:debug] << str if @options[:debug].is_a?(Array) \ No newline at end of file