mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00

git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/branches/ruby_1_6@1350 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
317 lines
6.6 KiB
Ruby
317 lines
6.6 KiB
Ruby
#
|
||
# irb.rb - irb main module
|
||
# $Release Version: 0.7.3 $
|
||
# $Revision$
|
||
# $Date$
|
||
# by Keiju ISHITSUKA(keiju@ishitsuka.com)
|
||
#
|
||
# --
|
||
#
|
||
#
|
||
#
|
||
require "e2mmap"
|
||
|
||
require "irb/init"
|
||
require "irb/context"
|
||
require "irb/extend-command"
|
||
require "irb/workspace"
|
||
|
||
require "irb/ruby-lex"
|
||
require "irb/input-method"
|
||
require "irb/locale"
|
||
|
||
STDOUT.sync = true
|
||
|
||
module IRB
|
||
@RCS_ID='-$Id$-'
|
||
|
||
class Abort < Exception;end
|
||
|
||
#
|
||
@CONF = {}
|
||
|
||
def IRB.conf
|
||
@CONF
|
||
end
|
||
|
||
# IRB version method
|
||
def IRB.version
|
||
if v = @CONF[:VERSION] then return v end
|
||
|
||
require "irb/version"
|
||
rv = @RELEASE_VERSION.sub(/\.0/, "")
|
||
@CONF[:VERSION] = format("irb %s(%s)", rv, @LAST_UPDATE_DATE)
|
||
end
|
||
|
||
# initialize IRB and start TOP_LEVEL irb
|
||
# (JP: IRB$B=i4|2=$H%H%C%W%l%Y%k(Birb$B5/F0(B)
|
||
def IRB.start(ap_path = nil)
|
||
$0 = File::basename(ap_path, ".rb") if ap_path
|
||
|
||
IRB.initialize(ap_path)
|
||
IRB.parse_opts
|
||
IRB.load_modules
|
||
|
||
if @CONF[:SCRIPT]
|
||
irb = Irb.new(nil, @CONF[:SCRIPT])
|
||
else
|
||
irb = Irb.new
|
||
end
|
||
|
||
@CONF[:IRB_RC].call(irb.context) if @CONF[:IRB_RC]
|
||
@CONF[:MAIN_CONTEXT] = irb.context
|
||
|
||
trap("SIGINT") do
|
||
irb.signal_handle
|
||
end
|
||
|
||
catch(:IRB_EXIT) do
|
||
irb.eval_input
|
||
end
|
||
print "\n"
|
||
end
|
||
|
||
def IRB.irb_exit(irb, ret)
|
||
throw :IRB_EXIT, ret
|
||
end
|
||
|
||
def IRB.irb_abort(irb, exception = Abort)
|
||
if defined? Thread
|
||
irb.context.thread.raise exception, "abort then interrupt!!"
|
||
else
|
||
raise exception, "abort then interrupt!!"
|
||
end
|
||
end
|
||
|
||
#
|
||
# irb interpriter main routine
|
||
# (JP: irb$B%$%s%?%W%j%?K\BN(B)
|
||
#
|
||
class Irb
|
||
def initialize(workspace = nil, input_method = nil)
|
||
@context = Context.new(self, workspace, input_method)
|
||
@context.main.extend ExtendCommand
|
||
@signal_status = :IN_IRB
|
||
|
||
@scanner = RubyLex.new
|
||
@scanner.exception_on_syntax_error = false
|
||
end
|
||
attr_reader :context
|
||
attr_accessor :scanner
|
||
|
||
def eval_input
|
||
@scanner.set_input(@context.io) do
|
||
signal_status(:IN_INPUT) do
|
||
unless l = @context.io.gets
|
||
if @context.ignore_eof? and @context.io.readable_atfer_eof?
|
||
l = "\n"
|
||
if @context.verbose?
|
||
printf "Use \"exit\" to leave %s\n", @context.ap_name
|
||
end
|
||
end
|
||
end
|
||
l
|
||
end
|
||
end
|
||
|
||
@scanner.set_prompt do
|
||
|ltype, indent, continue, line_no|
|
||
if ltype
|
||
f = @context.prompt_s
|
||
elsif continue
|
||
f = @context.prompt_c
|
||
else @context.prompt_i
|
||
f = @context.prompt_i
|
||
end
|
||
f = "" unless f
|
||
@context.io.prompt = p = prompt(f, ltype, indent, line_no)
|
||
if @context.auto_indent_mode
|
||
unless ltype
|
||
ind = prompt(@context.prompt_i, ltype, indent, line_no).size +
|
||
indent * 2 - p.size
|
||
ind += 2 if continue
|
||
@context.io.prompt = p + " " * ind if ind > 0
|
||
end
|
||
end
|
||
end
|
||
|
||
@scanner.each_top_level_statement do
|
||
|line, line_no|
|
||
signal_status(:IN_EVAL) do
|
||
begin
|
||
trace_in do
|
||
@context._ = @context.workspace.evaluate(line,
|
||
@context.irb_path,
|
||
line_no)
|
||
# @context._ = irb_eval(line, @context.bind, @context.irb_path, line_no)
|
||
end
|
||
|
||
if @context.inspect?
|
||
printf @context.return_format, @context._.inspect
|
||
else
|
||
printf @context.return_format, @context._
|
||
end
|
||
rescue StandardError, ScriptError, Abort
|
||
$! = RuntimeError.new("unknown exception raised") unless $!
|
||
print $!.type, ": ", $!, "\n"
|
||
if $@[0] =~ /irb(2)?(\/.*|-.*|\.rb)?:/ && $!.type.to_s !~ /^IRB/
|
||
irb_bug = true
|
||
else
|
||
irb_bug = false
|
||
end
|
||
|
||
messages = []
|
||
lasts = []
|
||
levels = 0
|
||
for m in $@
|
||
m = @context.workspace.filter_backtrace(m) unless irb_bug
|
||
if m
|
||
if messages.size < @context.back_trace_limit
|
||
messages.push "\tfrom "+m
|
||
else
|
||
lasts.push "\tfrom "+m
|
||
if lasts.size > @context.back_trace_limit
|
||
lasts.shift
|
||
levels += 1
|
||
end
|
||
end
|
||
end
|
||
end
|
||
print messages.join("\n"), "\n"
|
||
unless lasts.empty?
|
||
printf "... %d levels...\n", levels if levels > 0
|
||
print lasts.join("\n")
|
||
end
|
||
print "Maybe IRB bug!!\n" if irb_bug
|
||
end
|
||
end
|
||
end
|
||
end
|
||
|
||
# def irb_eval(line, bind, path, line_no)
|
||
# id, str = catch(:IRB_TOPLEVEL_EVAL){
|
||
# return eval(line, bind, path, line_no)
|
||
# }
|
||
# case id
|
||
# when :EVAL_TOPLEVEL
|
||
# eval(str, bind, "(irb_internal)", 1)
|
||
# when :EVAL_CONTEXT
|
||
# @context.instance_eval(str)
|
||
# else
|
||
# IRB.fail IllegalParameter
|
||
# end
|
||
# end
|
||
|
||
def signal_handle
|
||
unless @context.ignore_sigint?
|
||
print "\nabort!!\n" if @context.verbose?
|
||
exit
|
||
end
|
||
|
||
case @signal_status
|
||
when :IN_INPUT
|
||
print "^C\n"
|
||
@scanner.initialize_input
|
||
print @context.io.prompt
|
||
when :IN_EVAL
|
||
IRB.irb_abort(self)
|
||
when :IN_LOAD
|
||
IRB.irb_abort(self, LoadAbort)
|
||
when :IN_IRB
|
||
# ignore (JP: $B2?$b$7$J$$(B.)
|
||
else
|
||
# ignore (JP: $B$=$NB>$N>l9g$b2?$b$7$J$$(B.)
|
||
end
|
||
end
|
||
|
||
def signal_status(status)
|
||
return yield if @signal_status == :IN_LOAD
|
||
|
||
signal_status_back = @signal_status
|
||
@signal_status = status
|
||
begin
|
||
yield
|
||
ensure
|
||
@signal_status = signal_status_back
|
||
end
|
||
end
|
||
|
||
def trace_in
|
||
Tracer.on if @context.use_tracer?
|
||
begin
|
||
yield
|
||
ensure
|
||
Tracer.off if @context.use_tracer?
|
||
end
|
||
end
|
||
|
||
def prompt(prompt, ltype, indent, line_no)
|
||
p = prompt.dup
|
||
p.gsub!(/%([0-9]+)?([a-zA-Z])/) do
|
||
case $2
|
||
when "N"
|
||
@context.irb_name
|
||
when "m"
|
||
@context.main.to_s
|
||
when "M"
|
||
@context.main.inspect
|
||
when "l"
|
||
ltype
|
||
when "i"
|
||
if $1
|
||
format("%" + $1 + "d", indent)
|
||
else
|
||
indent.to_s
|
||
end
|
||
when "n"
|
||
if $1
|
||
format("%" + $1 + "d", line_no)
|
||
else
|
||
line_no.to_s
|
||
end
|
||
when "%"
|
||
"%"
|
||
end
|
||
end
|
||
p
|
||
end
|
||
|
||
def inspect
|
||
ary = []
|
||
for iv in instance_variables
|
||
case iv
|
||
when "@signal_status"
|
||
ary.push format("%s=:%s", iv, @signal_status.id2name)
|
||
when "@context"
|
||
ary.push format("%s=%s", iv, eval(iv).__to_s__)
|
||
else
|
||
ary.push format("%s=%s", iv, eval(iv))
|
||
end
|
||
end
|
||
format("#<%s: %s>", type, ary.join(", "))
|
||
end
|
||
end
|
||
|
||
# Singleton method
|
||
def @CONF.inspect
|
||
IRB.version unless self[:VERSION]
|
||
|
||
array = []
|
||
for k, v in sort{|a1, a2| a1[0].id2name <=> a2[0].id2name}
|
||
case k
|
||
when :MAIN_CONTEXT
|
||
next
|
||
when :PROMPT
|
||
s = v.collect{
|
||
|kk, vv|
|
||
ss = vv.collect{|kkk, vvv| ":#{kkk.id2name}=>#{vvv.inspect}"}
|
||
format(":%s=>{%s}", kk.id2name, ss.join(", "))
|
||
}
|
||
array.push format("CONF[:%s]={%s}", k.id2name, s.join(", "))
|
||
else
|
||
array.push format("CONF[:%s]=%s", k.id2name, v.inspect)
|
||
end
|
||
end
|
||
array.join("\n")
|
||
end
|
||
end
|