ruby-ll 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.yardopts +13 -0
- data/LICENSE +19 -0
- data/README.md +380 -0
- data/bin/ruby-ll +5 -0
- data/doc/DCO.md +25 -0
- data/doc/changelog.md +8 -0
- data/doc/css/common.css +77 -0
- data/ext/c/driver.c +258 -0
- data/ext/c/driver.h +28 -0
- data/ext/c/driver_config.c +209 -0
- data/ext/c/driver_config.h +53 -0
- data/ext/c/extconf.rb +13 -0
- data/ext/c/khash.h +619 -0
- data/ext/c/kvec.h +90 -0
- data/ext/c/libll.c +7 -0
- data/ext/c/libll.h +9 -0
- data/ext/c/macros.h +6 -0
- data/ext/java/Libll.java +12 -0
- data/ext/java/org/libll/Driver.java +247 -0
- data/ext/java/org/libll/DriverConfig.java +193 -0
- data/lib/ll.rb +26 -0
- data/lib/ll/ast/node.rb +13 -0
- data/lib/ll/branch.rb +57 -0
- data/lib/ll/cli.rb +118 -0
- data/lib/ll/code_generator.rb +32 -0
- data/lib/ll/compiled_configuration.rb +35 -0
- data/lib/ll/compiled_grammar.rb +167 -0
- data/lib/ll/configuration_compiler.rb +204 -0
- data/lib/ll/driver.rb +46 -0
- data/lib/ll/driver_config.rb +36 -0
- data/lib/ll/driver_template.erb +51 -0
- data/lib/ll/epsilon.rb +23 -0
- data/lib/ll/erb_context.rb +23 -0
- data/lib/ll/grammar_compiler.rb +359 -0
- data/lib/ll/lexer.rb +582 -0
- data/lib/ll/message.rb +102 -0
- data/lib/ll/parser.rb +280 -0
- data/lib/ll/parser_error.rb +8 -0
- data/lib/ll/rule.rb +53 -0
- data/lib/ll/setup.rb +11 -0
- data/lib/ll/source_line.rb +46 -0
- data/lib/ll/terminal.rb +29 -0
- data/lib/ll/token.rb +30 -0
- data/lib/ll/version.rb +3 -0
- data/ruby-ll.gemspec +47 -0
- metadata +217 -0
    
        data/lib/ll.rb
    ADDED
    
    | @@ -0,0 +1,26 @@ | |
| 1 | 
            +
            require 'pathname'
         | 
| 2 | 
            +
            require 'erb'
         | 
| 3 | 
            +
            require 'set'
         | 
| 4 | 
            +
            require 'optparse'
         | 
| 5 | 
            +
             | 
| 6 | 
            +
            require 'ast'
         | 
| 7 | 
            +
            require 'ansi/code'
         | 
| 8 | 
            +
             | 
| 9 | 
            +
            require_relative 'll/setup'
         | 
| 10 | 
            +
            require_relative 'll/source_line'
         | 
| 11 | 
            +
            require_relative 'll/lexer'
         | 
| 12 | 
            +
            require_relative 'll/token'
         | 
| 13 | 
            +
            require_relative 'll/parser'
         | 
| 14 | 
            +
            require_relative 'll/grammar_compiler'
         | 
| 15 | 
            +
            require_relative 'll/code_generator'
         | 
| 16 | 
            +
            require_relative 'll/compiled_grammar'
         | 
| 17 | 
            +
            require_relative 'll/rule'
         | 
| 18 | 
            +
            require_relative 'll/branch'
         | 
| 19 | 
            +
            require_relative 'll/terminal'
         | 
| 20 | 
            +
            require_relative 'll/epsilon'
         | 
| 21 | 
            +
            require_relative 'll/message'
         | 
| 22 | 
            +
            require_relative 'll/ast/node'
         | 
| 23 | 
            +
            require_relative 'll/erb_context'
         | 
| 24 | 
            +
            require_relative 'll/configuration_compiler'
         | 
| 25 | 
            +
            require_relative 'll/compiled_configuration'
         | 
