diff options
Diffstat (limited to 'Mac/Tools/twit/TwitCore.py')
-rw-r--r-- | Mac/Tools/twit/TwitCore.py | 493 |
1 files changed, 493 insertions, 0 deletions
diff --git a/Mac/Tools/twit/TwitCore.py b/Mac/Tools/twit/TwitCore.py new file mode 100644 index 0000000..51f6485 --- /dev/null +++ b/Mac/Tools/twit/TwitCore.py @@ -0,0 +1,493 @@ +# Window-interface-independent part of twit +import sys +import types +import bdb +import types + +SIMPLE_TYPES=( + types.NoneType, + types.IntType, + types.LongType, + types.FloatType, + types.ComplexType, + types.StringType +) + +def Initialize(): + pass + +class DebuggerStuff(bdb.Bdb): + + def __init__(self, parent): + bdb.Bdb.__init__(self) + self.parent = parent + self.exception_info = (None, None) + self.reason = 'Not running' + self.reset() + + def reset(self): + bdb.Bdb.reset(self) + self.forget() + + def forget(self): + self.lineno = None + self.stack = [] + self.curindex = 0 + self.curframe = None + + def setup(self, f, t): + self.forget() + self.stack, self.curindex = self.get_stack(f, t) + self.curframe = self.stack[self.curindex][0] + + def interaction(self, frame, traceback): + self.setup(frame, traceback) + self.parent.interact() + self.exception_info = (None, None) + + def user_call(self, frame, argument_list): + self.reason = 'Calling function' + self.interaction(frame, None) + + def user_line(self, frame): + self.reason = 'Stopped' + self.interaction(frame, None) + + def user_return(self, frame, return_value): + self.reason = 'Returning from function' + self.interaction(frame, None) + + def user_exception(self, frame, (exc_type, exc_value, exc_traceback)): + self.reason = 'Exception occurred' + self.exception_info = (exc_type, exc_value) + self.interaction(frame, exc_traceback) + + def getexception(self): + tp, value = self.exception_info + if tp <> None and type(tp) <> type(''): + tp = tp.__name__ + if value <> None and type(value) <> type(''): + value = `value` + return tp, value + + def getstacktrace(self): + names, locations = [], [] + for frame, lineno in self.stack: + name = frame.f_code.co_name + if not name: + name = "<lambda>" + elif name == '?': + name = "<not a function>" + else: + name = name + '()' + names.append(name) + + if lineno == -1: + lineno = getframelineno(frame) + + modname = getframemodname(frame) + if not modname: modname = "<unknown>" + + locations.append("%s:%d" % (modname, lineno)) + return names, locations + + def getframe(self, number): + if number < 0 or number >= len(self.stack): + return None + return self.stack[number][0] + + def getframevars(self, number, show_complex=1, show_system=1): + frame = self.getframe(number) + if not frame: + return [], [] + return getvarsfromdict(frame.f_locals, show_complex, show_system) + + def getframevar(self, number, var): + frame = self.getframe(number) + return frame.f_locals[var] + + def getframefilepos(self, frameno): + if frameno == None or frameno < 0 or frameno >= len(self.stack): + return None, None, None + frame, line = self.stack[frameno] + if line == -1: + line = getframelineno(frame) + modname = getframemodname(frame) + filename = frame.f_code.co_filename + return filename, modname, line + + def getprogramstate(self): + return self.reason + +class Application: + """Base code for the application""" + + def mi_init(self, run_args, pm_args): + self.dbg = DebuggerStuff(self) + self.run_dialog = self.new_stack_browser(self) + self.run_dialog.open() + self.module_dialog = None + self.initial_cmd = None + if pm_args: + while pm_args.tb_next <> None: + pm_args = pm_args.tb_next + self.dbg.setup(pm_args.tb_frame, pm_args) + self.run_dialog.setsession_pm() + elif run_args: + self.run_dialog.setsession_run() + self.initial_cmd = run_args + else: + self.run_dialog.setsession_none() + + def breaks_changed(self, filename): + self.run_dialog.breaks_changed(filename) + if self.module_dialog: + self.module_dialog.breaks_changed(filename) + + def to_debugger(self): + apply(self.dbg.run, self.initial_cmd) + + def interact(self): + # Interact with user. First, display correct info + self.run_dialog.update_views() + if self.module_dialog: + self.module_dialog.update_views() + + # Next, go into mainloop + self.one_mainloop() + + # Finally (before we start the debuggee again) show state + self.run_dialog.show_it_running() + + def quit_bdb(self): + self.dbg.set_quit() + + def run(self): + cmd = AskString('Statement to execute:') + self.initial_cmd = (cmd, None, None) + self.run_dialog.setsession_run() + self.exit_mainloop() + + def cont(self): + self.dbg.set_continue() + self.exit_mainloop() + + def step(self, frame): + self.dbg.set_next(frame) + self.exit_mainloop() + + def step_in(self): + self.dbg.set_step() + self.exit_mainloop() + + def step_out(self, frame): + self.dbg.set_return(frame) + self.exit_mainloop() + + def quit(self): + self.do_quit() + + def browse(self, module): + if not self.module_dialog: + self.module_dialog = self.new_module_browser(self) + self.module_dialog.open(module) + else: + self.module_dialog.focus(module) + + def browse_var(self, var): + b = self.new_var_browser(self, var) + +class StackBrowser: + """Base code for stack browser""" + def mi_open(self): + """Setup initial data structures""" + self.create_items() + self.cur_stackitem = None + self.cur_source = None + self.cur_modname = None + self.cur_line = None + self.show_complex = 1 + self.show_system = 0 + self.setup() + + # create_items(self) should create self.modules, self.vars and self.source + + def setup(self): + SetWatch() + """Fill the various widgets with values""" + name, value = self.parent.dbg.getexception() + self.setexception(name, value) + self.setprogramstate(self.parent.dbg.getprogramstate()) + + names, locations = self.parent.dbg.getstacktrace() + self.stack.setcontent(names, locations) + self.cur_stackitem = len(names)-1 + self.stack.select(self.cur_stackitem) + self.setup_frame() + + def setup_frame(self): + """Setup frame-dependent widget data""" + SetWatch() + self.cont_varnames, self.cont_varvalues = \ + self.parent.dbg.getframevars(self.cur_stackitem, + self.show_complex, self.show_system) + self.vars.setcontent(self.cont_varnames, self.cont_varvalues) + self.set_var_buttons() + + msg = "" + if self.cur_stackitem == None: + self.cur_source = None + self.cur_modname = None + self.cur_line = None + msg = "No stackframe selected" + else: + self.cur_source, self.cur_modname, optnextline = \ + self.parent.dbg.getframefilepos(self.cur_stackitem) + if optnextline >= 0: + self.cur_line = optnextline + if self.cur_source == '<string>': + self.cur_source = None + msg = "Executing from <string>" + print 'SOURCE', self.cur_source + print 'LINE', self.cur_line + + self.setsource(msg) + self.source.setcurline(self.cur_line) + self.breaks_changed(self.cur_source) + + + SetCursor() + + # setsource(msg) should display cur_source+content, or msg if None + + def show_it_running(self): + self.setprogramstate("Running") + + def update_views(self): + self.setup() + + def click_stack(self, number, *dummy): + if number == self.cur_stackitem: return + self.cur_stackitem = number + self.stack.select(self.cur_stackitem) + self.setup_frame() + + def click_var(self, var, *dummy): + v = self.parent.dbg.getframevar(self.cur_stackitem, var) + self.parent.browse_var(v) + + def click_source(self, lineno, inborder): + if not inborder: + self.source.select(lineno) + self.cur_line = lineno + if lineno == None or not self.cur_source or not inborder: + return + if self.parent.dbg.get_break(self.cur_source, lineno): + self.parent.dbg.clear_break(self.cur_source, lineno) + else: + self.parent.dbg.set_break(self.cur_source, lineno) + self.parent.breaks_changed(self.cur_source) + + def breaks_changed(self, filename): + if filename == self.cur_source: + list = self.parent.dbg.get_file_breaks(filename) + self.source.setbreaks(list) + + def click_quit(self): + self.parent.quit() + + def click_run(self): + self.parent.run() + + def click_continue(self): + self.parent.cont() + + def click_step(self): + if self.cur_stackitem <> None: + frame = self.parent.dbg.getframe(self.cur_stackitem) + self.parent.step(frame) + else: + self.parent.step_in() + + def click_step_in(self): + self.parent.step_in() + + def click_step_out(self): + if self.cur_stackitem <> None: + frame = self.parent.dbg.getframe(self.cur_stackitem) + self.parent.step_out(frame) + else: + self.parent.step_in() + + def click_browse(self): + self.parent.browse(self.cur_modname) + + def click_edit(self): + lino = self.cur_line + if not lino: + lino = 1 + if self.cur_source: + self.parent.edit(self.cur_source, lino) + +class ModuleBrowser: + """Base code for a module-browser""" + + def mi_open(self, module): + """Setup initial data structures""" + self.create_items() + self.cur_module = module + self.cur_source = None + self.cur_line = None + self.cont_modules = [] + self.value_windows = [] + self.setup() + + # create_items(self) should create self.modules, self.vars and self.source + + def setup(self): + """Fill the various widgets with values""" + SetWatch() + modnames = getmodulenames() + if not self.cur_module in modnames: + self.cur_module = None + if modnames <> self.cont_modules: + self.modules.setcontent(modnames) + self.cont_modules = modnames + if self.cur_module: + self.modules.select(self.cont_modules.index(self.cur_module)) + else: + self.modules.select(None) + self.setup_module() + + def setup_module(self): + """Setup module-dependent widget data""" + SetWatch() + if not self.cur_module: + self.vars.setcontent([], []) + else: + self.cont_varnames, self.cont_varvalues = getmodulevars(self.cur_module) + self.vars.setcontent(self.cont_varnames, self.cont_varvalues) + + msg = "" + if not self.cur_module: + self.cur_source = None + msg = "No module selected" + else: + m = sys.modules[self.cur_module] + try: + self.cur_source = m.__file__ + except AttributeError: + self.cur_source = None + msg = "Not a python module" + self.cur_lineno = 0 + self.setsource(msg) + self.source.select(self.cur_line) + self.breaks_changed(self.cur_source) + + SetCursor() + + # setsource(msg) should display cur_source+content, or msg if None + + def update_views(self): + self.setup_module() + + def click_module(self, module, *dummy): + if not module or module == self.cur_module: return + self.focus(module) + + def focus(self, module): + self.cur_module = module + self.setup() + + def click_var(self, var, *dummy): + if not var: return + m = sys.modules[self.cur_module] + dict = m.__dict__ + self.parent.browse_var(dict[var]) + + def click_source(self, lineno, inborder): + if not inborder: + self.source.select(lineno) + self.cur_lineno = lineno + if lineno == None or not self.cur_source or not inborder: + return + if self.parent.dbg.get_break(self.cur_source, lineno): + self.parent.dbg.clear_break(self.cur_source, lineno) + else: + self.parent.dbg.set_break(self.cur_source, lineno) + self.parent.breaks_changed(self.cur_source) + + def breaks_changed(self, filename): + if filename == self.cur_source: + list = self.parent.dbg.get_file_breaks(filename) + self.source.setbreaks(list) + + def click_edit(self): + lino = self.cur_lineno + if not lino: + lino = 1 + if self.cur_source: + self.parent.edit(self.cur_source, lino) + + +def getmodulenames(): + """Return a list of all current modules, sorted""" + list = sys.modules.keys()[:] + list.sort() + return list + +def getmodulevars(name): + """For given module return lists with names and values""" + m = sys.modules[name] + try: + dict = m.__dict__ + except AttributeError: + dict = {} + return getvarsfromdict(dict) + +def getvarsfromdict(dict, show_complex=1, show_system=1): + allnames = dict.keys()[:] + allnames.sort() + names = [] + for n in allnames: + if not show_complex: + if not type(dict[n]) in SIMPLE_TYPES: + continue + if not show_system: + if n[:2] == '__' and n[-2:] == '__': + continue + names.append(n) + values = [] + for n in names: + v = pretty(dict[n]) + values.append(v) + return names, values + +def pretty(var): + t = type(var) + if t == types.FunctionType: return '<function>' + if t == types.ClassType: return '<class>' + return `var` + +def getframelineno(frame): + """Given a frame return the line number""" + return getcodelineno(frame.f_code) + +def getfunclineno(func): + """Given a function return the line number""" + return getcodelineno(func.func_code) + +def getcodelineno(cobj): + """Given a code object return the line number""" + code = cobj.co_code + lineno = -1 + if ord(code[0]) == 127: # SET_LINENO instruction + lineno = ord(code[1]) | (ord(code[2]) << 8) + return lineno + +def getframemodname(frame): + """Given a frame return the module name""" + globals = frame.f_globals + if globals.has_key('__name__'): + return globals['__name__'] + return None |