| OLD | NEW |
| 1 """Bytecode manipulation for coverage.py""" | 1 """Bytecode manipulation for coverage.py""" |
| 2 | 2 |
| 3 import opcode, sys, types | 3 import opcode, types |
| 4 |
| 5 from coverage.backward import byte_to_int |
| 4 | 6 |
| 5 class ByteCode(object): | 7 class ByteCode(object): |
| 6 """A single bytecode.""" | 8 """A single bytecode.""" |
| 7 def __init__(self): | 9 def __init__(self): |
| 8 # The offset of this bytecode in the code object. | 10 # The offset of this bytecode in the code object. |
| 9 self.offset = -1 | 11 self.offset = -1 |
| 10 | 12 |
| 11 # The opcode, defined in the `opcode` module. | 13 # The opcode, defined in the `opcode` module. |
| 12 self.op = -1 | 14 self.op = -1 |
| 13 | 15 |
| 14 # The argument, a small integer, whose meaning depends on the opcode. | 16 # The argument, a small integer, whose meaning depends on the opcode. |
| 15 self.arg = -1 | 17 self.arg = -1 |
| 16 | 18 |
| 17 # The offset in the code object of the next bytecode. | 19 # The offset in the code object of the next bytecode. |
| 18 self.next_offset = -1 | 20 self.next_offset = -1 |
| 19 | 21 |
| 20 # The offset to jump to. | 22 # The offset to jump to. |
| 21 self.jump_to = -1 | 23 self.jump_to = -1 |
| 22 | 24 |
| 23 | 25 |
| 24 class ByteCodes(object): | 26 class ByteCodes(object): |
| 25 """Iterator over byte codes in `code`. | 27 """Iterator over byte codes in `code`. |
| 26 | 28 |
| 27 Returns `ByteCode` objects. | 29 Returns `ByteCode` objects. |
| 28 | 30 |
| 29 """ | 31 """ |
| 30 # pylint: disable=R0924 | 32 # pylint: disable=R0924 |
| 31 def __init__(self, code): | 33 def __init__(self, code): |
| 32 self.code = code | 34 self.code = code |
| 33 self.offset = 0 | |
| 34 | 35 |
| 35 if sys.version_info >= (3, 0): | 36 def __getitem__(self, i): |
| 36 def __getitem__(self, i): | 37 return byte_to_int(self.code[i]) |
| 37 return self.code[i] | |
| 38 else: | |
| 39 def __getitem__(self, i): | |
| 40 return ord(self.code[i]) | |
| 41 | 38 |
| 42 def __iter__(self): | 39 def __iter__(self): |
| 43 return self | 40 offset = 0 |
| 41 while offset < len(self.code): |
| 42 bc = ByteCode() |
| 43 bc.op = self[offset] |
| 44 bc.offset = offset |
| 44 | 45 |
| 45 def __next__(self): | 46 next_offset = offset+1 |
| 46 if self.offset >= len(self.code): | 47 if bc.op >= opcode.HAVE_ARGUMENT: |
| 47 raise StopIteration | 48 bc.arg = self[offset+1] + 256*self[offset+2] |
| 49 next_offset += 2 |
| 48 | 50 |
| 49 bc = ByteCode() | 51 label = -1 |
| 50 bc.op = self[self.offset] | 52 if bc.op in opcode.hasjrel: |
| 51 bc.offset = self.offset | 53 label = next_offset + bc.arg |
| 54 elif bc.op in opcode.hasjabs: |
| 55 label = bc.arg |
| 56 bc.jump_to = label |
| 52 | 57 |
| 53 next_offset = self.offset+1 | 58 bc.next_offset = offset = next_offset |
| 54 if bc.op >= opcode.HAVE_ARGUMENT: | 59 yield bc |
| 55 bc.arg = self[self.offset+1] + 256*self[self.offset+2] | |
| 56 next_offset += 2 | |
| 57 | |
| 58 label = -1 | |
| 59 if bc.op in opcode.hasjrel: | |
| 60 label = next_offset + bc.arg | |
| 61 elif bc.op in opcode.hasjabs: | |
| 62 label = bc.arg | |
| 63 bc.jump_to = label | |
| 64 | |
| 65 bc.next_offset = self.offset = next_offset | |
| 66 return bc | |
| 67 | |
| 68 next = __next__ # Py2k uses an old-style non-dunder name. | |
| 69 | 60 |
| 70 | 61 |
| 71 class CodeObjects(object): | 62 class CodeObjects(object): |
| 72 """Iterate over all the code objects in `code`.""" | 63 """Iterate over all the code objects in `code`.""" |
| 73 def __init__(self, code): | 64 def __init__(self, code): |
| 74 self.stack = [code] | 65 self.stack = [code] |
| 75 | 66 |
| 76 def __iter__(self): | 67 def __iter__(self): |
| 77 return self | 68 while self.stack: |
| 78 | |
| 79 def __next__(self): | |
| 80 if self.stack: | |
| 81 # We're going to return the code object on the stack, but first | 69 # We're going to return the code object on the stack, but first |
| 82 # push its children for later returning. | 70 # push its children for later returning. |
| 83 code = self.stack.pop() | 71 code = self.stack.pop() |
| 84 for c in code.co_consts: | 72 for c in code.co_consts: |
| 85 if isinstance(c, types.CodeType): | 73 if isinstance(c, types.CodeType): |
| 86 self.stack.append(c) | 74 self.stack.append(c) |
| 87 return code | 75 yield code |
| 88 | |
| 89 raise StopIteration | |
| 90 | |
| 91 next = __next__ | |
| OLD | NEW |