from rsqueakvm.plugins.python import global_state as gs

from pypy.module.pypyjit.interp_jit import PyFrame, PyPyJitDriver

old_init_frame = PyFrame.__init__
old_execute_frame = PyFrame.execute_frame
old_handle_operation_error = PyFrame.handle_operation_error


def __init__frame(self, space, code, w_globals, outer_func):
    self.w_globals = w_globals
    self.outer_func = outer_func
    old_init_frame(self, space, code, w_globals, outer_func)


def new_execute_frame(self, w_inputvalue=None, operr=None):
    try:
        return old_execute_frame(self, w_inputvalue, operr)
    except gs.RestartException as e:
        frame = e.py_frame_restart_info.frame
        if frame is not None and frame is not self:
            raise gs.RestartException(e.py_frame_restart_info)
        # Generate and execute new frame
        new_frame = gs.py_space.FrameClass(
            self.space, e.py_frame_restart_info.pycode or self.pycode,
            self.w_globals, self.outer_func)
        return new_execute_frame(new_frame, w_inputvalue, operr)


def new_handle_operation_error(self, ec, operr, attach_tb=True):
    if isinstance(operr, gs.RestartException):
        print 'Re-raising RestartException'
        raise operr
    gs.wp_error.set(operr.get_w_value(gs.py_space))
    print 'Python error caught'
    # import pdb; pdb.set_trace()
    gs.switch_action.perform()
    return old_handle_operation_error(self, ec, operr, attach_tb)


def patch_pypy():
    # Patch-out virtualizables from Pypy so that translation works
    try:
        # TODO: what if first delattr fails?
        delattr(PyFrame, '_virtualizable_')
        delattr(PyPyJitDriver, 'virtualizables')
    except AttributeError:
        pass

    PyFrame.__init__ = __init__frame
    PyFrame.execute_frame = new_execute_frame
    PyFrame.handle_operation_error = new_handle_operation_error

@@ -115,16 +115,166 @@
 itDriver
+%0Afrom pypy.interpreter.pyopcode import SApplicationException%0A%0Afrom pypy.tool.stdlib_opcode import bytecode_spec%0A%0Aopcodedesc = bytecode_spec.opcodedesc
 %0A%0Aold_in
@@ -1184,24 +1184,1245 @@
 e, operr)%0A%0A%0A
+def get_exception(self, handlerposition):%0A    %22Retrieve exception to catch%22%0A    next_opcode = ord(self.pycode.co_code%5Bhandlerposition + 1%5D)%0A    if next_opcode == opcodedesc.LOAD_GLOBAL.index:%0A        global_index = ord(self.pycode.co_code%5Bhandlerposition + 2%5D)%0A        return self._load_global(self.getname_u(global_index))%0A    elif next_opcode == opcodedesc.LOAD_NAME.index:%0A        if self.getorcreatedebug().w_locals is self.get_w_globals():%0A            global_index = ord(self.pycode.co_code%5Bhandlerposition + 2%5D)%0A            return self._load_global(self.getname_u(global_index))%0A    return None%0A%0A%0Adef has_exception_handler(self, operr):%0A    %22Returns True if this frame or one of his parents are able to handle operr%22%0A    frame = self%0A    while frame is not None:%0A        block = frame.lastblock%0A        while block is not None:%0A            if (block.handling_mask & SApplicationException.kind) != 0:%0A                block_exc = get_exception(frame, block.handlerposition)%0A                if block_exc is not None:%0A                    if gs.py_space.exception_match(operr.w_type, block_exc):%0A                        return True%0A            block = block.previous%0A        frame = frame.f_backref()%0A    return False%0A%0A%0A
 def new_hand
@@ -2585,16 +2585,105 @@
 e operr%0A
+%0A    if not self.has_exception_handler(operr):%0A        # import pdb; pdb.set_trace()%0A    
     gs.w
@@ -2726,16 +2726,20 @@
 space))%0A
+    
     prin
@@ -2770,38 +2770,8 @@
     
-# import pdb; pdb.set_trace()%0A
     
@@ -3217,24 +3217,124 @@
 ecute_frame%0A
+    PyFrame.get_exception = get_exception%0A    PyFrame.has_exception_handler = has_exception_handler%0A
     PyFrame.

Improve exception handling