class IDL::Engine

Public Class Methods

new(backend, options) click to toggle source
# File lib/ridl/runner.rb, line 87
def initialize(backend, options)
  @backend = backend ? Backend.load(backend) : Backend.null_be
  @initopts = options.merge({
    backend: @backend.name,
    macros: options[:macros].merge({
       __RIDL__: "#{RIDL_VERSION}",
       __RIDLBE__: @backend.name.to_s,
       __RIDLBE_VER__: @backend.version
    })
  })
  @optparser = init_optparser
  @inputstack = []
  @productionstack = ProductionStack.new
  @options = nil
end

Public Instance Methods

backend() click to toggle source
# File lib/ridl/runner.rb, line 103
def backend
  @backend
end
has_input?() click to toggle source
# File lib/ridl/runner.rb, line 125
def has_input?
  !@inputstack.empty?
end
has_production?(id) click to toggle source
# File lib/ridl/runner.rb, line 153
def has_production?(id)
  @productionstack.has?(id)
end
has_productions?() click to toggle source
# File lib/ridl/runner.rb, line 149
def has_productions?
  !@productionstack.empty?
end
options() click to toggle source
# File lib/ridl/runner.rb, line 107
def options
  @options || @initopts
end
parse(io, opts) click to toggle source
# File lib/ridl/runner.rb, line 270
def parse(io, opts)
  # parse IDL source
  _parser = ::IDL::Parser.new(opts)
  _parser.yydebug = opts[:debug]

  begin
    _parser.parse(io)
  rescue => e
    IDL.error(e.inspect)
    IDL.error(e.backtrace.join("\n")) unless e.is_a? IDL::ParseError
    return nil
  ensure
    io.close unless String === io || io == $stdin
  end
  _parser
end
peek_input() click to toggle source
# File lib/ridl/runner.rb, line 121
def peek_input
  @inputstack.first
end
peek_production() click to toggle source
# File lib/ridl/runner.rb, line 141
def peek_production
  @productionstack.peek
end
pop_input() click to toggle source
# File lib/ridl/runner.rb, line 117
def pop_input
  @inputstack.shift
end
pop_production() click to toggle source
# File lib/ridl/runner.rb, line 137
def pop_production
  @productionstack.pop
end
production(id) click to toggle source
# File lib/ridl/runner.rb, line 157
def production(id)
  @productionstack[id]
end
push_input(idlfile, opts) click to toggle source

Input management

# File lib/ridl/runner.rb, line 113
def push_input(idlfile, opts)
  @inputstack << [idlfile, opts]
end
push_production(id, producer) click to toggle source

Production management

# File lib/ridl/runner.rb, line 131
def push_production(id, producer)
  raise "Producer #{id} already queued" if @productionstack.has?(id)

  @productionstack.push(id, producer)
end
remove_production(id) click to toggle source
# File lib/ridl/runner.rb, line 145
def remove_production(id)
  @productionstack.remove(id)
end
run(argv, runopts = {}) click to toggle source
# File lib/ridl/runner.rb, line 171
def run(argv, runopts = {})

  # initialize options
  @options = @initopts.merge(runopts)

  # mark current (clean) state
  @options.mark

  # backup current engine (if any)
  cur_engine = Thread.current[:ridl_engine]
  # store currently running engine for current thread
  Thread.current[:ridl_engine] = self

  begin
    # parse arguments
    begin
      @optparser.parse!(argv)
    rescue ArgumentError => e
      IDL.error(e.inspect)
      IDL.error(e.backtrace.join("\n")) if IDL.verbose_level.positive?
      return false
    end

    if options[:preprocess]

      ## PREPROCESSING
      o = if options[:output].nil?
            $stdout
          else
            File.open(options[:output], 'w+')
          end
      options[:output] = o

      input_base = File.basename(argv.first)
      if input_base != argv.first
        options[:xincludepaths] << (File.dirname(argv.first) + '/')
      end

      return !parse("#include \"#{input_base}\"", options).nil?
    else
      ## collect input files from commandline
      collect_input(argv)

      ## CODE GENERATION
      while has_input?
        # get input from stack
        _idlfile, _opts = pop_input

        _fio = if IO === _idlfile || StringIO === _idlfile
                 _idlfile
               else
                 File.open(_idlfile, 'r')
               end
        raise 'cannot read from STDOUT' if $stdout == _fio

        # parse IDL source
        IDL.log(1, "RIDL - parsing #{IO === _idlfile ? 'from STDIN' : (StringIO === _idlfile ? 'from string' : _idlfile)}")

        unless _parser = parse(_fio, _opts)
          return false
        end

        # process parse result -> code generation
        IDL.log(2, 'RIDL - processing input')

        GenFile.transaction do
          begin

            backend.process_input(_parser, _opts)

            # handle productions
            while has_productions?
              IDL.log(2, "RIDL - running production #{peek_production}")

              # get next-in-line producer
              producer = pop_production

              # execute the producer
              producer.run(_parser)
            end

          rescue Backend::ProcessStop
            IDL.log(2, "RIDL - processing #{IO === _idlfile ? 'from STDIN' : (StringIO === _idlfile ? 'from string' : _idlfile)} stopped with \"#{$!.message}\"")

          rescue => e
            IDL.error(e)
            IDL.error(e.backtrace.join("\n")) unless e.is_a? IDL::ParseError
            return false
          end
        end
      end
    end
  ensure
    # restore previous state
    Thread.current[:ridl_engine] = cur_engine
  end
  true
