diff options
author | Ned Batchelder <ned@nedbatchelder.com> | 2013-01-08 09:57:24 -0500 |
---|---|---|
committer | Ned Batchelder <ned@nedbatchelder.com> | 2013-01-08 09:57:24 -0500 |
commit | 11829e9fe0b190e0ac4ce52a98553142782b3ff6 (patch) | |
tree | baf7c5ab00f90050f3a9d4708dc2110747aefa20 | |
parent | 562e0493d521fd8c7972d6edc8d7e52780505fa8 (diff) | |
download | python-coveragepy-git-11829e9fe0b190e0ac4ce52a98553142782b3ff6.tar.gz |
Use generators in the byte code parsing. __next__? yikes!
-rw-r--r-- | coverage/bytecode.py | 52 | ||||
-rw-r--r-- | coverage/parser.py | 15 |
2 files changed, 25 insertions, 42 deletions
diff --git a/coverage/bytecode.py b/coverage/bytecode.py index fd5c7da2..06bc1dfd 100644 --- a/coverage/bytecode.py +++ b/coverage/bytecode.py @@ -30,7 +30,6 @@ class ByteCodes(object): # pylint: disable=R0924 def __init__(self, code): self.code = code - self.offset = 0 if sys.version_info >= (3, 0): def __getitem__(self, i): @@ -40,32 +39,26 @@ class ByteCodes(object): return ord(self.code[i]) def __iter__(self): - return self + offset = 0 + while offset < len(self.code): + bc = ByteCode() + bc.op = self[offset] + bc.offset = offset - def __next__(self): - if self.offset >= len(self.code): - raise StopIteration + next_offset = offset+1 + if bc.op >= opcode.HAVE_ARGUMENT: + bc.arg = self[offset+1] + 256*self[offset+2] + next_offset += 2 - bc = ByteCode() - bc.op = self[self.offset] - bc.offset = self.offset + label = -1 + if bc.op in opcode.hasjrel: + label = next_offset + bc.arg + elif bc.op in opcode.hasjabs: + label = bc.arg + bc.jump_to = label - next_offset = self.offset+1 - if bc.op >= opcode.HAVE_ARGUMENT: - bc.arg = self[self.offset+1] + 256*self[self.offset+2] - next_offset += 2 - - label = -1 - if bc.op in opcode.hasjrel: - label = next_offset + bc.arg - elif bc.op in opcode.hasjabs: - label = bc.arg - bc.jump_to = label - - bc.next_offset = self.offset = next_offset - return bc - - next = __next__ # Py2k uses an old-style non-dunder name. + bc.next_offset = offset = next_offset + yield bc class CodeObjects(object): @@ -74,18 +67,11 @@ class CodeObjects(object): self.stack = [code] def __iter__(self): - return self - - def __next__(self): - if self.stack: + while self.stack: # We're going to return the code object on the stack, but first # push its children for later returning. code = self.stack.pop() for c in code.co_consts: if isinstance(c, types.CodeType): self.stack.append(c) - return code - - raise StopIteration - - next = __next__ + yield code diff --git a/coverage/parser.py b/coverage/parser.py index 44455054..bb6b6082 100644 --- a/coverage/parser.py +++ b/coverage/parser.py @@ -381,27 +381,25 @@ class ByteParser(object): """Map byte offsets to line numbers in `code`. Uses co_lnotab described in Python/compile.c to map byte offsets to - line numbers. Returns a list: [(b0, l0), (b1, l1), ...] + line numbers. Produces a sequence: (b0, l0), (b1, l1), ... """ # Adapted from dis.py in the standard library. byte_increments = self._lnotab_increments(self.code.co_lnotab[0::2]) line_increments = self._lnotab_increments(self.code.co_lnotab[1::2]) - bytes_lines = [] last_line_num = None line_num = self.code.co_firstlineno byte_num = 0 for byte_incr, line_incr in zip(byte_increments, line_increments): if byte_incr: if line_num != last_line_num: - bytes_lines.append((byte_num, line_num)) + yield (byte_num, line_num) last_line_num = line_num byte_num += byte_incr line_num += line_incr if line_num != last_line_num: - bytes_lines.append((byte_num, line_num)) - return bytes_lines + yield (byte_num, line_num) def _find_statements(self): """Find the statements in `self.code`. @@ -426,7 +424,6 @@ class ByteParser(object): Returns a list of `Chunk` objects. """ - # The list of chunks so far, and the one we're working on. chunks = [] chunk = None @@ -634,11 +631,11 @@ class ByteParser(object): class Chunk(object): - """A sequence of bytecodes with a single entrance. + """A sequence of byte codes with a single entrance. To analyze byte code, we have to divide it into chunks, sequences of byte - codes such that each basic block has only one entrance, the first - instruction in the block. + codes such that each chunk has only one entrance, the first instruction in + the block. This is almost the CS concept of `basic block`_, except that we're willing to have many exits from a chunk, and "basic block" is a more cumbersome |