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