DebugClients/Ruby/Debuggee.rb

changeset 0
de9c2efb9d02
child 13
1af94a91f439
diff -r 000000000000 -r de9c2efb9d02 DebugClients/Ruby/Debuggee.rb
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/DebugClients/Ruby/Debuggee.rb	Mon Dec 28 16:03:33 2009 +0000
@@ -0,0 +1,1208 @@
+# -*- coding: utf-8 -*-
+
+# Copyright (c) 2005 - 2009 Detlev Offenbach <detlev@die-offenbachs.de>
+#
+
+# Debuggee.rb is based in parts on debug.rb from Ruby and debuggee.rb.
+# Original copyrights of these files follow below.
+#
+# debug.rb
+# Copyright (C) 2000  Network Applied Communication Laboratory, Inc.
+# Copyright (C) 2000  Information-technology Promotion Agency, Japan
+#
+# debuggee.rb
+# Copyright (c) 2000 NAKAMURA, Hiroshi
+
+=begin edoc
+File implementing the real debugger, which is connected to the IDE frontend.
+=end
+
+require 'DebugQuit'
+require 'rbconfig'
+
+class DEBUGGER__
+=begin edoc
+Class implementing the real debugger.
+=end
+    class Mutex
+=begin edoc
+Class implementing a mutex.
+=end
+        def initialize
+=begin edoc
+Constructor
+=end
+            @locker = nil
+            @waiting = []
+            @locked = false;
+        end
+
+        def locked?
+=begin edoc
+Method returning the locked state.
+
+@return flag indicating the locked state (boolean)
+=end
+            @locked
+        end
+
+        def lock
+=begin edoc
+Method to lock the mutex.
+
+@return the mutex
+=end
+            return if @locker == Thread.current
+            while (Thread.critical = true; @locked)
+                @waiting.push Thread.current
+                Thread.stop
+            end
+            @locked = true
+            @locker = Thread.current
+            Thread.critical = false
+            self
+        end
+
+        def unlock
+=begin edoc
+Method to unlock the mutex.
+
+@return the mutex
+=end
+            return unless @locked
+            unless @locker == Thread.current
+                raise RuntimeError, "unlocked by other"
+            end
+            Thread.critical = true
+            t = @waiting.shift
+            @locked = false
+            @locker = nil
+            Thread.critical = false
+            t.run if t
+            self
+        end
+    end
+    MUTEX = Mutex.new
+
+    class Context
+=begin edoc
+Class defining the current execution context.
+=end
+        def initialize
+=begin edoc
+Constructor
+=end
+            if Thread.current == Thread.main
+                @stop_next = 1
+            else
+                @stop_next = 0
+            end
+            @last_file = nil
+            @file = nil
+            @line = nil
+            @no_step = nil
+            @frames = []
+            @frame_pos = 0 #LJ - for FR
+            @finish_pos = 0
+            @trace = false
+            @catch = ["StandardError"] #LJ - for FR
+            @suspend_next = false
+        end
+
+        def stop_next(n=1)
+=begin edoc
+Method to set the next stop point (i.e. stop at next line).
+
+@param counter defining the stop point (int)
+=end
+            @stop_next = n
+        end
+
+        def step_over(n=1)
+=begin edoc
+Method to set the next stop point skipping function calls.
+
+@param counter defining the stop point (int)
+=end
+            @stop_next = n
+            @no_step = @frames.size - @frame_pos
+        end
+    
+        def step_out
+=begin edoc
+Method to set the next stop point after the function call returns.
+=end
+            if @frame_pos != @frames.size
+                @finish_pos = @frames.size - @frame_pos
+                @frame_pos = 0
+                @stop_next -= 1
+            end
+        end
+    
+        def step_continue
+=begin edoc
+Method to continue execution until next breakpoint or watch expression.
+=end
+            @stop_next = 1
+            @no_step = -1
+        end
+    
+        def step_quit
+=begin edoc
+Method to stop debugging.
+=end
+            raise DebugQuit.new
+        end
+    
+        def set_suspend
+=begin edoc
+Method to suspend all threads.
+=end
+            @suspend_next = true
+        end
+
+        def clear_suspend
+=begin edoc
+Method to clear the suspend state.
+=end
+            @suspend_next = false
+        end
+
+        def suspend_all
+=begin edoc
+Method to suspend all threads.
+=end
+            DEBUGGER__.suspend
+        end
+
+        def resume_all
+=begin edoc
+Method to resume all threads.
+=end
+            DEBUGGER__.resume
+        end
+
+        def check_suspend
+=begin edoc
+Method to check the suspend state.
+=end
+            while (Thread.critical = true; @suspend_next)
+                DEBUGGER__.waiting.push Thread.current
+                @suspend_next = false
+                Thread.stop
+            end
+            Thread.critical = false
+        end
+
+        def stdout
+=begin edoc
+Method returning the stdout object.
+
+@return reference to the stdout object
+=end
+            DEBUGGER__.stdout
+        end
+
+        def break_points
+=begin edoc
+Method to return the list of breakpoints
+
+@return Array containing all breakpoints.
+=end
+            DEBUGGER__.break_points
+        end
+
+        def context(th)
+=begin edoc
+Method returning the context of a thread.
+
+@param th thread object to get the context for
+@return the context for the thread
+=end
+            DEBUGGER__.context(th)
+        end
+
+        def attached?
+=begin edoc
+Method returning the attached state.
+
+@return flag indicating, whether the debugger is attached to the IDE.
+=end
+            DEBUGGER__.attached?
+        end
+
+        def set_last_thread(th)
+=begin edoc
+Method to remember the last thread.
+
+@param th thread to be remembered.
+=end
+            DEBUGGER__.set_last_thread(th)
+        end
+
+        def debug_silent_eval(str, binding_)
+=begin edoc
+Method to eval a string without output.
+
+@param str String containing the expression to be evaluated
+@param binding_ the binding for the evaluation
+@return the result of the evaluation
+=end
+            val = eval(str, binding_)
+            val
+        end
+
+        def thnum
+=begin edoc
+Method returning the thread number of the current thread.
+
+@return thread number of the current thread.
+=end
+            num = DEBUGGER__.instance_eval{@thread_list[Thread.current]}
+            unless num
+                DEBUGGER__.make_thread_list
+                num = DEBUGGER__.instance_eval{@thread_list[Thread.current]}
+            end
+            num
+        end
+
+        def debug_command(file, line, id, binding_)
+=begin edoc
+Method to execute the next debug command.
+=end
+            MUTEX.lock
+            set_last_thread(Thread.current)
+            unless attached?
+                MUTEX.unlock
+                resume_all
+                return
+            end
+            @frame_pos = 0
+            @frames[0] = [binding_, file, line, id]
+            stdout.printf_line(@frames)
+            MUTEX.unlock
+            resume_all
+            eventLoop
+        end
+
+        def frame_set_pos(file, line)
+=begin edoc
+Method to set the frame position of the current frame.
+=end
+            if @frames[0]
+                @frames[0][1] = file
+                @frames[0][2] = line
+            end
+        end
+
+        def check_break_points(file, pos, binding_, id)
+=begin edoc
+Method to check, if the given position contains an active breakpoint.
+
+@param file filename containing the currently executed line (String)
+@param pos line number currently executed (int)
+@param binding_ current binding object
+@param id (ignored)
+@return flag indicating an active breakpoint (boolean)
+=end
+            # bp[0] enabled flag
+            # bp[1] 0 = breakpoint, 1 = watch expression
+            # bp[2] filename
+            # bp[3] linenumber
+            # bp[4] temporary flag
+            # bp[5] condition
+            # bp[6] ignore count
+            # bp[7] special condition
+            # bp[8] hash of special values
+            return false if break_points.empty?
+            for b in break_points
+                if b[0]
+                    if b[1] == 0 and b[2] == file and b[3] == pos   # breakpoint
+                        # Evaluate condition
+                        if b[5]
+                            begin
+                                if debug_silent_eval(b[5], binding_)
+                                    if b[6] == 0    # ignore count reached
+                                        # Delete once reached if temporary breakpoint
+                                        clear_break_point(file, pos) if b[4]
+                                        return true
+                                    else
+                                        b[6] -= 1
+                                    end
+                                end
+                            rescue StandardError, ScriptError
+                                nil
+                            end
+                        else
+                            if b[6] == 0    # ignore count reached
+                                # Delete once reached if temporary breakpoint
+                                clear_break_point(file, pos) if b[4]
+                                return true
+                            else
+                                b[6] -= 1
+                            end
+                        end
+                    elsif b[1] == 1                                 # watch expression
+                        begin
+                            bd = @frame_pos
+                            val = debug_silent_eval(b[5], binding_)
+                            if b[7].length() > 0
+                                if b[7] == "??created??"
+                                    if b[8][bd][0] == false
+                                        b[8][bd][0] = true
+                                        b[8][bd][1] = val
+                                        return true
+                                    else
+                                        next
+                                    end
+                                end
+                                b[8][bd][0] = true
+                                if b[7] == "??changed??"
+                                    if b[8][bd][1] != val
+                                        b[8][bd][1] = val
+                                        if b[8][bd][2] > 0
+                                            b[8][bd][2] -= 1
+                                            next
+                                        else
+                                            return true
+                                        end
+                                    else
+                                        next
+                                    end
+                                end
+                                next
+                            end
+                            if val
+                                if b[6] == 0    # ignore count reached
+                                    # Delete once reached if temporary breakpoint
+                                    clear_watch_point(b[2]) if b[4]
+                                    return true
+                                else
+                                    b[6] -= 1
+                                end
+                            end
+                        rescue StandardError, ScriptError
+                            if b[7].length() > 0
+                                if b[8][bd]
+                                    b[8][bd][0] = false
+                                else
+                                    b[8][bd] = [false, nil, b[6]]
+                                end
+                            else
+                                val = nil
+                            end
+                        end
+                    end
+                end
+            end
+            return false
+        end
+
+        def clear_break_point(file, pos)
+=begin edoc
+Method to delete a specific breakpoint.
+
+@param file filename containing the breakpoint (String)
+@param pos line number containing the breakpoint (int)
+=end
+            delete_break_point(file, pos)
+            stdout.printf_clear_breakpoint(file, pos)
+        end
+    
+        def add_break_point(file, pos, temp = false, cond = nil)
+=begin edoc
+Method to add a breakpoint.
+
+@param file filename for the breakpoint (String)
+@param pos line number for the breakpoint (int)
+@param temp flag indicating a temporary breakpoint (boolean)
+@param cond condition of a conditional breakpoint (String)
+=end
+            break_points.push [true, 0, file, pos, temp, cond, 0]
+        end
+
+        def delete_break_point(file, pos)
+=begin edoc
+Method to delete a breakpoint.
+
+@param file filename of the breakpoint (String)
+@param pos line number of the breakpoint (int)
+=end
+            break_points.delete_if { |bp|
+                bp[1] == 0 and bp[2] == file and bp[3] == pos
+            }
+        end
+
+        def enable_break_point(file, pos, enable)
+=begin edoc
+Method to set the enabled state of a breakpoint.
+
+@param file filename of the breakpoint (String)
+@param pos line number of the breakpoint (int)
+@param enable flag indicating the new enabled state (boolean)
+=end
+            for bp in break_points
+                if (bp[1] == 0 and bp[2] == file and bp[3] == pos)
+                    bp[0] = enable 
+                    break
+                end
+            end
+        end
+
+        def ignore_break_point(file, pos, count)
+=begin edoc
+Method to set the ignore count of a breakpoint.
+
+@param file filename of the breakpoint (String)
+@param pos line number of the breakpoint (int)
+@param count ignore count to be set (int)
+=end
+            for bp in break_points
+                if (bp[2] == file and bp[3] == pos)
+                    bp[6] = count 
+                    break
+                end
+            end
+        end
+
+        def clear_watch_point(cond)
+=begin edoc
+Method to delete a specific watch expression.
+
+@param cond expression specifying the watch expression (String)
+=end
+            delete_watch_point(cond)
+            stdout.printf_clear_watchexpression(cond)
+        end
+    
+        def add_watch_point(cond, temp = false)
+=begin edoc
+Method to add a watch expression.
+
+@param cond expression of the watch expression (String)
+@param temp flag indicating a temporary watch expression (boolean)
+=end
+            co1, co2 = cond.split()
+            if co2 == "??created??" or co2 == "??changed??"
+                break_points.push [true, 1, cond, 0, temp, co1, 0, co2, {}]
+            else
+                break_points.push [true, 1, cond, 0, temp, cond, 0, "", {}]
+            end
+        end
+    
+        def delete_watch_point(cond)
+=begin edoc
+Method to delete a watch expression.
+
+@param cond expression of the watch expression (String)
+=end
+            break_points.delete_if { |bp|
+                bp[1] == 1 and bp[2] == cond
+            }
+        end
+    
+        def enable_watch_point(cond, enable)
+=begin edoc
+Method to set the enabled state of a watch expression.
+
+@param cond expression of the watch expression (String)
+@param enable flag indicating the new enabled state (boolean)
+=end
+            for bp in break_points
+                if (bp[1] == 1 and bp[2] == cond)
+                    bp[0] = enable
+                    break
+                end
+            end
+        end
+    
+        def ignore_watch_point(cond, count)
+=begin edoc
+Method to set the ignore count of a watch expression.
+
+@param cond expression of the watch expression (String)
+@param count ignore count to be set (int)
+=end
+            for bp in break_points
+                if (bp[1] == 1 and bp[2] == cond)
+                    bp[6] = count
+                    break
+                end
+            end
+        end
+    
+        def excn_handle(file, line, id, binding_)
+=begin edoc
+Method to handle an exception
+
+@param file filename containing the currently executed line (String)
+@param pos line number currently executed (int)
+@param id (ignored)
+@param binding_ current binding object
+=end
+            if $!.class <= SystemExit
+                set_trace_func nil
+                stdout.printf_exit($!.status)
+                return
+            elsif $!.class <= ScriptError
+                msgParts = $!.message.split(":", 3)
+                filename = File.expand_path(msgParts[0])
+                linenr = msgParts[1].to_i
+                exclist = ["", [filename, linenr, 0]]
+                stdout.printf_scriptExcn(exclist)
+            else
+                exclist = ["%s" % $!.class, "%s" % $!, [file, line]]
+                @frames.each do |_binding, _file, _line, _id|
+                    next if [_file, _line] == exclist[-1]
+                    exclist << [_file, _line]
+                end
+                stdout.printf_excn(exclist)
+            end
+            debug_command(file, line, id, binding_)
+        end
+
+        def skip_it?(file)
+=begin edoc
+Method to filter out debugger files.
+
+Tracing is turned off for files that are part of the
+debugger that are called from the application being debugged.
+
+@param file name of the file to be checked (String)
+@return flag indicating, whether the file should be skipped (boolean)
+=end
+            if file =~ /\(eval\)/
+                return true
+            end
+           
+            if not traceRuby? and
+               (file =~ /#{Config::CONFIG['sitelibdir']}/ or
+                file =~ /#{Config::CONFIG['rubylibdir']}/)
+                return true
+            end
+            
+            if ["AsyncFile.rb", "AsyncIO.rb", "Config.rb", "DebugClient.rb",
+                "DebugClientBaseModule.rb", "DebugClientCapabilities.rb",
+                "DebugProtocol.rb", "DebugQuit.rb", "Debuggee.rb"].include?(\
+                    File.basename(file))
+                return true
+            end
+            return false
+        end
+    
+        def trace_func(event, file, line, id, binding_, klass)
+=begin edoc
+Method executed by the tracing facility.
+
+@param event the tracing event (String)
+@param file the name of the file being traced (String)
+@param line the line number being traced (int)
+@param id object id
+@param binding_ a binding object
+@param klass name of a class
+=end
+            context(Thread.current).check_suspend
+          
+            if skip_it?(file) and not ["call","return"].include?(event)
+                case event
+                when 'line'
+                    frame_set_pos(file, line)
+                    
+                when 'call'
+                    @frames.unshift [binding_, file, line, id]
+                
+                when 'c-call'
+                    frame_set_pos(file, line)
+            
+                when 'class'
+                    @frames.unshift [binding_, file, line, id]
+                    
+                when 'return', 'end'
+                    @frames.shift
+        
+                when 'end'
+                    @frames.shift
+        
+                when 'raise' 
+                    excn_handle(file, line, id, binding_)
+                    
+                end
+                @last_file = file
+                return
+            end
+        
+            @file = file
+            @line = line
+            
+            case event
+            when 'line'
+                frame_set_pos(file, line)
+                eventPoll
+                if !@no_step or @frames.size == @no_step
+                    @stop_next -= 1
+                    @stop_next = -1 if @stop_next < 0
+                elsif @frames.size < @no_step
+                    @stop_next = 0        # break here before leaving...
+                else
+                    # nothing to do. skipped.
+                end
+                if check_break_points(file, line, binding_, id) or @stop_next == 0 
+                    @no_step = nil
+                    suspend_all
+                    debug_command(file, line, id, binding_)
+                end
+    
+            when 'call'
+                @frames.unshift [binding_, file, line, id]
+                if check_break_points(file, id.id2name, binding_, id) or
+                    check_break_points(klass.to_s, id.id2name, binding_, id)
+                    suspend_all
+                    debug_command(file, line, id, binding_)
+                end
+    
+            when 'c-call'
+                frame_set_pos(file, line)
+                if id == :require and klass == Kernel
+                    @frames.unshift [binding_, file, line, id]
+                else
+                    frame_set_pos(file, line)
+                end
+        
+            when 'c-return'
+                if id == :require and klass == Kernel
+                    if @frames.size == @finish_pos
+                        @stop_next = 1
+                        @finish_pos = 0
+                    end
+                    @frames.shift
+                end
+    
+            when 'class'
+                @frames.unshift [binding_, file, line, id]
+    
+            when 'return', 'end'
+                if @frames.size == @finish_pos
+                    @stop_next = 1
+                    @finish_pos = 0
+                end
+                @frames.shift
+    
+            when 'end'
+                @frames.shift
+    
+            when 'raise'
+                @no_step = nil
+                @stop_next = 0        # break here before leaving...
+                excn_handle(file, line, id, binding_)
+    
+            end
+            @last_file = file
+        end
+    end
+
+    trap("INT") { DEBUGGER__.interrupt }
+    @last_thread = Thread::main
+    @max_thread = 1
+    @thread_list = {Thread::main => 1}
+    @break_points = []
+    @waiting = []
+    @stdout = STDOUT
+    @loaded_files = {}
+
+    class SilentObject
+=begin edoc
+Class defining an object that ignores all messages.
+=end
+        def method_missing( msg_id, *a, &b )
+=begin edoc
+Method invoked for all messages it cannot handle.
+
+@param msg_id symbol for the method called
+@param *a arguments passed to the missing method
+@param &b unknown
+=end
+        end
+    end
+    SilentClient = SilentObject.new()
+    @client = SilentClient
+    @attached = false
+
+    class <<DEBUGGER__
+=begin edoc
+Class defining a singleton object for the debugger.
+=end
+        def stdout
+=begin edoc
+Method returning the stdout object.
+
+@return reference to the stdout object
+=end
+            @stdout
+        end
+
+        def stdout=(s)
+=begin edoc
+Method to set the stdout object.
+
+@param s reference to the stdout object
+=end
+            @stdout = s
+        end
+
+        def break_points
+=begin edoc
+Method to return the list of breakpoints
+
+@return Array containing all breakpoints.
+=end
+            @break_points
+        end
+
+        def last_thread
+=begin edoc
+Method returning the last active thread.
+
+@return active thread
+=end
+            @last_thread
+        end
+
+        def attach( debugger )
+=begin edoc
+Method to connect the debugger to the IDE.
+
+@param debugger reference to the object handling the
+    communication with the IDE.
+=end
+            unless @attached
+                set_client( debugger )
+                @attached = true
+                interrupt
+            else
+                false
+            end
+        end
+
+        def client
+=begin edoc
+Method returning a reference to the client object.
+
+@return reference to the client object.
+=end
+            @client
+        end
+
+        def set_client( debugger )
+=begin edoc
+Method to set the client handling the connection.
+
+@param debugger reference to the object handling the connection
+=end
+            @client = Client.new( debugger )
+            DEBUGGER__.stdout = @client
+        end
+
+        def attached?
+=begin edoc
+Method returning the attached state.
+
+@return flag indicating, whether the debugger is attached to the IDE.
+=end
+            @attached
+        end
+
+        def quit(status = 0)
+=begin edoc
+Method to quit the debugger.
+
+@param status exit status of the program
+=end
+            @client.printf_exit(status)
+            STDERR.flush; STDOUT.flush
+        end
+
+        def waiting
+=begin edoc
+Method returning the waiting list.
+
+@return the waiting list
+=end
+            @waiting
+        end
+
+        def set_last_thread(th)
+=begin edoc
+Method to remember the last thread.
+
+@param th thread to be remembered.
+=end
+            @last_thread = th
+        end
+
+        def suspend
+=begin edoc
+Method to suspend the program being debugged.
+=end
+            Thread.critical = true
+            make_thread_list
+            for th, in @thread_list
+                next if th == Thread.current
+                context(th).set_suspend
+            end
+            Thread.critical = false
+            # Schedule other threads to suspend as soon as possible.
+            Thread.pass
+        end
+
+        def resume
+=begin edoc
+Method to resume the program being debugged.
+=end
+            Thread.critical = true
+            make_thread_list
+            for th, in @thread_list
+                next if th == Thread.current
+                context(th).clear_suspend
+            end
+            waiting.each do |th|
+                th.run
+            end
+            waiting.clear
+            Thread.critical = false
+            # Schedule other threads to restart as soon as possible.
+            Thread.pass
+        end
+
+        def context(thread=Thread.current)
+=begin edoc
+Method returning the context of a thread.
+
+@param th threat the context is requested for
+@return context object for the thread
+=end
+            c = thread[:__debugger_data__]
+            unless c
+                thread[:__debugger_data__] = c = Context.new
+            end
+            c
+        end
+
+        def interrupt
+=begin edoc
+Method to stop execution at the next instruction.
+=end
+            context(@last_thread).stop_next
+        end
+
+        def get_thread(num)
+=begin edoc
+Method returning a thread by number.
+
+@param num thread number (int)
+@return thread with the requested number
+=end
+            th = @thread_list.index(num)
+            unless th
+                @stdout.print "No thread ##{num}\n"
+                throw :debug_error
+            end
+            th
+            end
+
+        def thread_list(num)
+=begin edoc
+Method to list the state of a thread.
+
+@param num thread number (int)
+=end
+            th = get_thread(num)
+            if th == Thread.current
+                @stdout.print "+"
+            else
+                @stdout.print " "
+            end
+            @stdout.printf "%d ", num
+            @stdout.print th.inspect, "\t"
+            file = context(th).instance_eval{@file}
+            if file
+                @stdout.print file,":",context(th).instance_eval{@line}
+            end
+            @stdout.print "\n"
+        end
+
+        def thread_list_all
+=begin edoc
+Method to list the state of all threads.
+=end
+            for th in @thread_list.values.sort
+                thread_list(th)
+            end
+        end
+
+        def make_thread_list
+=begin edoc
+Method to create a thread list.
+=end
+            hash = {}
+            for th in Thread::list
+                next if (th[:__debugger_hidden__])
+                if @thread_list.key? th
+                    hash[th] = @thread_list[th]
+                else
+                    @max_thread += 1
+                    hash[th] = @max_thread
+                end
+            end
+            @thread_list = hash
+        end
+
+        def debug_thread_info(input, binding_)
+=begin edoc
+Method handling the thread related debug commands.
+
+@param input debug command (String)
+@param binding_ reference to the binding object
+=end
+            case input
+            when /^l(?:ist)?/
+                make_thread_list
+                thread_list_all
+
+            when /^c(?:ur(?:rent)?)?$/
+                make_thread_list
+                thread_list(@thread_list[Thread.current])
+
+            when /^(?:sw(?:itch)?\s+)?(\d+)/
+                make_thread_list
+                th = get_thread($1.to_i)
+                if th == Thread.current
+                    @stdout.print "It's the current thread.\n"
+                else
+                    thread_list(@thread_list[th])
+                    context(th).stop_next
+                    th.run
+                    return :cont
+                end
+
+            when /^stop\s+(\d+)/
+                make_thread_list
+                th = get_thread($1.to_i)
+                if th == Thread.current
+                    @stdout.print "It's the current thread.\n"
+                elsif th.stop?
+                    @stdout.print "Already stopped.\n"
+                else
+                    thread_list(@thread_list[th])
+                    context(th).suspend 
+                end
+
+            when /^resume\s+(\d+)/
+                make_thread_list
+                th = get_thread($1.to_i)
+                if th == Thread.current
+                    @stdout.print "It's the current thread.\n"
+                elsif !th.stop?
+                    @stdout.print "Already running."
+                else
+                    thread_list(@thread_list[th])
+                    th.run
+                end
+            end
+        end
+    
+        def eventLoop
+=begin edoc
+Method calling the main event loop.
+=end
+            @client.eventLoop
+        end
+    
+        def eventPoll
+=begin edoc
+Method calling the main function polling for an event sent by the IDE.
+=end
+            @client.eventPoll
+        end
+        
+        def traceRuby?
+=begin edoc
+Method to check, if we should trace into the Ruby interpreter libraries.
+=end
+            @client.traceRuby?
+        end
+    end
+
+
+    class Context
+        def eventLoop
+=begin edoc
+Method calling the main event loop.
+=end
+            DEBUGGER__.eventLoop
+        end
+    
+        def eventPoll
+=begin edoc
+Method calling the main function polling for an event sent by the IDE.
+=end
+            DEBUGGER__.eventPoll
+        end
+        
+        def traceRuby?
+=begin edoc
+Method to check, if we should trace into the Ruby interpreter libraries.
+=end
+            DEBUGGER__.traceRuby?
+        end
+    end
+
+    require 'DebugProtocol'
+  
+    class Client
+=begin edoc
+Class handling the connection to the IDE.
+=end
+        def initialize( debugger )
+=begin edoc
+Constructor
+
+@param debugger reference to the object having the IDE connection.
+=end
+            @debugger = debugger
+        end
+
+        def eventLoop
+=begin edoc
+Method calling the main event loop.
+=end
+            @debugger.eventLoop()
+        end
+    
+        def eventPoll
+=begin edoc
+Method calling the main function polling for an event sent by the IDE.
+=end
+            @debugger.eventPoll()
+        end
+        
+        def traceRuby?
+=begin edoc
+Method to check, if we should trace into the Ruby interpreter libraries.
+=end
+            @debugger.traceRuby
+        end
+
+        def printf( *args )
+=begin edoc
+Method to print something to the IDE.
+
+@param *args Arguments to be printed.
+=end
+            @debugger.write("#{args.join(', ')}\n")
+        end
+
+        def printf_line(frames)
+=begin edoc
+Method to report the current line and the current stack trace to the IDE.
+
+@param frames reference to the array containing the stack trace.
+=end
+            fr_list = []
+            for bind, file, line, id in frames
+                break unless bind
+                break if file =~ /\(eval\)/
+                fr_list << [file, line, id ? id.id2name : '']
+            end
+            
+            @debugger.write("%s%s\n" % [ResponseLine, fr_list.inspect])
+        end
+
+        def printf_excn(exclist)
+=begin edoc
+Method to report an exception to the IDE.
+
+@param exclist info about the exception to be reported
+=end
+            @debugger.write("%s%s\n" % [ResponseException, exclist.inspect])
+        end
+    
+        def printf_scriptExcn(exclist)
+=begin edoc
+Method to report a ScriptError to the IDE.
+
+@param exclist info about the exception to be reported
+=end
+            @debugger.write("%s%s\n" % [ResponseSyntax, exclist.inspect])
+        end
+
+        def printf_clear_breakpoint(file, line)
+=begin edoc
+Method to report the deletion of a temporary breakpoint to the IDE.
+
+@param file filename of the breakpoint (String)
+@param line line number of the breakpoint (int)
+=end
+            @debugger.write("%s%s,%d\n" % [ResponseClearBreak, file, line])
+        end
+    
+        def printf_clear_watchexpression(cond)
+=begin edoc
+Method to report the deletion of a temporary watch expression to the IDE.
+
+@param cond expression of the watch expression (String)
+=end
+            @debugger.write("%s%s\n" % [ResponseClearWatch, cond])
+        end
+    
+        def printf_exit(status)
+=begin edoc
+Method to report the exit status to the IDE.
+
+@param status exit status of the program (int)
+=end
+            @debugger.write("%s%d\n" % [ResponseExit, status])
+        end
+    end
+
+    class Context
+        def current_frame
+=begin edoc
+Method returning the current execution frame.
+
+@return current execution frame
+=end
+            @frames[@frame_pos]
+        end
+    
+        def get_frame(frameno)
+=begin edoc
+Method returning a specific execution frame.
+
+@param frameno frame number of the frame to be returned (int)
+@return the requested execution frame
+=end
+            @frames[frameno]
+        end
+    
+        def current_binding
+=begin edoc
+Method returning the binding object of the current execution frame.
+
+@return binding object of the current execution frame
+=end
+            @frames[@frame_pos][0]
+        end
+    
+        def get_binding(frameno)
+=begin edoc
+Method returning the binding object of a specific execution frame.
+
+@param frameno frame number of the frame (int)
+@return the requested binding object
+=end
+            @frames[frameno][0]
+        end
+    end
+  
+    Thread.main["name"] = 'Main'
+end

eric ide

mercurial