| 26 | 
            +
            require_relative 'll/cli'
         | 
    
        data/lib/ll/ast/node.rb
    ADDED
    
    
    
        data/lib/ll/branch.rb
    ADDED
    
    | @@ -0,0 +1,57 @@ | |
| 1 | 
            +
            module LL
         | 
| 2 | 
            +
              ##
         | 
| 3 | 
            +
              # The Branch class contains information of a single rule branch such as the
         | 
| 4 | 
            +
              # steps and the associated callback code.
         | 
| 5 | 
            +
              #
         | 
| 6 | 
            +
              class Branch
         | 
| 7 | 
            +
                attr_reader :steps, :source_line, :ruby_code
         | 
| 8 | 
            +
             | 
| 9 | 
            +
                ##
         | 
| 10 | 
            +
                # @param [Array] steps
         | 
| 11 | 
            +
                # @param [LL::SourceLine] source_line
         | 
| 12 | 
            +
                # @param [String] ruby_code
         | 
| 13 | 
            +
                #
         | 
| 14 | 
            +
                def initialize(steps, source_line, ruby_code = nil)
         | 
| 15 | 
            +
                  @steps       = steps
         | 
| 16 | 
            +
                  @source_line = source_line
         | 
| 17 | 
            +
                  @ruby_code   = ruby_code
         | 
| 18 | 
            +
                end
         | 
| 19 | 
            +
             | 
| 20 | 
            +
                ##
         | 
| 21 | 
            +
                # Returns the FIRST() set of this branch.
         | 
| 22 | 
            +
                #
         | 
| 23 | 
            +
                # @return [Array<LL::Terminal>]
         | 
| 24 | 
            +
                #
         | 
| 25 | 
            +
                def first_set
         | 
| 26 | 
            +
                  first = steps[0]
         | 
| 27 | 
            +
             | 
| 28 | 
            +
                  return first.is_a?(Rule) ? first.first_set : [first]
         | 
| 29 | 
            +
                end
         | 
| 30 | 
            +
             | 
| 31 | 
            +
                ##
         | 
| 32 | 
            +
                # Returns the FOLLOW() set of this branch.
         | 
| 33 | 
            +
                #
         | 
| 34 | 
            +
                # @return [Array<LL::Terminal>]
         | 
| 35 | 
            +
                #
         | 
| 36 | 
            +
                def follow_set
         | 
| 37 | 
            +
                  follow = steps[1]
         | 
| 38 | 
            +
             | 
| 39 | 
            +
                  if follow.is_a?(Rule)
         | 
| 40 | 
            +
                    set = follow.first_set
         | 
| 41 | 
            +
                  elsif follow
         | 
| 42 | 
            +
                    set = [follow]
         | 
| 43 | 
            +
                  else
         | 
| 44 | 
            +
                    set = []
         | 
| 45 | 
            +
                  end
         | 
| 46 | 
            +
             | 
| 47 | 
            +
                  return set
         | 
| 48 | 
            +
                end
         | 
| 49 | 
            +
             | 
| 50 | 
            +
                ##
         | 
| 51 | 
            +
                # @return [String]
         | 
| 52 | 
            +
                #
         | 
| 53 | 
            +
                def inspect
         | 
| 54 | 
            +
                  return "Branch(steps: #{steps.inspect}, ruby_code: #{ruby_code.inspect})"
         | 
| 55 | 
            +
                end
         | 
| 56 | 
            +
              end # Branch
         | 
| 57 | 
            +
            end # LL
         | 
    
        data/lib/ll/cli.rb
    ADDED
    
    | @@ -0,0 +1,118 @@ | |
| 1 | 
            +
            module LL
         | 
| 2 | 
            +
              ##
         | 
| 3 | 
            +
              # CLI that can be used to generate ruby-ll parsers from a grammar file.
         | 
| 4 | 
            +
              #
         | 
| 5 | 
            +
              class CLI
         | 
| 6 | 
            +
                ##
         | 
| 7 | 
            +
                # @param [Array] argv
         | 
| 8 | 
            +
                #
         | 
