mirror of
https://github.com/mistergibson/gxg-web-client.git
synced 2026-08-15 11:34:29 -07:00
872 lines
22 KiB
Ruby
872 lines
22 KiB
Ruby
TOPLEVEL_BINDING = binding()
|
|
|
|
module Rubinius
|
|
class Loader
|
|
def initialize
|
|
@exit_code = 0
|
|
@process_id = Process.pid
|
|
@load_paths = []
|
|
@requires = []
|
|
@evals = []
|
|
@script = nil
|
|
@debugging = false
|
|
@repl = true
|
|
@printed_version = false
|
|
@input_loop = false
|
|
@input_loop_print = false
|
|
@input_loop_split = false
|
|
@simple_options = false
|
|
@early_option_stop = false
|
|
@check_syntax = false
|
|
@load_profiler = false
|
|
@enable_gems = true
|
|
@load_gemfile = false
|
|
@deprecations = false
|
|
|
|
version = RUBY_VERSION.split(".").first(2).join(".")
|
|
@gem_bins = ["#{version}/bin", "bin"].map do |dir|
|
|
File.join Rubinius::GEMS_PATH, dir
|
|
end
|
|
end
|
|
|
|
private :initialize
|
|
|
|
def self.debugger
|
|
@debugger_proc
|
|
end
|
|
|
|
def self.debugger=(prc)
|
|
@debugger_proc = prc
|
|
end
|
|
|
|
# Finish setting up after loading the core library.
|
|
def preamble
|
|
set_program_name "rbx"
|
|
@stage = "running Loader preamble"
|
|
|
|
# Set the default visibility for the top level binding
|
|
TOPLEVEL_BINDING.variables.method_visibility = :private
|
|
|
|
$VERBOSE = false
|
|
end
|
|
|
|
# Set up $LOAD_PATH.
|
|
def system_load_path
|
|
@stage = "setting up system load path"
|
|
|
|
@lib_bin = "#{Rubinius::CODEDB_PATH}/source/bin"
|
|
|
|
$LOAD_PATH.unshift(Rubinius::ARCH_PATH,
|
|
Rubinius::SITE_PATH,
|
|
"#{Rubinius::SITE_PATH}/#{RUBY_VERSION}",
|
|
Rubinius::VENDOR_PATH,
|
|
"#{Rubinius::CODEDB_PATH}/source")
|
|
|
|
if libs = ENV['RUBYLIB']
|
|
Rubinius::Logger.system.write "RUBYLIB: #{libs}"
|
|
|
|
$LOAD_PATH.unshift(*libs.split(File::PATH_SEPARATOR).compact)
|
|
end
|
|
end
|
|
|
|
# Load customization code:
|
|
# /etc/rbxrc
|
|
# $HOME/.rbxrc
|
|
# $RBX_PRELOAD
|
|
def preload
|
|
@stage = "preloading rbxrc code"
|
|
|
|
['/etc/rbxrc',"#{ENV['HOME']}/.rbxrc",ENV['RBX_PRELOAD']].each do |file|
|
|
begin
|
|
load file if file and File.exist?(file)
|
|
rescue LoadError
|
|
nil
|
|
end
|
|
end
|
|
end
|
|
|
|
# Register signal handlers.
|
|
def signals
|
|
@stage = "registering signal handlers"
|
|
|
|
# Set up a handler for SIGINT that raises Interrupt on the main thread
|
|
Signal.trap("INT") do |sig|
|
|
raise Interrupt, "Thread has been interrupted"
|
|
end
|
|
|
|
["HUP", "QUIT", "TERM", "ALRM", "USR1", "USR2"].each do |signal|
|
|
Signal.trap(signal) do |sig|
|
|
raise SignalException, sig
|
|
end
|
|
end
|
|
end
|
|
|
|
def show_syntax_error(e)
|
|
STDERR.puts "A syntax error has occurred:"
|
|
STDERR.puts " #{e.message}"
|
|
STDERR.puts "\nCode:\n#{e.code}"
|
|
if e.column
|
|
STDERR.puts((" " * (e.column - 1)) + "^")
|
|
end
|
|
end
|
|
|
|
def show_syntax_errors(syns)
|
|
syns.each do |e|
|
|
STDERR.puts "#{e.file}:#{e.line}: #{e.reason}"
|
|
end
|
|
end
|
|
|
|
# Checks if a subcommand with basename +base+ exists. Returns the full
|
|
# path to the subcommand if it does; otherwise, returns nil.
|
|
def find_subcommand(base)
|
|
command = File.join @lib_bin, "#{base}.rb"
|
|
return command if File.exist? command
|
|
return nil
|
|
end
|
|
|
|
# Checks if a gem wrapper named +base+ exists. Returns the full path to
|
|
# the gem wrapper if it does; otherwise, returns nil.
|
|
def find_gem_wrapper(base)
|
|
@gem_bins.each do |dir|
|
|
wrapper = File.join dir, base
|
|
return wrapper if File.exist? wrapper
|
|
end
|
|
return nil
|
|
end
|
|
|
|
# Detects if the Rubinius executable was aliased to a subcommand or a
|
|
# rubygems executable. If so, changes ARGV as if Rubinius were invoked
|
|
# to run the subcommand or rubygems executable.
|
|
def detect_alias
|
|
cmd = ARG0.split("/").last
|
|
|
|
# ignore the common ones straight away
|
|
return if cmd == "rbx" or cmd == "ruby"
|
|
|
|
# Check if we are aliased to a Rubinius subcommand.
|
|
if subcommand = find_subcommand(cmd)
|
|
ARGV.unshift subcommand
|
|
return
|
|
end
|
|
|
|
# Check if we are aliased to a rubygems executable.
|
|
if gem_wrapper = find_gem_wrapper(cmd)
|
|
ARGV.unshift "-S", gem_wrapper
|
|
end
|
|
end
|
|
|
|
def handle_simple_options(argv)
|
|
argv.delete_if do |x|
|
|
if x[0] == ?-
|
|
if equal = x.index("=")
|
|
name = x.substring(1, equal-1)
|
|
|
|
equal += 1
|
|
val = x.substring(equal, x.size - equal)
|
|
else
|
|
name = x.substring(1, x.size - 1)
|
|
val = true
|
|
end
|
|
|
|
name.gsub! "-", "_"
|
|
|
|
Rubinius::Globals[:"$#{name}"] = val
|
|
|
|
true
|
|
else
|
|
false
|
|
end
|
|
end
|
|
end
|
|
|
|
def define_global_methods
|
|
Kernel.module_eval do
|
|
def gsub(pattern, rep=nil, &block)
|
|
target = $_
|
|
raise TypeError, "$_ must be a String, but is #{target.inspect}" unless target.kind_of? String
|
|
$_ = target.gsub(pattern, rep, &block)
|
|
end
|
|
module_function :gsub
|
|
|
|
def sub(pattern, rep=nil, &block)
|
|
target = $_
|
|
raise TypeError, "$_ must be a String, but is #{target.inspect}" unless target.kind_of? String
|
|
$_ = target.sub(pattern, rep, &block)
|
|
end
|
|
module_function :sub
|
|
|
|
def chomp(string=$/)
|
|
raise TypeError, "$_ must be a String" unless $_.kind_of? String
|
|
$_ = $_.chomp(string)
|
|
end
|
|
module_function :chomp
|
|
|
|
def chop
|
|
raise TypeError, "$_ must be a String" unless $_.kind_of? String
|
|
$_ = $_.chop
|
|
end
|
|
module_function :chop
|
|
end
|
|
end
|
|
|
|
# Process all command line arguments.
|
|
def options(argv=ARGV)
|
|
@stage = "processing command line arguments"
|
|
|
|
options = Options.new "Usage: rbx [subcommand] [options] [--] [script] [arguments]", 25
|
|
|
|
options.left_align
|
|
options.on_extra do |x|
|
|
raise Options::ParseError, "Unrecognized option: #{x}" if x[0] == ?-
|
|
if @script.nil? and @evals.empty?
|
|
@script = x
|
|
else
|
|
argv.unshift x
|
|
end
|
|
options.stop_parsing
|
|
end
|
|
|
|
options.doc "Script is any valid Ruby source code file"
|
|
|
|
options.doc "\nRuby options"
|
|
options.on "-", "Read and evaluate code from STDIN" do
|
|
@repl = false
|
|
set_program_name "-"
|
|
stdin = STDIN.dup
|
|
script = STDIN.read
|
|
STDIN.reopen(stdin)
|
|
execute_script script
|
|
end
|
|
|
|
options.on "--", "Stop processing command line arguments" do
|
|
@early_option_stop = true
|
|
options.stop_parsing
|
|
end
|
|
|
|
options.on "-a", "Used with -n and -p, splits $_ into $F" do
|
|
@input_loop_split = true
|
|
Rubinius::Globals.set!(:$-a, true)
|
|
end
|
|
|
|
options.on "-c", "Only check the syntax" do
|
|
@repl = false
|
|
@check_syntax = true
|
|
end
|
|
|
|
options.on "-C", "DIR", "Change directory to DIR before running scripts" do |dir|
|
|
@directory = dir
|
|
end
|
|
|
|
options.on "-d", "Enable debugging output and set $DEBUG to true" do
|
|
$VERBOSE = true
|
|
$DEBUG = true
|
|
end
|
|
|
|
options.on "--disable-gems", "Do not automatically load rubygems on startup" do
|
|
@enable_gems = false
|
|
end
|
|
|
|
options.on "-e", "CODE", "Compile and execute CODE" do |code|
|
|
@repl = false
|
|
set_program_name "(eval)"
|
|
@evals << code
|
|
end
|
|
|
|
options.on '-F', "PATTERN", "Set $; to PATTERN" do |pattern|
|
|
Rubinius::Globals.set!(:$;, Regexp.new(pattern))
|
|
end
|
|
|
|
options.on '-G', '--gemfile', 'Respect a Gemfile in the current path' do
|
|
@load_gemfile = true
|
|
end
|
|
|
|
options.on "-h", "--help", "Display this help" do
|
|
@repl = false
|
|
puts options
|
|
done
|
|
end
|
|
|
|
options.on "-i", "[EXT]", "Edit ARGV files in place, making backup with EXT" do |ext|
|
|
# in place edit mode
|
|
ext ||= ''
|
|
$-i = ext
|
|
end
|
|
|
|
options.on "-I", "DIR1[:DIR2]", "Add directories to $LOAD_PATH" do |dir|
|
|
@load_paths << dir
|
|
end
|
|
|
|
options.on "-K", "Ignored $KCODE option for compatibility" do
|
|
msg = "The -K option is deprecated. Rubinius internal encoding is always UTF-8"
|
|
STDERR.puts msg
|
|
Rubinius::Logger.system.warn msg
|
|
end
|
|
|
|
options.on "-U", "Set Encoding.default_internal to UTF-8" do
|
|
msg = "The -U option is deprecated. Rubinius internal encoding is always UTF-8"
|
|
STDERR.puts msg
|
|
Rubinius::Logger.system.warn msg
|
|
end
|
|
|
|
options.on "-E", "ENC", "Set external:internal character encoding to ENC" do |enc|
|
|
external, internal = enc.split(":")
|
|
Encoding.default_external = external if external and !external.empty?
|
|
|
|
if internal and !internal.empty?
|
|
msg = "The -E option setting internal encoding is deprecated. Rubinius internal encoding is always UTF-8"
|
|
STDERR.puts msg
|
|
Rubinius::Logger.system.warn msg
|
|
end
|
|
end
|
|
|
|
options.on "--main", "PATH", "Load PATH directly from CodeDB" do |path|
|
|
code = Rubinius::CoreDB.load_feature path, "", false, false
|
|
if code
|
|
code.create_script false
|
|
Rubinius.run_script code
|
|
exit 0
|
|
else
|
|
puts "file not found: #{path}"
|
|
exit 1
|
|
end
|
|
end
|
|
|
|
options.on "-n", "Wrap running code in 'while(gets()) ...'" do
|
|
@input_loop = true
|
|
define_global_methods
|
|
end
|
|
|
|
options.on "-p", "Same as -n, but also print $_" do
|
|
@input_loop = true
|
|
@input_loop_print = true
|
|
Rubinius::Globals.set!(:$-p, true)
|
|
define_global_methods
|
|
end
|
|
|
|
options.on "-r", "LIBRARY", "Require library before execution" do |file|
|
|
@requires << file
|
|
end
|
|
|
|
options.on("-s", "Process options after the script into globals") do
|
|
@simple_options = true
|
|
end
|
|
|
|
options.on("-S", "SCRIPT",
|
|
"Run SCRIPT using PATH environment variable to find it") do |script|
|
|
options.stop_parsing
|
|
@repl = false
|
|
|
|
# Load a gemfile now if we need to so that -S can see binstubs
|
|
# internal to the Gemfile
|
|
gemfile
|
|
|
|
# First, check if any existing gem wrappers match.
|
|
unless file = find_gem_wrapper(script)
|
|
# Then, check if any Rubinius subcommands match.
|
|
unless file = find_subcommand(script)
|
|
# Finally, check if any file on PATH matches.
|
|
search = ENV['PATH'].split(File::PATH_SEPARATOR)
|
|
search.each do |d|
|
|
path = File.join d, script
|
|
if File.exist? path
|
|
file = path
|
|
break
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
set_program_name script if file
|
|
|
|
# if missing, let it die a natural death
|
|
@script = file ? file : script
|
|
end
|
|
|
|
options.on "-v", "Display the version and set $VERBOSE to true" do
|
|
@repl = false
|
|
$VERBOSE = true
|
|
|
|
unless @printed_version
|
|
puts Rubinius.version
|
|
@printed_version = true
|
|
end
|
|
end
|
|
|
|
options.on "-w", "Enable warnings" do
|
|
$VERBOSE = true
|
|
end
|
|
|
|
options.on("-W", "[level]",
|
|
"Set warning level: 0=silence, 1=medium, 2=verbose (default)") do |l|
|
|
case l
|
|
when "0"
|
|
$VERBOSE = nil
|
|
when "1"
|
|
$VERBOSE = false
|
|
when nil
|
|
$VERBOSE = true
|
|
else
|
|
# MRI -h says -W2 sets $VERBOSE to true, but behaviorally
|
|
# any value >= 2 sets $VERBOSE to true.
|
|
$VERBOSE = true
|
|
end
|
|
end
|
|
|
|
options.on "--show-nil-location", "Show where nil value originated when NoMethodError on nil is raised" do
|
|
$rbx_show_nil_location = true
|
|
end
|
|
|
|
options.on "--deprecated", "Display any deprecations" do
|
|
@deprecations = true
|
|
end
|
|
|
|
options.on "--version", "Display the version" do
|
|
@repl = false
|
|
puts Rubinius.version
|
|
end
|
|
|
|
options.doc <<-DOC
|
|
\nRubinius subcommands
|
|
|
|
Rubinius provides subcommands that implement various facilities. Each
|
|
subcommand provides its own help. For example:
|
|
|
|
rbx compile -h
|
|
|
|
Available subcommands:
|
|
|
|
compile Run the bytecode compiler
|
|
gem Run RubyGems 'gem' command
|
|
irb Run IRB
|
|
erb Run ERb
|
|
DOC
|
|
|
|
options.doc <<-DOC
|
|
VM Options
|
|
-X<variable>[=<value>]
|
|
This option is recognized by the VM before any ruby code is loaded.
|
|
It is used to set VM configuration options.
|
|
|
|
Use -Xhelp to see the list of options the VM recognizes.
|
|
All variables, even ones that the VM doesn't understand, are available
|
|
in Rubinius::Config.
|
|
|
|
Options are parsed from these sources, in this order:
|
|
|
|
1. The file .rbxrc in the current working directory.
|
|
2. The RBXOPT environment variable.
|
|
3. The command line options.
|
|
|
|
This order permits environment and command line options to override
|
|
"application" configuration. Likewise, command line options can override
|
|
environment configuration.
|
|
|
|
A number of Rubinius features are driven by setting these variables.
|
|
DOC
|
|
|
|
options.parse ARGV
|
|
|
|
handle_rubyopt(options)
|
|
|
|
if @early_option_stop and @simple_options
|
|
handle_simple_options(argv)
|
|
end
|
|
|
|
if Rubinius::Config['help']
|
|
STDOUT.puts "Rubinius configuration variables:"
|
|
STDOUT.puts " These variables are normally set via -X and read via Rubinius::Config[var]."
|
|
STDOUT.puts
|
|
|
|
require 'rubinius/configuration'
|
|
Rubinius::ConfigurationVariables.instance.show_help(STDOUT)
|
|
exit 0
|
|
end
|
|
|
|
exit 0 if Rubinius::Config["config.print"]
|
|
|
|
if str = Rubinius::Config['tool.require']
|
|
begin
|
|
require str
|
|
rescue LoadError
|
|
STDERR.puts "Unable to require file for tool: '#{str}'"
|
|
end
|
|
end
|
|
|
|
if Rubinius::Config['profile'] || Rubinius::Config['jit.profile']
|
|
@load_profiler = true
|
|
end
|
|
|
|
if @check_syntax
|
|
check_syntax
|
|
end
|
|
end
|
|
|
|
# Sets $0 ($PROGRAM_NAME) without changing the process title
|
|
def set_program_name(name)
|
|
Rubinius::Globals.set! :$0, name
|
|
end
|
|
private :set_program_name
|
|
|
|
def handle_rubyopt(options)
|
|
if env_opts = ENV['RUBYOPT']
|
|
Rubinius::Logger.system.write "RUBYOPT: #{env_opts}"
|
|
|
|
options.start_parsing
|
|
env_opts = env_opts.strip.split(/\s+/)
|
|
|
|
until env_opts.empty?
|
|
entry = env_opts.shift
|
|
|
|
unless entry[0] == ?-
|
|
entry = "-#{entry}"
|
|
end
|
|
|
|
opt, arg, rest = options.split entry, 2
|
|
|
|
options.process env_opts, entry, opt, arg
|
|
end
|
|
end
|
|
|
|
end
|
|
|
|
# Update the load paths with any -I arguments.
|
|
def load_paths
|
|
@stage = "setting load paths"
|
|
|
|
@load_paths.each do |path|
|
|
path.split(":").reverse_each do |path|
|
|
# We used to run expand_path on path first, but MRI
|
|
# doesn't and it breaks some code if we do.
|
|
$LOAD_PATH.unshift(path)
|
|
end
|
|
end
|
|
end
|
|
|
|
def deprecations
|
|
@stage = "showing deprecations"
|
|
|
|
return unless @deprecations
|
|
|
|
if Rubinius::DEPRECATIONS.size > 0
|
|
Rubinius::DEPRECATIONS.each do |desc, alt|
|
|
STDERR.puts <<-EOM
|
|
Deprecation: #{desc}
|
|
Alternative: #{alt}
|
|
|
|
EOM
|
|
end
|
|
|
|
exit 1
|
|
else
|
|
STDERR.puts "Rubinius #{Rubinius::VERSION} has no deprecation notices"
|
|
exit 0
|
|
end
|
|
end
|
|
|
|
def load_compiler
|
|
@stage = "loading the compiler"
|
|
|
|
begin
|
|
CodeLoader.load_compiler
|
|
rescue LoadError => e
|
|
message = "Unable to load the bytecode compiler."
|
|
Rubinius::Logger.system.error message
|
|
Rubinius::Logger.system.error(
|
|
"Please run 'rake' or 'rake install' to rebuild the compiler.")
|
|
Rubinius::Logger.log_exception message, e
|
|
exit 1
|
|
end
|
|
end
|
|
|
|
def debugger
|
|
@stage = "running the debugger"
|
|
|
|
if Rubinius::Config['debug']
|
|
if custom = Loader.debugger
|
|
custom.call
|
|
else
|
|
require 'rubinius/debugger'
|
|
Rubinius::Debugger.start
|
|
end
|
|
end
|
|
end
|
|
|
|
def rubygems
|
|
@stage = "loading Rubygems"
|
|
|
|
CodeLoader.load_rubygems if @enable_gems
|
|
end
|
|
|
|
def gemfile
|
|
@stage = "loading Gemfile"
|
|
|
|
if @load_gemfile
|
|
CodeLoader.load_rubygems
|
|
require 'bundler/setup'
|
|
@load_gemfile = false
|
|
end
|
|
end
|
|
|
|
def profiler
|
|
return unless @load_profiler
|
|
@stage = "loading profiler"
|
|
|
|
require 'profile'
|
|
end
|
|
|
|
# Require any -r arguments
|
|
def requires
|
|
@stage = "requiring command line files"
|
|
|
|
@requires.each { |file| require file }
|
|
end
|
|
|
|
# Evaluate any -e arguments
|
|
def evals
|
|
return if @evals.empty?
|
|
|
|
@repl = false
|
|
@stage = "evaluating command line code"
|
|
|
|
Dir.chdir(@directory) if @directory
|
|
|
|
if @input_loop
|
|
while gets
|
|
$F = $_.split if @input_loop_split
|
|
eval @evals.join("\n"), TOPLEVEL_BINDING, "-e", 1
|
|
print $_ if @input_loop_print
|
|
end
|
|
else
|
|
eval @evals.join("\n"), TOPLEVEL_BINDING, "-e", 1
|
|
end
|
|
end
|
|
|
|
# Run the script passed on the command line
|
|
def script
|
|
return unless @script and @evals.empty?
|
|
|
|
@repl = false
|
|
|
|
handle_simple_options(ARGV) if @simple_options
|
|
|
|
@stage = "running #{@script}"
|
|
Dir.chdir @directory if @directory
|
|
|
|
if File.exist? @script
|
|
if IO.read(@script, 6) == "!RBIX\n"
|
|
raise LoadError, "'#{@script}' is not a Ruby source file"
|
|
end
|
|
else
|
|
if @script.suffix?(".rb")
|
|
raise LoadError, "unable to find '#{@script}'"
|
|
else
|
|
command = File.join @lib_bin, "#{@script}.rb"
|
|
unless File.exist? command
|
|
raise LoadError, "unable to find Rubinius command '#{@script}'"
|
|
else
|
|
@script = command
|
|
end
|
|
end
|
|
end
|
|
|
|
set_program_name @script
|
|
CodeLoader.new(@script).load_script
|
|
end
|
|
|
|
#Check Ruby syntax of source
|
|
def check_syntax
|
|
parser_class = Rubinius::ToolSets::Runtime::Melbourne
|
|
|
|
if @script
|
|
if File.exist?(@script)
|
|
parser = parser_class.new @script, 1, []
|
|
parser.parse_file
|
|
else
|
|
puts "rbx: Unable to find file -- #{@script} (LoadError)"
|
|
exit 1
|
|
end
|
|
elsif not @evals.empty?
|
|
parser = parser_class.new('-e', 1, [])
|
|
parser.parse_string(@evals.join("\n"))
|
|
else
|
|
parser = parser_class.new('-', 1, [])
|
|
parser.parse_string(STDIN.read)
|
|
end
|
|
|
|
puts "Syntax OK"
|
|
exit 0
|
|
rescue SyntaxError => e
|
|
show_syntax_errors(parser.syntax_errors)
|
|
exit 1
|
|
end
|
|
|
|
# Run IRB unless we were passed -e, -S arguments or a script to run.
|
|
def repl
|
|
return unless @repl
|
|
|
|
@stage = "running IRB"
|
|
|
|
# Check if a different REPL is set.
|
|
repl = ENV["RBX_REPL"] || "irb"
|
|
|
|
if Terminal
|
|
load File.join(Rubinius::GEMS_PATH, "bin", repl)
|
|
else
|
|
set_program_name "(eval)"
|
|
execute_script "p #{STDIN.read}"
|
|
end
|
|
end
|
|
|
|
def execute_script(script)
|
|
eval script, TOPLEVEL_BINDING
|
|
end
|
|
|
|
def run_at_exits
|
|
until AtExit.empty?
|
|
begin
|
|
AtExit.shift.call
|
|
rescue SystemExit => e
|
|
@exit_code = e.status
|
|
# We recurse down so that future at_exits
|
|
# see the current exception
|
|
run_at_exits
|
|
end
|
|
end
|
|
end
|
|
|
|
def flush_stdio
|
|
STDOUT.flush unless STDOUT.closed?
|
|
STDERR.flush unless STDERR.closed?
|
|
end
|
|
|
|
def exit_with_exception(e)
|
|
@exit_code = 1
|
|
Rubinius::Logger.log_exception "An exception occurred #{@stage}", e
|
|
end
|
|
|
|
# Cleanup and at_exit processing.
|
|
def epilogue
|
|
@stage = "running at_exit handlers"
|
|
|
|
begin
|
|
Signal.run_handler Signal::Names["EXIT"]
|
|
rescue SystemExit => e
|
|
@exit_code = e.status
|
|
end
|
|
|
|
run_at_exits
|
|
|
|
flush_stdio
|
|
|
|
rescue Object => e
|
|
exit_with_exception e
|
|
end
|
|
|
|
# Exit.
|
|
def done
|
|
# check that this is a valid exit rather than failing to process
|
|
# unwinding properly.
|
|
#
|
|
# TODO: this code is pretty gross, nice object inspectors, please.
|
|
thread_state = Rubinius.thread_state
|
|
reason = thread_state[0]
|
|
unless reason == :none
|
|
STDERR.puts "\nERROR: the VM is exiting improperly #{@stage}"
|
|
STDERR.puts "intended operation: #{reason.inspect}"
|
|
STDERR.puts "associated value: #{thread_state[1].inspect}"
|
|
|
|
destination = thread_state[2]
|
|
|
|
if destination
|
|
method = destination.method
|
|
|
|
STDERR.puts "destination scope:"
|
|
STDERR.puts " method: #{method.name} at #{method.file}:#{method.first_line}"
|
|
STDERR.puts " module: #{destination.module.name}"
|
|
STDERR.puts " block: #{destination.block}" if destination.block
|
|
else
|
|
STDERR.puts "destination scope: unknown"
|
|
end
|
|
|
|
if reason == :catch_throw
|
|
STDERR.puts "throw destination: #{thread_state[4].inspect}"
|
|
end
|
|
|
|
if exception = thread_state[3]
|
|
begin
|
|
exception.render
|
|
rescue Exception => e
|
|
STDERR.puts "Unable to render backtrace: #{e.message} (#{e.class})"
|
|
STDERR.puts "Raw backtrace data:"
|
|
|
|
exception.locations.each do |loc|
|
|
p [loc.file, loc.line]
|
|
end
|
|
end
|
|
end
|
|
|
|
@exit_code = 1
|
|
end
|
|
|
|
Process.exit! @exit_code
|
|
end
|
|
|
|
def handle_exception(e)
|
|
case e
|
|
when SystemExit
|
|
@exit_code = e.status
|
|
when SyntaxError
|
|
@exit_code = 1
|
|
|
|
STDERR.puts e.awesome_backtrace.show
|
|
STDERR.puts
|
|
|
|
show_syntax_error(e)
|
|
when Interrupt
|
|
exit_with_exception e
|
|
when SignalException
|
|
Signal.trap(e.signo, "SIG_DFL")
|
|
Process.kill e.signo, Process.pid
|
|
when nil
|
|
# what?
|
|
else
|
|
exit_with_exception e
|
|
end
|
|
rescue Object => e
|
|
exit_with_exception e
|
|
ensure
|
|
epilogue
|
|
end
|
|
|
|
# Orchestrate everything.
|
|
def main
|
|
preamble
|
|
system_load_path
|
|
signals
|
|
load_compiler
|
|
preload
|
|
detect_alias
|
|
options
|
|
load_paths
|
|
deprecations
|
|
rubygems
|
|
gemfile
|
|
debugger
|
|
profiler
|
|
requires
|
|
evals
|
|
script
|
|
repl
|
|
|
|
rescue Object => e
|
|
handle_exception e
|
|
else
|
|
# We do this, run epilogue both in the rescue blocks and also here,
|
|
# so that at_exit{} hooks can read $!.
|
|
epilogue
|
|
ensure
|
|
done
|
|
end
|
|
end
|
|
end
|
|
|