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