| 9 | 
            +
                def run(argv = ARGV)
         | 
| 10 | 
            +
                  options, leftovers = parse(argv)
         | 
| 11 | 
            +
             | 
| 12 | 
            +
                  if leftovers.empty?
         | 
| 13 | 
            +
                    abort <<-EOF.strip
         | 
| 14 | 
            +
            Error: you must specify a grammar input file'
         | 
| 15 | 
            +
             | 
| 16 | 
            +
            #{parser}
         | 
| 17 | 
            +
            EOF
         | 
| 18 | 
            +
                  end
         | 
| 19 | 
            +
             | 
| 20 | 
            +
                  input = File.expand_path(leftovers[0])
         | 
| 21 | 
            +
             | 
| 22 | 
            +
                  unless options[:output]
         | 
| 23 | 
            +
                    options[:output] = output_from_input(input)
         | 
| 24 | 
            +
                  end
         | 
| 25 | 
            +
             | 
| 26 | 
            +
                  generate(input, options)
         | 
| 27 | 
            +
                end
         | 
| 28 | 
            +
             | 
| 29 | 
            +
                ##
         | 
| 30 | 
            +
                # @param [String] input
         | 
| 31 | 
            +
                # @return [String]
         | 
| 32 | 
            +
                #
         | 
| 33 | 
            +
                def output_from_input(input)
         | 
| 34 | 
            +
                  input_ext = File.extname(input)
         | 
| 35 | 
            +
             | 
