@@ -436,6 +436,8 @@ def __init__(self, file=None, lineno_width=0, offset_width=0, positions_width=0,
436436 *positions_width* sets the width of the instruction positions field (0 omits it)
437437 *label_width* sets the width of the label field
438438 *show_caches* is a boolean indicating whether to display cache lines
439+
440+ If *positions_width* is specified, *lineno_width* is ignored.
439441 """
440442 self .file = file
441443 self .lineno_width = lineno_width
@@ -465,25 +467,36 @@ def print_instruction(self, instr, mark_as_current=False):
465467 def print_instruction_line (self , instr , mark_as_current ):
466468 """Format instruction details for inclusion in disassembly output."""
467469 lineno_width = self .lineno_width
470+ positions_width = self .positions_width
468471 offset_width = self .offset_width
469472 label_width = self .label_width
470473
471- new_source_line = (lineno_width > 0 and
474+ new_source_line = (( lineno_width > 0 or positions_width > 0 ) and
472475 instr .starts_line and
473476 instr .offset > 0 )
474477 if new_source_line :
475478 print (file = self .file )
476479
477480 fields = []
478481 # 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 )
485492 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 )
487500 # Column: Label
488501 if instr .label is not None :
489502 lbl = f"L{ instr .label } :"
@@ -821,7 +834,7 @@ def _make_labels_map(original_code, exception_entries=()):
821834 e .target_label = labels_map [e .target ]
822835 return labels_map
823836
824- _NO_LINENO = ' --'
837+ _NO_LINENO = ' --'
825838
826839def _get_lineno_width (linestarts ):
827840 if linestarts is None :
@@ -836,6 +849,21 @@ def _get_lineno_width(linestarts):
836849 return lineno_width
837850
838851def _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 )
839867 return 0
840868
841869def _disassemble_bytes (code , lasti = - 1 , linestarts = None ,
0 commit comments