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