| 36 | 
            +
                  return input.gsub(/#{Regexp.compile(input_ext)}$/, '.rb')
         | 
| 37 | 
            +
                end
         | 
| 38 | 
            +
             | 
| 39 | 
            +
                ##
         | 
| 40 | 
            +
                # @param [String] input
         | 
| 41 | 
            +
                # @param [Hash] options
         | 
| 42 | 
            +
                #
         | 
| 43 | 
            +
                def generate(input, options)
         | 
| 44 | 
            +
                  raw_grammar    = File.read(input)
         | 
| 45 | 
            +
                  parser         = Parser.new(raw_grammar, input)
         | 
| 46 | 
            +
                  gcompiler      = GrammarCompiler.new
         | 
| 47 | 
            +
                  codegen        = CodeGenerator.new
         | 
| 48 | 
            +
                  configcompiler = ConfigurationCompiler.new
         | 
| 49 | 
            +
             | 
| 50 | 
            +
                  ast      = parser.parse
         | 
| 51 | 
            +
                  cgrammar = gcompiler.compile(ast)
         | 
| 52 | 
            +
             | 
| 53 | 
            +
                  cgrammar.display_messages
         | 
| 54 | 
            +
             | 
| 55 | 
            +
                  if cgrammar.valid?
         | 
| 56 | 
            +
                    config = configcompiler.generate(cgrammar)
         | 
| 57 | 
            +
                    output = codegen.generate(config, options[:requires])
         | 
| 58 | 
            +
             | 
| 59 | 
            +
                    File.open(options[:output], 'w') do |file|
         | 
| 60 | 
            +
                      file.write(output)
         | 
| 61 | 
            +
                    end
         | 
| 62 | 
            +
                  else
         | 
| 63 | 
            +
                    exit 1
         | 
| 64 | 
            +
                  end
         | 
| 65 | 
            +
                end
         | 
| 66 | 
            +
             | 
| 67 | 
            +
                ##
         | 
| 68 | 
            +
                # @param [Array] argv
         | 
| 69 | 
            +
                # @return [Array]
         | 
| 70 | 
            +
                #
         | 
| 71 | 
            +
                def parse(argv)
         | 
| 72 | 
            +
                  options = {
         | 
| 73 | 
            +
                    :requires => true,
         | 
| 74 | 
            +
                    :output   => nil
         | 
| 75 | 
            +
                  }
         | 
| 76 | 
            +
             | 
| 77 | 
            +
                  parser = OptionParser.new do |opt|
         | 
| 78 | 
            +
                    opt.summary_indent = '  '
         | 
| 79 | 
            +
             | 
| 80 | 
            +
                    opt.banner = <<-EOF.strip
         | 
| 81 | 
            +
            Usage: ruby-ll [INPUT-GRAMMAR] [OPTIONS]
         | 
| 82 | 
            +
             | 
| 83 | 
            +
            About:
         | 
| 84 | 
            +
             | 
| 85 | 
            +
              Generates a Ruby LL(1) parser from a ruby-ll compatible grammar file.
         | 
| 86 | 
            +
             | 
| 87 | 
            +
            Examples:
         | 
| 88 | 
            +
             | 
| 89 | 
            +
              ruby-ll lib/ll/parser.rll                   # output goes to lib/ll/parser.rl
         | 
| 90 | 
            +
              ruby-ll lib/ll/parser.rll -o /tmp/parser.rb # output goes to /tmp/parser.rb
         | 
| 91 | 
            +
                    EOF
         | 
| 92 | 
            +
             | 
| 93 | 
            +
                    opt.separator "\nOptions:\n\n"
         | 
| 94 | 
            +
             | 
| 95 | 
            +
                    opt.on '-h', '--help', 'Shows this help message' do
         | 
| 96 | 
            +
                      abort parser.to_s
         | 
| 97 | 
            +
                    end
         | 
| 98 | 
            +
             | 
| 99 | 
            +
                    opt.on '--no-requires', 'Disables adding of require calls' do
         | 
| 100 | 
            +
                      options[:requires] = false
         | 
| 101 | 
            +
                    end
         | 
| 102 | 
            +
             | 
| 103 | 
            +
                    opt.on '-o [PATH]', '--output [PATH]', 'Writes output to PATH' do |val|
         | 
| 104 | 
            +
                      options[:output] = val
         | 
| 105 | 
            +
                    end
         | 
| 106 | 
            +
             | 
| 107 | 
            +
                    opt.on '-v', '--version', 'Shows the current version' do
         | 
| 108 | 
            +
                      puts "ruby-ll #{VERSION} on #{RUBY_DESCRIPTION}"
         | 
| 109 | 
            +
                      exit
         | 
| 110 | 
            +
                    end
         | 
| 111 | 
            +
                  end
         | 
| 112 | 
            +
             | 
| 113 | 
            +
                  leftovers = parser.parse(argv)
         | 
| 114 | 
            +
             | 
| 115 | 
            +
                  return options, leftovers
         | 
| 116 | 
            +
                end
         | 
| 117 | 
            +
              end # CLI
         | 
| 118 | 
            +
            end # LL
         | 
| @@ -0,0 +1,32 @@ | |
| 1 | 
            +
            module LL
         | 
| 2 | 
            +
              ##
         | 
| 3 | 
            +
              # The CodeGenerator class takes a {LL::CompiledConfiguration} instance and
         | 
| 4 | 
            +
              # turns it into a block of Ruby source code that can be used as an actual
         | 
| 5 | 
            +
              # LL(1) parser.
         | 
| 6 | 
            +
              #
         | 
| 7 | 
            +
              class CodeGenerator
         | 
| 8 | 
            +
                ##
         | 
| 9 | 
            +
                # The ERB template to use for code generation.
         | 
| 10 | 
            +
                #
         | 
| 11 | 
            +
                # @return [String]
         | 
| 12 | 
            +
                #
         | 
| 13 | 
            +
                TEMPLATE = File.expand_path('../driver_template.erb', __FILE__)
         | 
| 14 | 
            +
             | 
| 15 | 
            +
                ##
         | 
| 16 | 
            +
                # @param [LL::CompiledConfiguration] config
         | 
| 17 | 
            +
                # @param [TrueClass|FalseClass] add_requires
         | 
| 18 | 
            +
                # @return [String]
         | 
| 19 | 
            +
                #
         | 
| 20 | 
            +
                def generate(config, add_requires = true)
         | 
| 21 | 
            +
                  context = ERBContext.new(
         | 
| 22 | 
            +
                    :config       => config,
         | 
| 23 | 
            +
                    :add_requires => add_requires
         | 
| 24 | 
            +
                  )
         | 
| 25 | 
            +
             | 
| 26 | 
            +
                  template = File.read(TEMPLATE)
         | 
| 27 | 
            +
                  erb      = ERB.new(template, nil, '-').result(context.get_binding)
         | 
| 28 | 
            +
             | 
| 29 | 
            +
                  return erb
         | 
| 30 | 
            +
                end
         | 
| 31 | 
            +
              end # CodeGenerator
         | 
| 32 | 
            +
            end # LL
         | 
| @@ -0,0 +1,35 @@ | |
| 1 | 
            +
            module LL
         | 
| 2 | 
            +
              ##
         | 
| 3 | 
            +
              # Class for storing the compiled state/lookup/action tables and the likes.
         | 
| 4 | 
            +
              #
         | 
| 5 | 
            +
              class CompiledConfiguration
         | 
| 6 | 
            +
                attr_reader :name, :namespace, :inner, :header, :terminals, :rules, :table,
         | 
| 7 | 
            +
                  :actions, :action_bodies
         | 
| 8 | 
            +
             | 
| 9 | 
            +
                ##
         | 
| 10 | 
            +
                # @param [Hash] options
         | 
| 11 | 
            +
                #
         | 
| 12 | 
            +
                # @option options [String] :name
         | 
| 13 | 
            +
                # @option options [Array] :namespace
         | 
| 14 | 
            +
                # @option options [String] :inner
         | 
| 15 | 
            +
                # @option options [String] :header
         | 
| 16 | 
            +
                # @option options [Array] :terminals
         | 
| 17 | 
            +
                # @option options [Array] :rules
         | 
| 18 | 
            +
                # @option options [Array] :table
         | 
| 19 | 
            +
                # @option options [Array] :actions
         | 
| 20 | 
            +
                # @option options [Hash] :action_bodies
         | 
| 21 | 
            +
                #
         | 
| 22 | 
            +
                def initialize(options = {})
         | 
| 23 | 
            +
                  options.each do |key, value|
         | 
| 24 | 
            +
                    instance_variable_set("@#{key}", value) if respond_to?(key)
         | 
| 25 | 
            +
                  end
         | 
| 26 | 
            +
             | 
| 27 | 
            +
                  @namespace     ||= []
         | 
| 28 | 
            +
                  @terminals     ||= []
         | 
| 29 | 
            +
                  @rules         ||= []
         | 
| 30 | 
            +
                  @table         ||= []
         | 
| 31 | 
            +
                  @actions       ||= []
         | 
| 32 | 
            +
                  @action_bodies ||= {}
         | 
| 33 | 
            +
                end
         | 
| 34 | 
            +
              end # CompiledConfiguration
         | 
| 35 | 
            +
            end # LL
         | 
| @@ -0,0 +1,167 @@ | |
| 1 | 
            +
            module LL
         | 
| 2 | 
            +
              ##
         | 
| 3 | 
            +
              # The CompiledGrammar class contains compilation results such as the parser
         | 
| 4 | 
            +
              # name, the rules of the grammar, the terminals, etc.
         | 
| 5 | 
            +
              #
         | 
| 6 | 
            +
              class CompiledGrammar
         | 
| 7 | 
            +
                attr_accessor :name, :inner, :header
         | 
| 8 | 
            +
             | 
| 9 | 
            +
                attr_reader :warnings, :errors
         | 
| 10 | 
            +
             | 
| 11 | 
            +
                def initialize
         | 
| 12 | 
            +
                  @warnings  = []
         | 
| 13 | 
            +
                  @errors    = []
         | 
| 14 | 
            +
                  @terminals = {}
         | 
| 15 | 
            +
                  @rules     = {}
         | 
| 16 | 
            +
                  @inner     = nil
         | 
| 17 | 
            +
                  @header    = nil
         | 
| 18 | 
            +
                end
         | 
| 19 | 
            +
             | 
| 20 | 
            +
                ##
         | 
| 21 | 
            +
                # @param [String] message
         | 
| 22 | 
            +
                # @param [LL::SourceLine] source_line
         | 
| 23 | 
            +
                #
         | 
| 24 | 
            +
                def add_error(message, source_line)
         | 
| 25 | 
            +
                  @errors << Message.new(:error, message, source_line)
         | 
| 26 | 
            +
                end
         | 
| 27 | 
            +
             | 
| 28 | 
            +
                ##
         | 
| 29 | 
            +
                # @param [String] message
         | 
| 30 | 
            +
                # @param [LL::SourceLine] source_line
         | 
| 31 | 
            +
                #
         | 
| 32 | 
            +
                def add_warning(message, source_line)
         | 
| 33 | 
            +
                  @warnings << Message.new(:warning, message, source_line)
         | 
| 34 | 
            +
                end
         | 
| 35 | 
            +
             | 
| 36 | 
            +
                ##
         | 
| 37 | 
            +
                # @param [String] name
         | 
| 38 | 
            +
                # @return [TrueClass|FalseClass]
         | 
| 39 | 
            +
                #
         | 
| 40 | 
            +
                def has_terminal?(name)
         | 
| 41 | 
            +
                  return @terminals.key?(name)
         | 
| 42 | 
            +
                end
         | 
| 43 | 
            +
             | 
| 44 | 
            +
                ##
         | 
| 45 | 
            +
                # @param [String] name
         | 
| 46 | 
            +
                # @param [LL::SourceLine] source_line
         | 
| 47 | 
            +
                # @return [LL::Terminal]
         | 
| 48 | 
            +
                #
         | 
| 49 | 
            +
                def add_terminal(name, source_line)
         | 
| 50 | 
            +
                  return @terminals[name] = Terminal.new(name, source_line)
         | 
| 51 | 
            +
                end
         | 
| 52 | 
            +
             | 
| 53 | 
            +
                ##
         | 
| 54 | 
            +
                # Returns true if a rule for the given name has already been assigned.
         | 
| 55 | 
            +
                #
         | 
| 56 | 
            +
                # @param [String] name
         | 
| 57 | 
            +
                # @return [TrueClass|FalseClass]
         | 
| 58 | 
            +
                #
         | 
| 59 | 
            +
                def has_rule?(name)
         | 
| 60 | 
            +
                  return @rules.key?(name)
         | 
| 61 | 
            +
                end
         | 
| 62 | 
            +
             | 
| 63 | 
            +
                ##
         | 
| 64 | 
            +
                # Returns true if a rule already exists for a given name _and_ has at least
         | 
| 65 | 
            +
                # 1 branch.
         | 
| 66 | 
            +
                #
         | 
| 67 | 
            +
                # @see [#has_rule?]
         | 
| 68 | 
            +
                #
         | 
| 69 | 
            +
                def has_rule_with_branches?(name)
         | 
| 70 | 
            +
                  return has_rule?(name) && !@rules[name].branches.empty?
         | 
| 71 | 
            +
                end
         | 
| 72 | 
            +
             | 
| 73 | 
            +
                ##
         | 
| 74 | 
            +
                # @param [LL::Rule] rule
         | 
| 75 | 
            +
                # @return [LL::Rule]
         | 
| 76 | 
            +
                #
         | 
| 77 | 
            +
                def add_rule(rule)
         | 
| 78 | 
            +
                  return @rules[rule.name] = rule
         | 
| 79 | 
            +
                end
         | 
| 80 | 
            +
             | 
| 81 | 
            +
                ##
         | 
| 82 | 
            +
                # @param [String] name
         | 
| 83 | 
            +
                # @return [LL::Rule]
         | 
| 84 | 
            +
                #
         | 
| 85 | 
            +
                def lookup_rule(name)
         | 
| 86 | 
            +
                  return @rules[name]
         | 
| 87 | 
            +
                end
         | 
| 88 | 
            +
             | 
| 89 | 
            +
                ##
         | 
| 90 | 
            +
                # Looks up an identifier from the list of terminals and/or rules. Rules take
         | 
| 91 | 
            +
                # precedence over terminals.
         | 
| 92 | 
            +
                #
         | 
| 93 | 
            +
                # If no rule/terminal could be found nil is returned instead.
         | 
| 94 | 
            +
                #
         | 
| 95 | 
            +
                # @param [String] name
         | 
| 96 | 
            +
                # @return [LL::Rule|LL::Terminal|NilClass]
         | 
| 97 | 
            +
                #
         | 
| 98 | 
            +
                def lookup_identifier(name)
         | 
| 99 | 
            +
                  if has_rule?(name)
         | 
| 100 | 
            +
                    ident = lookup_rule(name)
         | 
| 101 | 
            +
                  elsif has_terminal?(name)
         | 
| 102 | 
            +
                    ident = @terminals[name]
         | 
| 103 | 
            +
                  else
         | 
| 104 | 
            +
                    ident = nil
         | 
| 105 | 
            +
                  end
         | 
| 106 | 
            +
             | 
| 107 | 
            +
                  return ident
         | 
| 108 | 
            +
                end
         | 
| 109 | 
            +
             | 
| 110 | 
            +
                ##
         | 
| 111 | 
            +
                # @return [Array]
         | 
| 112 | 
            +
                #
         | 
| 113 | 
            +
                def rules
         | 
| 114 | 
            +
                  return @rules.values
         | 
| 115 | 
            +
                end
         | 
| 116 | 
            +
             | 
| 117 | 
            +
                ##
         | 
| 118 | 
            +
                # @return [Hash]
         | 
| 119 | 
            +
                #
         | 
| 120 | 
            +
                def rule_indices
         | 
| 121 | 
            +
                  return rules.each_with_index.each_with_object({}) do |(rule, idx), h|
         | 
| 122 | 
            +
                    h[rule] = idx
         | 
| 123 | 
            +
                  end
         | 
| 124 | 
            +
                end
         | 
| 125 | 
            +
             | 
| 126 | 
            +
                ##
         | 
| 127 | 
            +
                # @return [Array]
         | 
| 128 | 
            +
                #
         | 
| 129 | 
            +
                def terminals
         | 
| 130 | 
            +
                  return @terminals.values
         | 
| 131 | 
            +
                end
         | 
| 132 | 
            +
             | 
| 133 | 
            +
                ##
         | 
| 134 | 
            +
                # @return [Hash]
         | 
| 135 | 
            +
                #
         | 
| 136 | 
            +
                def terminal_indices
         | 
| 137 | 
            +
                  return terminals.each_with_index.each_with_object({}) do |(term, idx), h|
         | 
| 138 | 
            +
                    h[term] = idx
         | 
| 139 | 
            +
                  end
         | 
| 140 | 
            +
                end
         | 
| 141 | 
            +
             | 
| 142 | 
            +
                ##
         | 
| 143 | 
            +
                # @return [TrueClass|FalseClass]
         | 
| 144 | 
            +
                #
         | 
| 145 | 
            +
                def valid?
         | 
| 146 | 
            +
                  return @errors.empty?
         | 
| 147 | 
            +
                end
         | 
| 148 | 
            +
             | 
| 149 | 
            +
                ##
         | 
| 150 | 
            +
                # Displays all warnings and errors.
         | 
| 151 | 
            +
                #
         | 
| 152 | 
            +
                def display_messages
         | 
| 153 | 
            +
                  [:errors, :warnings].each do |type|
         | 
| 154 | 
            +
                    send(type).each do |msg|
         | 
| 155 | 
            +
                      output.puts(msg.to_s)
         | 
| 156 | 
            +
                    end
         | 
| 157 | 
            +
                  end
         | 
| 158 | 
            +
                end
         | 
| 159 | 
            +
             | 
| 160 | 
            +
                ##
         | 
| 161 | 
            +
                # @return [IO]
         | 
| 162 | 
            +
                #
         | 
| 163 | 
            +
                def output
         | 
| 164 | 
            +
                  return STDERR
         | 
| 165 | 
            +
                end
         | 
| 166 | 
            +
              end # CompiledGrammar
         | 
| 167 | 
            +
            end # LL
         |