Skip to content

Commit a934b4e

Browse files
committed
allow to show code's positions in dis
1 parent 3157e24 commit a934b4e

File tree

1 file changed

+38
-9
lines changed

1 file changed

+38
-9
lines changed

Lib/dis.py

Lines changed: 38 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import types
55
import collections
66
import io
7+
from fileinput import lineno
78

89
from opcode import *
910
from opcode import (
@@ -436,6 +437,8 @@ def __init__(self, file=None, lineno_width=0, offset_width=0, positions_width=0,
436437
*positions_width* sets the width of the instruction positions field (0 omits it)
437438
*label_width* sets the width of the label field
438439
*show_caches* is a boolean indicating whether to display cache lines
440+
441+
If *positions_width* is specified, *lineno_width* is ignored.
439442
"""
440443
self.file = file
441444
self.lineno_width = lineno_width
@@ -465,25 +468,36 @@ def print_instruction(self, instr, mark_as_current=False):
465468
def print_instruction_line(self, instr, mark_as_current):
466469
"""Format instruction details for inclusion in disassembly output."""
467470
lineno_width = self.lineno_width
471+
positions_width = self.positions_width
468472
offset_width = self.offset_width
469473
label_width = self.label_width
470474

471-
new_source_line = (lineno_width > 0 and
475+
new_source_line = ((lineno_width > 0 or positions_width > 0) and
472476
instr.starts_line and
473477
instr.offset > 0)
474478
if new_source_line:
475479
print(file=self.file)
476480

477481
fields = []
478482
# Column: Source code line number
479-
if lineno_width:
480-
if instr.starts_line:
481-
lineno_fmt = "%%%dd" if instr.line_number is not None else "%%%ds"
482-
lineno_fmt = lineno_fmt % lineno_width
483-
lineno = _NO_LINENO if instr.line_number is None else instr.line_number
484-
fields.append(lineno_fmt % lineno)
483+
if lineno_width or positions_width:
484+
if positions_width:
485+
# reporting positions instead of just line numbers
486+
assert lineno_width > 0
487+
if instr_positions := instr.positions:
488+
ps = tuple('?' if p is None else p for p in instr_positions)
489+
positions_str = "%s:%s-%s:%s" % ps
490+
fields.append(f'{positions_str:{positions_width}}')
491+
else:
492+
fields.append(' ' * positions_width)
485493
else:
486-
fields.append(' ' * lineno_width)
494+
if instr.starts_line:
495+
lineno_fmt = "%%%dd" if instr.line_number is not None else "%%%ds"
496+
lineno_fmt = lineno_fmt % lineno_width
497+
lineno = _NO_LINENO if instr.line_number is None else instr.line_number
498+
fields.append(lineno_fmt % lineno)
499+
else:
500+
fields.append(' ' * lineno_width)
487501
# Column: Label
488502
if instr.label is not None:
489503
lbl = f"L{instr.label}:"
@@ -821,7 +835,7 @@ def _make_labels_map(original_code, exception_entries=()):
821835
e.target_label = labels_map[e.target]
822836
return labels_map
823837

824-
_NO_LINENO = ' --'
838+
_NO_LINENO = ' --'
825839

826840
def _get_lineno_width(linestarts):
827841
if linestarts is None:
@@ -836,6 +850,21 @@ def _get_lineno_width(linestarts):
836850
return lineno_width
837851

838852
def _get_positions_width(code):
853+
# Positions are formatted as 'LINE:COL-ENDLINE:ENDCOL' with an additional
854+
# whitespace after the end column. If one of the component is missing, we
855+
# will print ? instead, thus the minimum width is 8 = 1 + len('?:?-?:?'),
856+
# except if all positions are undefined, in which case positions are not
857+
# printed (i.e. positions_width = 0).
858+
has_value = True
859+
values_width = 0
860+
for positions in code.co_positions():
861+
if not has_value and any(isinstance(p) for p in positions):
862+
has_value = True
863+
width = sum(1 if p is None else len(str(p)) for p in positions)
864+
values_width = max(width, values_width)
865+
if has_value:
866+
# 3 = number of separators in a normal format
867+
return 1 + max(7, 3 + values_width)
839868
return 0
840869

841870
def _disassemble_bytes(code, lasti=-1, linestarts=None,

0 commit comments

Comments
 (0)