|
2 | 2 | """ |
3 | 3 | from __future__ import print_function, division |
4 | 4 |
|
5 | | -import inspect |
6 | | -import types |
7 | | - |
8 | 5 | from xpython.byteop.byteop25 import ByteOp25 |
9 | 6 | from xpython.byteop.byteop33 import ByteOp33 |
10 | 7 | from xpython.byteop.byteop34 import ByteOp34 |
@@ -77,31 +74,91 @@ def BUILD_MAP_UNPACK_WITH_CALL(self, oparg): |
77 | 74 | mappings, the relative position of the corresponding callable |
78 | 75 | f is encoded in the second byte of oparg. |
79 | 76 | """ |
80 | | - arg, count = divmod(arg, 256) |
| 77 | + arg, count = divmod(oparg, 256) |
81 | 78 | elts = self.vm.popn(count) |
82 | 79 | kwargs = {k:v for m in elts for k, v in m.items()} |
83 | 80 | # FIXME: This is probably not right |
84 | 81 | self.vm.call_function(arg, 0, kwargs) |
85 | 82 |
|
86 | 83 |
|
87 | | - def GET_AITER(self): |
88 | | - raise self.VirtualMachineError("GET_AITER not implemented yet") |
| 84 | + def GET_AITER(self): |
| 85 | + raise self.VirtualMachineError("GET_AITER not implemented yet") |
| 86 | + |
| 87 | + def GET_ANEXT(self): |
| 88 | + raise self.VirtualMachineError("GET_ANEXT not implemented yet") |
| 89 | + |
| 90 | + def BEFORE_ASYNC_WITH(self): |
| 91 | + raise self.VirtualMachineError("BEFORE_ASYNC_WITH not implemented yet") |
| 92 | + return |
89 | 93 |
|
90 | | - def GET_ANEXT(self): |
91 | | - raise self.VirtualMachineError("GET_ANEXT not implemented yet") |
| 94 | + def GET_YIELD_FROM_ITER(self): |
| 95 | + raise self.VirtualMachineError("GET_YIELD_FROM_ITER not implemented yet") |
92 | 96 |
|
93 | | - def BEFORE_ASYNC_WITH(self): |
94 | | - raise self.VirtualMachineError("BEFORE_ASYNC_WITH not implemented yet") |
95 | | - return |
| 97 | + def GET_AWAITABLE(self): |
| 98 | + raise self.VirtualMachineError("GET_AWAITABLE not implemented yet") |
96 | 99 |
|
97 | | - def GET_YIELD_FROM_ITER(self): |
98 | | - raise self.VirtualMachineError("GET_YIELD_FROM_ITER not implemented yet") |
| 100 | + def WITH_CLEANUP_START(self): |
| 101 | + """Cleans up the stack when a with statement block exits. |
99 | 102 |
|
100 | | - def GET_AWAITABLE(self): |
101 | | - raise self.VirtualMachineError("GET_AWAITABLE not implemented yet") |
| 103 | + TOS is the context manager’s __exit__() bound method. Below |
| 104 | + TOS are 1–3 values indicating how/why the finally clause was |
| 105 | + entered: |
102 | 106 |
|
103 | | - def WITH_CLEANUP_START(self): |
104 | | - raise self.VirtualMachineError("WITH_CLEANUP_START not implemented yet") |
| 107 | + * SECOND = None |
| 108 | + * (SECOND, THIRD) = (WHY_{RETURN,CONTINUE}), retval |
| 109 | + * SECOND = WHY_*; no retval below it |
| 110 | + * (SECOND, THIRD, FOURTH) = exc_info() |
105 | 111 |
|
106 | | - def WITH_CLEANUP_FINISH(self): |
107 | | - raise self.VirtualMachineError("WITH_CLEANUP_FINISH not implemented yet") |
| 112 | + In the last case, TOS(SECOND, THIRD, FOURTH) is called, |
| 113 | + otherwise TOS(None, None, None). Pushes SECOND and result of the call |
| 114 | + to the stack. Cleans up the stack when a `with` statement block |
| 115 | + exits. TOS is the context manager's `__exit__()` bound method. |
| 116 | + """ |
| 117 | + second = third = fourth = None |
| 118 | + TOS = self.vm.top() |
| 119 | + if TOS is None: |
| 120 | + exit_func = self.vm.pop(1) |
| 121 | + elif isinstance(TOS, str): |
| 122 | + # FIXME: This code does something funky with pushing "continue" |
| 123 | + # See the comment under CONTINUE_LOOP. |
| 124 | + # jump addresses on the frame stack. As a result, we need to |
| 125 | + # set up here something to make END_FINALLY work and remove |
| 126 | + # the jump address. This means that the comment or semantics |
| 127 | + # described above isn't strictly correct. |
| 128 | + if TOS in ("return", "continue"): |
| 129 | + exit_func = self.vm.pop(2) |
| 130 | + second = TOS |
| 131 | + else: |
| 132 | + exit_func = self.vm.pop(1) |
| 133 | + second = None |
| 134 | + elif issubclass(TOS, BaseException): |
| 135 | + fourth, third, second = self.vm.popn(3) |
| 136 | + tp, exc, tb = self.vm.popn(3) |
| 137 | + self.vm.push(None) |
| 138 | + self.vm.push(fourth, third, second) |
| 139 | + block = self.vm.pop_block() |
| 140 | + assert block.type == "except-handler" |
| 141 | + self.vm.push_block(block.type, block.handler, block.level - 1) |
| 142 | + else: |
| 143 | + pass |
| 144 | + exit_ret = exit_func(second, third, fourth) |
| 145 | + self.vm.push(exit_ret) |
| 146 | + self.vm.push(second) |
| 147 | + |
| 148 | + def WITH_CLEANUP_FINISH(self): |
| 149 | + """Pops exception type and result of "exit" function call from the stack. |
| 150 | +
|
| 151 | + If the stack represents an exception, and the function call |
| 152 | + returns a ‘true’ value, this information is "zapped" and |
| 153 | + replaced with a single WHY_SILENCED to prevent END_FINALLY |
| 154 | + from re-raising the exception. (But non-local gotos will still |
| 155 | + be resumed.) |
| 156 | + """ |
| 157 | + # FIXME: Not sure what this is supposed to be |
| 158 | + exit_ret = self.vm.pop(1) |
| 159 | + if bool(exit_ret): |
| 160 | + # An error occurred, and was suppressed |
| 161 | + self.vm.push("silenced") |
| 162 | + else: |
| 163 | + self.vm.pop(1) |
| 164 | + pass |
0 commit comments