end
verbose_level() click to toggle source

Verbosity control

# File lib/ridl/runner.rb, line 163
def verbose_level
  options[:verbose]
end
verbose_level=(l) click to toggle source
# File lib/ridl/runner.rb, line 167
def verbose_level=(l)
  options[:verbose] = l
end

Private Instance Methods

collect_input(argv) click to toggle source
# File lib/ridl/runner.rb, line 289
def collect_input(argv)
  ## collect input files from commandline
  argv.each do |_arg|
    _opts = options.dup

    _opts[:idlfile] = _arg
    if _opts[:no_input]
      # do not parse specified file (only used as template for output names)
      # instead push an empty StringIO object
      _arg = StringIO.new('')
    else
      if _opts[:search_incpath]
        _fname = _arg
        _fpath = if File.file?(_fname) && File.readable?(_fname)
                   _fname
                 else
                   _fp = _opts[:includepaths].find do |_p|
                     _f = _p + _fname
                     File.file?(_f) && File.readable?(_f)
                   end
                   _opts[:outputdir] = _fp unless _fp.nil? || !_opts[:outputdir].nil?
                   _fp += '/' + _fname unless _fp.nil?
                   _fp
                 end
        _arg = _fpath unless _fpath.nil?
      end
      _opts[:xincludepaths] << (File.dirname(_arg) + '/')
    end

    _opts[:outputdir] ||= '.'

    push_input(_arg, _opts)
  end

  ## if no IDL input file specified read from STDIN
  unless has_input?
    _opts = options.dup
    _opts[:outputdir] ||= '.'
    push_input($stdin, _opts)
  end
end
init_optparser() click to toggle source
# File lib/ridl/runner.rb, line 331
   def init_optparser
     script_name = File.basename($0, '.*')
     unless script_name =~ /ridlc/
       script_name = 'ruby ' + $0
     end

     # set up option parser with common options
     opts = OptionParser.new
     opts.banner = "Usage: #{script_name} [:backend] [options] [<idlfile> [<idlfile> ...]]\n\n" +
         "    backend\t\tSpecifies the IDL language mapping backend to use.\n" +
         "           \t\tDefault = :null\n\n" +
         "    Active language mapping = :#{backend.name}"
     opts.separator ''
     opts.on('-I PATH', '--include=PATH', String,
             'Adds include searchpath.',
             'Default: none') { |v|
       self.options[:includepaths] << (v.end_with?('\\', '/') ? v : v + '/')
     }
     opts.on('-Dmacro=[value]', String, 'defines preprocessor macro') { |v|
       name, value = v.split('=')
       self.options[:macros][name] = (value ? value : true)
     }
     opts.on('-n NAMESPACE', '--namespace=NAMESPACE', String,
             'Defines rootlevel enclosing namespace.',
             'Default: nil') { |v|
       self.options[:namespace] = v
     }
     opts.on('-v', '--verbose',
             'Set verbosity level. Repeat to increment.',
             'Default: 0') { |_|
       self.options[:verbose] += 1
     }
     opts.on('--debug',
             'Set parser debug mode. Do NOT do this at home!',
             'Default: off') { |_|
       self.options[:debug] = true
     }
     opts.on('--search-includepath',
             'Use include paths to find main IDL source.',
             'Default: off') { |_|
       self.options[:search_incpath] = true
     }
     opts.on('--no-input',
              'Do not parse specified file(s) as input IDL.',
              'Default: off') { |_|
       self.options[:no_input] = true
     }
     if @initopts[:preprocess]
       opts.on('--output=FILE', String,
               'Specifies filename to generate output in.',
               'Default: basename(idlfile)-\'.idl\'+<postfix>+<ext>') { |v|
         self.options[:output] = v
       }
     end

     # setup language mapping specific options
     be_options = OptionList.new
     @backend.setup_be(be_options, @initopts)
     be_options.to_option_parser(opts, self)

     opts.on('-V', '--version',
             'Show version information and exit.') {
       puts "RIDL compiler #{RIDL_VERSION}"
       puts RIDL_COPYRIGHT
       puts '---'
       @backend.print_version
       exit
     }

     opts.separator ""

     opts.on('-h', '--help',
             'Show this help message.') { puts opts
puts
exit }

     opts
   end