@@ -436,6 +436,8 @@ def __init__(self, file=None, lineno_width=0, offset_width=0, positions_width=0,
436
436
*positions_width* sets the width of the instruction positions field (0 omits it)
437
437
*label_width* sets the width of the label field
438
438
*show_caches* is a boolean indicating whether to display cache lines
439
+
440
+ If *positions_width* is specified, *lineno_width* is ignored.
439
441
"""
440
442
self .file = file
441
443
self .lineno_width = lineno_width
@@ -465,25 +467,36 @@ def print_instruction(self, instr, mark_as_current=False):
465
467
def print_instruction_line (self , instr , mark_as_current ):
466
468
"""Format instruction details for inclusion in disassembly output."""
467
469
lineno_width = self .lineno_width
470
+ positions_width = self .positions_width
468
471
offset_width = self .offset_width
469
472
label_width = self .label_width
470
473
471
- new_source_line = (lineno_width > 0 and
474
+ new_source_line = (( lineno_width > 0 or positions_width > 0 ) and
472
475
instr .starts_line and
473
476
instr .offset > 0 )
474
477
if new_source_line :
475
478
print (file = self .file )
476
479
477
480
fields = []
478
481
# 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 )
482
+ if lineno_width or positions_width :
483
+ if positions_width :
484
+ # reporting positions instead of just line numbers
485
+ assert lineno_width > 0
486
+ if instr_positions := instr .positions :
487
+ ps = tuple ('?' if p is None else p for p in instr_positions )
488
+ positions_str = "%s:%s-%s:%s" % ps
489
+ fields .append (f'{ positions_str :{positions_width }} ' )
490
+ else :
491
+ fields .append (' ' * positions_width )
485
492
else :
486
- fields .append (' ' * lineno_width )
493
+ if instr .starts_line :
494
+ lineno_fmt = "%%%dd" if instr .line_number is not None else "%%%ds"
495
+ lineno_fmt = lineno_fmt % lineno_width
496
+ lineno = _NO_LINENO if instr .line_number is None else instr .line_number
497
+ fields .append (lineno_fmt % lineno )
498
+ else :
499
+ fields .append (' ' * lineno_width )
487
500
# Column: Label
488
501
if instr .label is not None :
489
502
lbl = f"L{ instr .label } :"
@@ -821,7 +834,7 @@ def _make_labels_map(original_code, exception_entries=()):
821
834
e .target_label = labels_map [e .target ]
822
835
return labels_map
823
836
824
- _NO_LINENO = ' --'
837
+ _NO_LINENO = ' --'
825
838
826
839
def _get_lineno_width (linestarts ):
827
840
if linestarts is None :
@@ -836,6 +849,21 @@ def _get_lineno_width(linestarts):
836
849
return lineno_width
837
850
838
851
def _get_positions_width (code ):
852
+ # Positions are formatted as 'LINE:COL-ENDLINE:ENDCOL' with an additional
853
+ # whitespace after the end column. If one of the component is missing, we
854
+ # will print ? instead, thus the minimum width is 8 = 1 + len('?:?-?:?'),
855
+ # except if all positions are undefined, in which case positions are not
856
+ # printed (i.e. positions_width = 0).
857
+ has_value = True
858
+ values_width = 0
859
+ for positions in code .co_positions ():
860
+ if not has_value and any (isinstance (p ) for p in positions ):
861
+ has_value = True
862
+ width = sum (1 if p is None else len (str (p )) for p in positions )
863
+ values_width = max (width , values_width )
864
+ if has_value :
865
+ # 3 = number of separators in a normal format
866
+ return 1 + max (7 , 3 + values_width )
839
867
return 0
840
868
841
869
def _disassemble_bytes (code , lasti = - 1 , linestarts = None ,
0 commit comments