Fix up Rubinius specific library specs.
[rbx.git] / lib / irb.rb
bloba74d62c4531ee63167d2e060f23d56067da4e0e7
2 #   irb.rb - irb main module
3 #       $Release Version: 0.9.5 $
4 #       $Revision: 11708 $
5 #       $Date: 2007-02-12 15:01:19 -0800 (Mon, 12 Feb 2007) $
6 #       by Keiju ISHITSUKA(keiju@ruby-lang.org)
8 # --
12 require "e2mmap"
14 require "irb/init"
15 require "irb/context"
16 require "irb/extend-command"
17 #require "irb/workspace"
19 require "irb/ruby-lex"
20 require "irb/input-method"
21 require "irb/locale"
23 STDOUT.sync = true
25 module IRB
26   @RCS_ID='-$Id: irb.rb 11708 2007-02-12 23:01:19Z shyouhei $-'
28   class Abort < Exception;end
30   #
31   @CONF = {}
33   def IRB.conf
34     @CONF
35   end
37   # IRB version method
38   def IRB.version
39     if v = @CONF[:VERSION] then return v end
41     require "irb/version"
42     rv = @RELEASE_VERSION.sub(/\.0/, "")
43     @CONF[:VERSION] = format("irb %s(%s)", rv, @LAST_UPDATE_DATE)
44   end
46   def IRB.CurrentContext
47     IRB.conf[:MAIN_CONTEXT]
48   end
50   # initialize IRB and start TOP_LEVEL irb
51   def IRB.start(ap_path = nil)
52     $0 = File::basename(ap_path, ".rb") if ap_path
54     IRB.setup(ap_path)
56     if @CONF[:IRB_CLASS]
57       klass = @CONF[:IRB_CLASS]
58     else
59       klass = Irb
60     end
62     if @CONF[:SCRIPT]
63       irb = klass.new(nil, @CONF[:SCRIPT])
64     else
65       irb = klass.new
66     end
68     @CONF[:IRB_RC].call(irb.context) if @CONF[:IRB_RC]
69     @CONF[:MAIN_CONTEXT] = irb.context
71     trap("SIGINT") do
72       irb.signal_handle
73     end
74     
75     catch(:IRB_EXIT) do
76       irb.eval_input
77     end
78 #    print "\n"
79   end
81   def IRB.irb_exit(irb, ret)
82     throw :IRB_EXIT, ret
83   end
85   def IRB.irb_abort(irb, exception = Abort)
86     if defined? Thread
87       irb.context.thread.raise exception, "abort then interrupt!!"
88     else
89       raise exception, "abort then interrupt!!"
90     end
91   end
93   #
94   # irb interpriter main routine 
95   #
96   class Irb
97     def initialize(workspace = nil, input_method = nil, output_method = nil)
98       @context = Context.new(self, workspace, input_method, output_method)
99       @context.main.extend ExtendCommandBundle
100       @signal_status = :IN_IRB
102       @scanner = RubyLex.new
103       @scanner.exception_on_syntax_error = false
104     end
105     attr_reader :context
106     attr_accessor :scanner
108     def eval_input
109       @scanner.set_prompt do
110         |ltype, indent, continue, line_no|
111         if ltype
112           f = @context.prompt_s
113         elsif continue
114           f = @context.prompt_c
115         elsif indent > 0
116           f = @context.prompt_n
117         else @context.prompt_i
118           f = @context.prompt_i
119         end
120         f = "" unless f
121         if @context.prompting?
122           @context.io.prompt = p = prompt(f, ltype, indent, line_no)
123         else
124           @context.io.prompt = p = ""
125         end
126         if @context.auto_indent_mode
127           unless ltype
128             ind = prompt(@context.prompt_i, ltype, indent, line_no)[/.*\z/].size +
129               indent * 2 - p.size
130             ind += 2 if continue
131             @context.io.prompt = p + " " * ind if ind > 0
132           end
133         end
134       end
135        
136       @scanner.set_input(@context.io) do
137         signal_status(:IN_INPUT) do
138           if l = @context.io.gets
139             print l if @context.verbose?
140           else
141             if @context.ignore_eof? and @context.io.readable_atfer_eof?
142               l = "\n"
143               if @context.verbose?
144                 printf "Use \"exit\" to leave %s\n", @context.ap_name
145               end
146             end
147           end
148           l
149         end
150       end
151       
152       process_statements
153     end
154     
155     def process_statements
156       @scanner.each_top_level_statement do |line, line_no|
157         signal_status(:IN_EVAL) do
158           begin
159             line.untaint
160             @context.evaluate(line, line_no)
161             output_value if @context.echo?
162           rescue StandardError, ScriptError, Abort
163             $! = RuntimeError.new("unknown exception raised") unless $!
164             print $!.class, ": ", $!, "\n"
165             if  $@[0] =~ /irb(2)?(\/.*|-.*|\.rb)?:/ && $!.class.to_s !~ /^IRB/
166               irb_bug = true 
167             else
168               irb_bug = false
169             end
170             
171             messages = []
172             lasts = []
173             levels = 0
174             for m in $@
175               m = @context.workspace.filter_backtrace(m) unless irb_bug
176               if m
177                 if messages.size < @context.back_trace_limit
178                   messages.push "\tfrom "+m
179                 else
180                   lasts.push "\tfrom "+m
181                   if lasts.size > @context.back_trace_limit
182                     lasts.shift 
183                     levels += 1
184                   end
185                 end
186               end
187             end
188             print messages.join("\n"), "\n"
189             unless lasts.empty?
190               printf "... %d levels...\n", levels if levels > 0
191               print lasts.join("\n")
192             end
193             print "Maybe IRB bug!!\n" if irb_bug
194           end
195           if $SAFE > 2
196             warn "Error: irb does not work for $SAFE level higher than 2"
197             exit 1
198           end
199         end
200       end
201     end
203     def suspend_name(path = nil, name = nil)
204       @context.irb_path, back_path = path, @context.irb_path if path
205       @context.irb_name, back_name = name, @context.irb_name if name
206       begin
207         yield back_path, back_name
208       ensure
209         @context.irb_path = back_path if path
210         @context.irb_name = back_name if name
211       end
212     end
214     def suspend_workspace(workspace)
215       @context.workspace, back_workspace = workspace, @context.workspace
216       begin
217         yield back_workspace
218       ensure
219         @context.workspace = back_workspace
220       end
221     end
223     def suspend_input_method(input_method)
224       back_io = @context.io
225       @context.instance_eval{@io = input_method}
226       begin
227         yield back_io
228       ensure
229         @context.instance_eval{@io = back_io}
230       end
231     end
233     def suspend_context(context)
234       @context, back_context = context, @context
235       begin
236         yield back_context
237       ensure
238         @context = back_context
239       end
240     end
242     def signal_handle
243       unless @context.ignore_sigint?
244         print "\nabort!!\n" if @context.verbose?
245         exit
246       end
248       case @signal_status
249       when :IN_INPUT
250         print "^C\n"
251         raise RubyLex::TerminateLineInput
252       when :IN_EVAL
253         IRB.irb_abort(self)
254       when :IN_LOAD
255         IRB.irb_abort(self, LoadAbort)
256       when :IN_IRB
257         # ignore
258       else
259         # ignore other cases as well
260       end
261     end
263     def signal_status(status)
264       return yield if @signal_status == :IN_LOAD
266       signal_status_back = @signal_status
267       @signal_status = status
268       begin
269         yield
270       ensure
271         @signal_status = signal_status_back
272       end
273     end
275     def prompt(prompt, ltype, indent, line_no)
276       p = prompt.dup
277       p.gsub!(/%([0-9]+)?([a-zA-Z])/) do
278         case $2
279         when "N"
280           @context.irb_name
281         when "m"
282           @context.main.to_s
283         when "M"
284           @context.main.inspect
285         when "l"
286           ltype
287         when "i"
288           if $1 
289             format("%" + $1 + "d", indent)
290           else
291             indent.to_s
292           end
293         when "n"
294           if $1 
295             format("%" + $1 + "d", line_no)
296           else
297             line_no.to_s
298           end
299         when "%"
300           "%"
301         end
302       end
303       p
304     end
306     def output_value
307       if @context.inspect?
308         printf @context.return_format, @context.last_value.inspect
309       else
310         printf @context.return_format, @context.last_value
311       end
312     end
314     def inspect
315       ary = []
316       for iv in instance_variables
317         case iv
318         when "@signal_status"
319           ary.push format("%s=:%s", iv, @signal_status.id2name)
320         when "@context"
321           ary.push format("%s=%s", iv, eval(iv).__to_s__)
322         else
323           ary.push format("%s=%s", iv, eval(iv))
324         end
325       end
326       format("#<%s: %s>", self.class, ary.join(", "))
327     end
328   end
330   # Singleton method
331   def @CONF.inspect
332     IRB.version unless self[:VERSION]
334     array = []
335     for k, v in sort{|a1, a2| a1[0].id2name <=> a2[0].id2name}
336       case k
337       when :MAIN_CONTEXT, :__TMP__EHV__
338         array.push format("CONF[:%s]=...myself...", k.id2name)
339       when :PROMPT
340         s = v.collect{
341           |kk, vv|
342           ss = vv.collect{|kkk, vvv| ":#{kkk.id2name}=>#{vvv.inspect}"}
343           format(":%s=>{%s}", kk.id2name, ss.join(", "))
344         }
345         array.push format("CONF[:%s]={%s}", k.id2name, s.join(", "))
346       else
347         array.push format("CONF[:%s]=%s", k.id2name, v.inspect)
348       end
349     end
350     array.join("\n")
351   end