@@ -71,6 +71,46 @@ impl Frame {
7171 }
7272 }
7373
74+ #[ pygetset( setter) ]
75+ fn set_f_lineno ( & self , value : PySetterValue , vm : & VirtualMachine ) -> PyResult < ( ) > {
76+ let target_line = match value {
77+ PySetterValue :: Assign ( val) => {
78+ let line_ref: PyIntRef = val
79+ . downcast ( )
80+ . map_err ( |_| vm. new_value_error ( "lineno must be an integer" . to_owned ( ) ) ) ?;
81+ line_ref
82+ . try_to_primitive :: < usize > ( vm)
83+ . map_err ( |_| vm. new_value_error ( "lineno must be an integer" . to_owned ( ) ) ) ?
84+ }
85+ PySetterValue :: Delete => {
86+ return Err ( vm. new_type_error ( "can't delete f_lineno attribute" . to_owned ( ) ) ) ;
87+ }
88+ } ;
89+
90+ // Find the first instruction at the target line
91+ let locations = & self . code . locations ;
92+ let mut target_idx = None ;
93+ for ( idx, ( loc, _) ) in locations. iter ( ) . enumerate ( ) {
94+ if loc. line . get ( ) == target_line {
95+ target_idx = Some ( idx) ;
96+ break ;
97+ }
98+ }
99+
100+ match target_idx {
101+ Some ( idx) => {
102+ // Set lasti to point to the target instruction.
103+ // The run loop reads lasti then increments, so set to idx
104+ // so the next iteration executes instruction at idx.
105+ self . set_lasti ( idx as u32 ) ;
106+ Ok ( ( ) )
107+ }
108+ None => Err ( vm. new_value_error ( format ! (
109+ "line {target_line} comes after the current code block"
110+ ) ) ) ,
111+ }
112+ }
113+
74114 #[ pygetset]
75115 fn f_trace ( & self ) -> PyObjectRef {
76116 let boxed = self . trace . lock ( ) ;
0 commit comments