Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 18 additions & 10 deletions xdis/codetype/code310.py
Original file line number Diff line number Diff line change
Expand Up @@ -163,24 +163,32 @@ def co_lines(self):
either be a positive integer, or None

Parsing implementation adapted from: https://github.com/python/cpython/blob/3.10/Objects/lnotab_notes.txt
The algorithm presented in the lnotab_notes.txt file is slightly inaccurate. The first linetable entry will have a line delta of 0, and should be yielded instead of skipped.
This implementation follows the lineiter definition in https://github.com/python/cpython/blob/3.10/Objects/codeobject.c#L1030.
"""
line = self.co_firstlineno
end_offset = 0
line = self.co_firstlineno

# co_linetable is pairs of (offset_delta: unsigned byte, line_delta: signed byte)
for offset_delta, line_delta in struct.iter_unpack('=Bb', self.co_linetable):
assert isinstance(line_delta, int)
assert isinstance(offset_delta, int)
if line_delta == 0: # No change to line number, just accumulate changes to end
end_offset += offset_delta
continue

start_offset = end_offset
end_offset = start_offset + offset_delta
if line_delta == -128: # No valid line number -- skip entry
continue
line += line_delta
if end_offset == start_offset: # Empty range, omit.
end_offset += offset_delta

# line_delta of -128 signifies an instruction range that is not associated with any line
if line_delta != -128:
line += line_delta
display_line = line
else:
display_line = None

# omit empty ranges
if start_offset == end_offset:
continue
yield start_offset, end_offset, line

yield start_offset, end_offset, display_line

def encode_lineno_tab(self):
"""
Expand Down