1#
2#   irb.rb - irb main module
3#       $Release Version: 0.9.6 $
4#       $Revision: 39075 $
5#       by Keiju ISHITSUKA(keiju@ruby-lang.org)
6#
7# --
8#
9#
10#
11require "e2mmap"
12
13require "irb/init"
14require "irb/context"
15require "irb/extend-command"
16#require "irb/workspace"
17
18require "irb/ruby-lex"
19require "irb/input-method"
20require "irb/locale"
21
22STDOUT.sync = true
23
24# IRB stands for "interactive ruby" and is a tool to interactively execute ruby
25# expressions read from the standard input.
26#
27# The +irb+ command from your shell will start the interpreter.
28#
29# == Usage
30#
31# Use of irb is easy if you know ruby.
32#
33# When executing irb, prompts are displayed as follows. Then, enter the ruby
34# expression. An input is executed when it is syntactically complete.
35#
36#     $ irb
37#     irb(main):001:0> 1+2
38#     #=> 3
39#     irb(main):002:0> class Foo
40#     irb(main):003:1>  def foo
41#     irb(main):004:2>    print 1
42#     irb(main):005:2>  end
43#     irb(main):006:1> end
44#     #=> nil
45#
46# The Readline extension module can be used with irb. Use of Readline is
47# default if it's installed.
48#
49# == Command line options
50#
51#   Usage:  irb.rb [options] [programfile] [arguments]
52#     -f                Suppress read of ~/.irbrc
53#     -m                Bc mode (load mathn, fraction or matrix are available)
54#     -d                Set $DEBUG to true (same as `ruby -d')
55#     -r load-module    Same as `ruby -r'
56#     -I path           Specify $LOAD_PATH directory
57#     -U                Same as `ruby -U`
58#     -E enc            Same as `ruby -E`
59#     -w                Same as `ruby -w`
60#     -W[level=2]       Same as `ruby -W`
61#     --inspect         Use `inspect' for output (default except for bc mode)
62#     --noinspect       Don't use inspect for output
63#     --readline        Use Readline extension module
64#     --noreadline      Don't use Readline extension module
65#     --prompt prompt-mode
66#     --prompt-mode prompt-mode
67#                       Switch prompt mode. Pre-defined prompt modes are
68#                       `default', `simple', `xmp' and `inf-ruby'
69#     --inf-ruby-mode   Use prompt appropriate for inf-ruby-mode on emacs.
70#                       Suppresses --readline.
71#     --simple-prompt   Simple prompt mode
72#     --noprompt        No prompt mode
73#     --tracer          Display trace for each execution of commands.
74#     --back-trace-limit n
75#                       Display backtrace top n and tail n. The default
76#                       value is 16.
77#     --irb_debug n     Set internal debug level to n (not for popular use)
78#     -v, --version     Print the version of irb
79#
80# == Configuration
81#
82# IRB reads from <code>~/.irbrc</code> when it's invoked.
83#
84# If <code>~/.irbrc</code> doesn't exist, +irb+ will try to read in the following order:
85#
86# * +.irbrc+
87# * +irb.rc+
88# * +_irbrc+
89# * <code>$irbrc</code>
90#
91# The following are alternatives to the command line options. To use them type
92# as follows in an +irb+ session:
93#
94#     IRB.conf[:IRB_NAME]="irb"
95#     IRB.conf[:MATH_MODE]=false
96#     IRB.conf[:INSPECT_MODE]=nil
97#     IRB.conf[:IRB_RC] = nil
98#     IRB.conf[:BACK_TRACE_LIMIT]=16
99#     IRB.conf[:USE_LOADER] = false
100#     IRB.conf[:USE_READLINE] = nil
101#     IRB.conf[:USE_TRACER] = false
102#     IRB.conf[:IGNORE_SIGINT] = true
103#     IRB.conf[:IGNORE_EOF] = false
104#     IRB.conf[:PROMPT_MODE] = :DEFALUT
105#     IRB.conf[:PROMPT] = {...}
106#     IRB.conf[:DEBUG_LEVEL]=0
107#
108# === Auto indentation
109#
110# To enable auto-indent mode in irb, add the following to your +.irbrc+:
111#
112#     IRB.conf[:AUTO_INDENT] = true
113#
114# === Autocompletion
115#
116# To enable autocompletion for irb, add the following to your +.irbrc+:
117#
118#     require 'irb/completion'
119#
120# === History
121#
122# By default, irb disables history and will not store any commands you used.
123#
124# If you want to enable history, add the following to your +.irbrc+:
125#
126#     IRB.conf[:SAVE_HISTORY] = 1000
127#
128# This will now store the last 1000 commands in <code>~/.irb_history</code>.
129#
130# See IRB::Context#save_history= for more information.
131#
132# == Customizing the IRB Prompt
133#
134# In order to customize the prompt, you can change the following Hash:
135#
136#     IRB.conf[:PROMPT]
137#
138# This example can be used in your +.irbrc+
139#
140#     IRB.conf[:PROMPT][:MY_PROMPT] = { # name of prompt mode
141#       :AUTO_INDENT => true            # enables auto-indent mode
142#       :PROMPT_I => nil,		# normal prompt
143#       :PROMPT_S => nil,		# prompt for continuated strings
144#       :PROMPT_C => nil,		# prompt for continuated statement
145#       :RETURN => "    ==>%s\n"	# format to return value
146#     }
147#
148#     IRB.conf[:PROMPT_MODE] = :MY_PROMPT
149#
150# Or, invoke irb with the above prompt mode by:
151#
152#     irb --prompt my-prompt
153#
154# Constants +PROMPT_I+, +PROMPT_S+ and +PROMPT_C+ specify the format. In the
155# prompt specification, some special strings are available:
156#
157#     %N    # command name which is running
158#     %m    # to_s of main object (self)
159#     %M    # inspect of main object (self)
160#     %l    # type of string(", ', /, ]), `]' is inner %w[...]
161#     %NNi  # indent level. NN is degits and means as same as printf("%NNd").
162#           # It can be ommited
163#     %NNn  # line number.
164#     %%    # %
165#
166# For instance, the default prompt mode is defined as follows:
167#
168#     IRB.conf[:PROMPT_MODE][:DEFAULT] = {
169#       :PROMPT_I => "%N(%m):%03n:%i> ",
170#       :PROMPT_S => "%N(%m):%03n:%i%l ",
171#       :PROMPT_C => "%N(%m):%03n:%i* ",
172#       :RETURN => "%s\n" # used to printf
173#     }
174#
175# irb comes with a number of available modes:
176#
177#   # :NULL:
178#   #   :PROMPT_I:
179#   #   :PROMPT_N:
180#   #   :PROMPT_S:
181#   #   :PROMPT_C:
182#   #   :RETURN: |
183#   #     %s
184#   # :DEFAULT:
185#   #   :PROMPT_I: ! '%N(%m):%03n:%i> '
186#   #   :PROMPT_N: ! '%N(%m):%03n:%i> '
187#   #   :PROMPT_S: ! '%N(%m):%03n:%i%l '
188#   #   :PROMPT_C: ! '%N(%m):%03n:%i* '
189#   #   :RETURN: |
190#   #     => %s
191#   # :CLASSIC:
192#   #   :PROMPT_I: ! '%N(%m):%03n:%i> '
193#   #   :PROMPT_N: ! '%N(%m):%03n:%i> '
194#   #   :PROMPT_S: ! '%N(%m):%03n:%i%l '
195#   #   :PROMPT_C: ! '%N(%m):%03n:%i* '
196#   #   :RETURN: |
197#   #     %s
198#   # :SIMPLE:
199#   #   :PROMPT_I: ! '>> '
200#   #   :PROMPT_N: ! '>> '
201#   #   :PROMPT_S:
202#   #   :PROMPT_C: ! '?> '
203#   #   :RETURN: |
204#   #     => %s
205#   # :INF_RUBY:
206#   #   :PROMPT_I: ! '%N(%m):%03n:%i> '
207#   #   :PROMPT_N:
208#   #   :PROMPT_S:
209#   #   :PROMPT_C:
210#   #   :RETURN: |
211#   #     %s
212#   #   :AUTO_INDENT: true
213#   # :XMP:
214#   #   :PROMPT_I:
215#   #   :PROMPT_N:
216#   #   :PROMPT_S:
217#   #   :PROMPT_C:
218#   #   :RETURN: |2
219#   #         ==>%s
220#
221# == Restrictions
222#
223# Because irb evaluates input immediately after it is syntactically complete,
224# the results may be slightly different than directly using ruby.
225#
226# == IRB Sessions
227#
228# IRB has a special feature, that allows you to manage many sessions at once.
229#
230# You can create new sessions with Irb.irb, and get a list of current sessions
231# with the +jobs+ command in the prompt.
232#
233# === Commands
234#
235# JobManager provides commands to handle the current sessions:
236#
237#   jobs    # List of current sessions
238#   fg      # Switches to the session of the given number
239#   kill    # Kills the session with the given number
240#
241# The +exit+ command, or ::irb_exit, will quit the current session and call any
242# exit hooks with IRB.irb_at_exit.
243#
244# A few commands for loading files within the session are also available:
245#
246# +source+::
247#   Loads a given file in the current session and displays the source lines,
248#   see IrbLoader#source_file
249# +irb_load+::
250#   Loads the given file similarly to Kernel#load, see IrbLoader#irb_load
251# +irb_require+::
252#   Loads the given file similarly to Kernel#require
253#
254# === Configuration
255#
256# The command line options, or IRB.conf, specify the default behavior of
257# Irb.irb.
258#
259# On the other hand, each conf in IRB@Command+line+options is used to
260# individually configure IRB.irb.
261#
262# If a proc is set for IRB.conf[:IRB_RC], its will be invoked after execution
263# of that proc with the context of the current session as its argument. Each
264# session can be configured using this mechanism.
265#
266# === Session variables
267#
268# There are a few variables in every Irb session that can come in handy:
269#
270# <code>_</code>::
271#   The value command executed, as a local variable
272# <code>__</code>::
273#   The history of evaluated commands
274# <code>__[line_no]</code>::
275#   Returns the evaluation value at the given line number, +line_no+.
276#   If +line_no+ is a negative, the return value +line_no+ many lines before
277#   the most recent return value.
278#
279# === Example using IRB Sessions
280#
281#   # invoke a new session
282#   irb(main):001:0> irb
283#   # list open sessions
284#   irb.1(main):001:0> jobs
285#     #0->irb on main (#<Thread:0x400fb7e4> : stop)
286#     #1->irb#1 on main (#<Thread:0x40125d64> : running)
287#
288#   # change the active session
289#   irb.1(main):002:0> fg 0
290#   # define class Foo in top-level session
291#   irb(main):002:0> class Foo;end
292#   # invoke a new session with the context of Foo
293#   irb(main):003:0> irb Foo
294#   # define Foo#foo
295#   irb.2(Foo):001:0> def foo
296#   irb.2(Foo):002:1>   print 1
297#   irb.2(Foo):003:1> end
298#
299#   # change the active session
300#   irb.2(Foo):004:0> fg 0
301#   # list open sessions
302#   irb(main):004:0> jobs
303#     #0->irb on main (#<Thread:0x400fb7e4> : running)
304#     #1->irb#1 on main (#<Thread:0x40125d64> : stop)
305#     #2->irb#2 on Foo (#<Thread:0x4011d54c> : stop)
306#   # check if Foo#foo is available
307#   irb(main):005:0> Foo.instance_methods #=> [:foo, ...]
308#
309#   # change the active sesssion
310#   irb(main):006:0> fg 2
311#   # define Foo#bar in the context of Foo
312#   irb.2(Foo):005:0> def bar
313#   irb.2(Foo):006:1>  print "bar"
314#   irb.2(Foo):007:1> end
315#   irb.2(Foo):010:0>  Foo.instance_methods #=> [:bar, :foo, ...]
316#
317#   # change the active session
318#   irb.2(Foo):011:0> fg 0
319#   irb(main):007:0> f = Foo.new  #=> #<Foo:0x4010af3c>
320#   # invoke a new session with the context of f (instance of Foo)
321#   irb(main):008:0> irb f
322#   # list open sessions
323#   irb.3(<Foo:0x4010af3c>):001:0> jobs
324#     #0->irb on main (#<Thread:0x400fb7e4> : stop)
325#     #1->irb#1 on main (#<Thread:0x40125d64> : stop)
326#     #2->irb#2 on Foo (#<Thread:0x4011d54c> : stop)
327#     #3->irb#3 on #<Foo:0x4010af3c> (#<Thread:0x4010a1e0> : running)
328#   # evaluate f.foo
329#   irb.3(<Foo:0x4010af3c>):002:0> foo #=> 1 => nil
330#   # evaluate f.bar
331#   irb.3(<Foo:0x4010af3c>):003:0> bar #=> bar => nil
332#   # kill jobs 1, 2, and 3
333#   irb.3(<Foo:0x4010af3c>):004:0> kill 1, 2, 3
334#   # list open sesssions, should only include main session
335#   irb(main):009:0> jobs
336#     #0->irb on main (#<Thread:0x400fb7e4> : running)
337#   # quit irb
338#   irb(main):010:0> exit
339module IRB
340  @RCS_ID='-$Id: irb.rb 39075 2013-02-05 15:57:19Z zzak $-'
341
342  # An exception raised by IRB.irb_abort
343  class Abort < Exception;end
344
345  @CONF = {}
346
347
348  # Displays current configuration.
349  #
350  # Modifing the configuration is achieved by sending a message to IRB.conf.
351  #
352  # See IRB@Configuration for more information.
353  def IRB.conf
354    @CONF
355  end
356
357  # Returns the current version of IRB, including release version and last
358  # updated date.
359  def IRB.version
360    if v = @CONF[:VERSION] then return v end
361
362    require "irb/version"
363    rv = @RELEASE_VERSION.sub(/\.0/, "")
364    @CONF[:VERSION] = format("irb %s(%s)", rv, @LAST_UPDATE_DATE)
365  end
366
367  # The current IRB::Context of the session, see IRB.conf
368  #
369  #   irb
370  #   irb(main):001:0> IRB.CurrentContext.irb_name = "foo"
371  #   foo(main):002:0> IRB.conf[:MAIN_CONTEXT].irb_name #=> "foo"
372  def IRB.CurrentContext
373    IRB.conf[:MAIN_CONTEXT]
374  end
375
376  # Initializes IRB and creates a new Irb.irb object at the +TOPLEVEL_BINDING+
377  def IRB.start(ap_path = nil)
378    $0 = File::basename(ap_path, ".rb") if ap_path
379
380    IRB.setup(ap_path)
381
382    if @CONF[:SCRIPT]
383      irb = Irb.new(nil, @CONF[:SCRIPT])
384    else
385      irb = Irb.new
386    end
387
388    @CONF[:IRB_RC].call(irb.context) if @CONF[:IRB_RC]
389    @CONF[:MAIN_CONTEXT] = irb.context
390
391    trap("SIGINT") do
392      irb.signal_handle
393    end
394
395    begin
396      catch(:IRB_EXIT) do
397        irb.eval_input
398      end
399    ensure
400      irb_at_exit
401    end
402#    print "\n"
403  end
404
405  # Calls each event hook of IRB.conf[:AT_EXIT] when the current session quits.
406  def IRB.irb_at_exit
407    @CONF[:AT_EXIT].each{|hook| hook.call}
408  end
409
410  # Quits irb
411  def IRB.irb_exit(irb, ret)
412    throw :IRB_EXIT, ret
413  end
414
415  # Aborts then interrupts irb.
416  #
417  # Will raise an Abort exception, or the given +exception+.
418  def IRB.irb_abort(irb, exception = Abort)
419    if defined? Thread
420      irb.context.thread.raise exception, "abort then interrupt!"
421    else
422      raise exception, "abort then interrupt!"
423    end
424  end
425
426  class Irb
427    # Creates a new irb session
428    def initialize(workspace = nil, input_method = nil, output_method = nil)
429      @context = Context.new(self, workspace, input_method, output_method)
430      @context.main.extend ExtendCommandBundle
431      @signal_status = :IN_IRB
432
433      @scanner = RubyLex.new
434      @scanner.exception_on_syntax_error = false
435    end
436    # Returns the current context of this irb session
437    attr_reader :context
438    # The lexer used by this irb session
439    attr_accessor :scanner
440
441    # Evaluates input for this session.
442    def eval_input
443      @scanner.set_prompt do
444        |ltype, indent, continue, line_no|
445        if ltype
446          f = @context.prompt_s
447        elsif continue
448          f = @context.prompt_c
449        elsif indent > 0
450          f = @context.prompt_n
451        else
452          f = @context.prompt_i
453        end
454        f = "" unless f
455        if @context.prompting?
456          @context.io.prompt = p = prompt(f, ltype, indent, line_no)
457        else
458          @context.io.prompt = p = ""
459        end
460        if @context.auto_indent_mode
461          unless ltype
462            ind = prompt(@context.prompt_i, ltype, indent, line_no)[/.*\z/].size +
463              indent * 2 - p.size
464            ind += 2 if continue
465            @context.io.prompt = p + " " * ind if ind > 0
466          end
467        end
468      end
469
470      @scanner.set_input(@context.io) do
471        signal_status(:IN_INPUT) do
472          if l = @context.io.gets
473            print l if @context.verbose?
474          else
475            if @context.ignore_eof? and @context.io.readable_after_eof?
476              l = "\n"
477              if @context.verbose?
478                printf "Use \"exit\" to leave %s\n", @context.ap_name
479              end
480            else
481              print "\n"
482            end
483          end
484          l
485        end
486      end
487
488      @scanner.each_top_level_statement do |line, line_no|
489        signal_status(:IN_EVAL) do
490          begin
491            line.untaint
492            @context.evaluate(line, line_no)
493            output_value if @context.echo?
494            exc = nil
495          rescue Interrupt => exc
496          rescue SystemExit, SignalException
497            raise
498          rescue Exception => exc
499          end
500          if exc
501            print exc.class, ": ", exc, "\n"
502            if exc.backtrace[0] =~ /irb(2)?(\/.*|-.*|\.rb)?:/ && exc.class.to_s !~ /^IRB/ &&
503                !(SyntaxError === exc)
504              irb_bug = true
505            else
506              irb_bug = false
507            end
508
509            messages = []
510            lasts = []
511            levels = 0
512            for m in exc.backtrace
513              m = @context.workspace.filter_backtrace(m) unless irb_bug
514              if m
515                if messages.size < @context.back_trace_limit
516                  messages.push "\tfrom "+m
517                else
518                  lasts.push "\tfrom "+m
519                  if lasts.size > @context.back_trace_limit
520                    lasts.shift
521                    levels += 1
522                  end
523                end
524              end
525            end
526            print messages.join("\n"), "\n"
527            unless lasts.empty?
528              printf "... %d levels...\n", levels if levels > 0
529              print lasts.join("\n")
530            end
531            print "Maybe IRB bug!\n" if irb_bug
532          end
533          if $SAFE > 2
534            abort "Error: irb does not work for $SAFE level higher than 2"
535          end
536        end
537      end
538    end
539
540    # Evaluates the given block using the given +path+ as the Context#irb_path
541    # and +name+ as the Context#irb_name.
542    #
543    # Used by the irb command +source+, see IRB@IRB+Sessions for more
544    # information.
545    def suspend_name(path = nil, name = nil)
546      @context.irb_path, back_path = path, @context.irb_path if path
547      @context.irb_name, back_name = name, @context.irb_name if name
548      begin
549        yield back_path, back_name
550      ensure
551        @context.irb_path = back_path if path
552        @context.irb_name = back_name if name
553      end
554    end
555
556    # Evaluates the given block using the given +workspace+ as the
557    # Context#workspace.
558    #
559    # Used by the irb command +irb_load+, see IRB@IRB+Sessions for more
560    # information.
561    def suspend_workspace(workspace)
562      @context.workspace, back_workspace = workspace, @context.workspace
563      begin
564        yield back_workspace
565      ensure
566        @context.workspace = back_workspace
567      end
568    end
569
570    # Evaluates the given block using the given +input_method+ as the
571    # Context#io.
572    #
573    # Used by the irb commands +source+ and +irb_load+, see IRB@IRB+Sessions
574    # for more information.
575    def suspend_input_method(input_method)
576      back_io = @context.io
577      @context.instance_eval{@io = input_method}
578      begin
579        yield back_io
580      ensure
581        @context.instance_eval{@io = back_io}
582      end
583    end
584
585    # Evaluates the given block using the given +context+ as the Context.
586    def suspend_context(context)
587      @context, back_context = context, @context
588      begin
589        yield back_context
590      ensure
591        @context = back_context
592      end
593    end
594
595    # Handler for the signal SIGINT, see Kernel#trap for more information.
596    def signal_handle
597      unless @context.ignore_sigint?
598        print "\nabort!\n" if @context.verbose?
599        exit
600      end
601
602      case @signal_status
603      when :IN_INPUT
604        print "^C\n"
605        raise RubyLex::TerminateLineInput
606      when :IN_EVAL
607        IRB.irb_abort(self)
608      when :IN_LOAD
609        IRB.irb_abort(self, LoadAbort)
610      when :IN_IRB
611        # ignore
612      else
613        # ignore other cases as well
614      end
615    end
616
617    # Evaluates the given block using the given +status+.
618    def signal_status(status)
619      return yield if @signal_status == :IN_LOAD
620
621      signal_status_back = @signal_status
622      @signal_status = status
623      begin
624        yield
625      ensure
626        @signal_status = signal_status_back
627      end
628    end
629
630    def prompt(prompt, ltype, indent, line_no) # :nodoc:
631      p = prompt.dup
632      p.gsub!(/%([0-9]+)?([a-zA-Z])/) do
633        case $2
634        when "N"
635          @context.irb_name
636        when "m"
637          @context.main.to_s
638        when "M"
639          @context.main.inspect
640        when "l"
641          ltype
642        when "i"
643          if $1
644            format("%" + $1 + "d", indent)
645          else
646            indent.to_s
647          end
648        when "n"
649          if $1
650            format("%" + $1 + "d", line_no)
651          else
652            line_no.to_s
653          end
654        when "%"
655          "%"
656        end
657      end
658      p
659    end
660
661    def output_value # :nodoc:
662      printf @context.return_format, @context.inspect_last_value
663    end
664
665    # Outputs the local variables to this current session, including
666    # #signal_status and #context, using IRB::Locale.
667    def inspect
668      ary = []
669      for iv in instance_variables
670        case (iv = iv.to_s)
671        when "@signal_status"
672          ary.push format("%s=:%s", iv, @signal_status.id2name)
673        when "@context"
674          ary.push format("%s=%s", iv, eval(iv).__to_s__)
675        else
676          ary.push format("%s=%s", iv, eval(iv))
677        end
678      end
679      format("#<%s: %s>", self.class, ary.join(", "))
680    end
681  end
682
683  def @CONF.inspect
684    IRB.version unless self[:VERSION]
685
686    array = []
687    for k, v in sort{|a1, a2| a1[0].id2name <=> a2[0].id2name}
688      case k
689      when :MAIN_CONTEXT, :__TMP__EHV__
690        array.push format("CONF[:%s]=...myself...", k.id2name)
691      when :PROMPT
692        s = v.collect{
693          |kk, vv|
694          ss = vv.collect{|kkk, vvv| ":#{kkk.id2name}=>#{vvv.inspect}"}
695          format(":%s=>{%s}", kk.id2name, ss.join(", "))
696        }
697        array.push format("CONF[:%s]={%s}", k.id2name, s.join(", "))
698      else
699        array.push format("CONF[:%s]=%s", k.id2name, v.inspect)
700      end
701    end
702    array.join("\n")
703  end
704end
705