@@ -40,6 +40,22 @@ pub struct ReplaceArgs {
4040 co_flags : OptionalArg < u16 > ,
4141 #[ pyarg( named, optional) ]
4242 co_varnames : OptionalArg < Vec < PyObjectRef > > ,
43+ #[ pyarg( named, optional) ]
44+ co_nlocals : OptionalArg < u32 > ,
45+ #[ pyarg( named, optional) ]
46+ co_stacksize : OptionalArg < u32 > ,
47+ #[ pyarg( named, optional) ]
48+ co_code : OptionalArg < crate :: builtins:: PyBytesRef > ,
49+ #[ pyarg( named, optional) ]
50+ co_linetable : OptionalArg < crate :: builtins:: PyBytesRef > ,
51+ #[ pyarg( named, optional) ]
52+ co_exceptiontable : OptionalArg < crate :: builtins:: PyBytesRef > ,
53+ #[ pyarg( named, optional) ]
54+ co_freevars : OptionalArg < Vec < PyObjectRef > > ,
55+ #[ pyarg( named, optional) ]
56+ co_cellvars : OptionalArg < Vec < PyObjectRef > > ,
57+ #[ pyarg( named, optional) ]
58+ co_qualname : OptionalArg < PyStrRef > ,
4359}
4460
4561#[ derive( Clone ) ]
@@ -350,6 +366,34 @@ impl PyCode {
350366 vm. ctx . new_tuple ( names)
351367 }
352368
369+ #[ pygetset]
370+ pub fn co_linetable ( & self , vm : & VirtualMachine ) -> crate :: builtins:: PyBytesRef {
371+ // Return empty bytes for now - this should be the new line table format
372+ vm. ctx . new_bytes ( vec ! [ ] )
373+ }
374+
375+ #[ pygetset]
376+ pub fn co_exceptiontable ( & self , vm : & VirtualMachine ) -> crate :: builtins:: PyBytesRef {
377+ // Return empty bytes for now - this should be exception table
378+ vm. ctx . new_bytes ( vec ! [ ] )
379+ }
380+
381+ #[ pymethod]
382+ pub fn co_lines ( & self , vm : & VirtualMachine ) -> PyResult < PyObjectRef > {
383+ // Return an iterator over (start_offset, end_offset, lineno) tuples
384+ // For now, return an empty iterator
385+ let empty_list = vm. ctx . new_list ( vec ! [ ] ) ;
386+ vm. call_method ( empty_list. as_object ( ) , "__iter__" , ( ) )
387+ }
388+
389+ #[ pymethod]
390+ pub fn co_positions ( & self , vm : & VirtualMachine ) -> PyResult < PyObjectRef > {
391+ // Return an iterator over (line, end_line, column, end_column) tuples
392+ // For now, return an iterator that yields None tuples
393+ let empty_list = vm. ctx . new_list ( vec ! [ ] ) ;
394+ vm. call_method ( empty_list. as_object ( ) , "__iter__" , ( ) )
395+ }
396+
353397 #[ pymethod]
354398 pub fn replace ( & self , args : ReplaceArgs , vm : & VirtualMachine ) -> PyResult < Self > {
355399 let posonlyarg_count = match args. co_posonlyargcount {
@@ -408,6 +452,63 @@ impl PyCode {
408452 OptionalArg :: Missing => self . code . varnames . iter ( ) . map ( |s| s. to_object ( ) ) . collect ( ) ,
409453 } ;
410454
455+ let qualname = match args. co_qualname {
456+ OptionalArg :: Present ( qualname) => qualname,
457+ OptionalArg :: Missing => self . code . qualname . to_owned ( ) ,
458+ } ;
459+
460+ let max_stackdepth = match args. co_stacksize {
461+ OptionalArg :: Present ( stacksize) => stacksize,
462+ OptionalArg :: Missing => self . code . max_stackdepth ,
463+ } ;
464+
465+ let instructions = match args. co_code {
466+ OptionalArg :: Present ( _code_bytes) => {
467+ // Convert bytes back to instructions
468+ // For now, keep the original instructions
469+ // TODO: Properly parse bytecode from bytes
470+ self . code . instructions . clone ( )
471+ }
472+ OptionalArg :: Missing => self . code . instructions . clone ( ) ,
473+ } ;
474+
475+ let cellvars = match args. co_cellvars {
476+ OptionalArg :: Present ( cellvars) => cellvars
477+ . into_iter ( )
478+ . map ( |o| o. as_interned_str ( vm) . unwrap ( ) )
479+ . collect ( ) ,
480+ OptionalArg :: Missing => self . code . cellvars . clone ( ) ,
481+ } ;
482+
483+ let freevars = match args. co_freevars {
484+ OptionalArg :: Present ( freevars) => freevars
485+ . into_iter ( )
486+ . map ( |o| o. as_interned_str ( vm) . unwrap ( ) )
487+ . collect ( ) ,
488+ OptionalArg :: Missing => self . code . freevars . clone ( ) ,
489+ } ;
490+
491+ // Validate co_nlocals if provided
492+ if let OptionalArg :: Present ( nlocals) = args. co_nlocals {
493+ if nlocals as usize != varnames. len ( ) {
494+ return Err ( vm. new_value_error ( format ! (
495+ "co_nlocals ({}) != len(co_varnames) ({})" ,
496+ nlocals,
497+ varnames. len( )
498+ ) ) ) ;
499+ }
500+ }
501+
502+ // Note: co_linetable and co_exceptiontable are not stored in CodeObject yet
503+ // They would need to be added to the CodeObject structure
504+ // For now, just validate they are bytes if provided
505+ if let OptionalArg :: Present ( _linetable) = args. co_linetable {
506+ // Would store linetable if CodeObject supported it
507+ }
508+ if let OptionalArg :: Present ( _exceptiontable) = args. co_exceptiontable {
509+ // Would store exceptiontable if CodeObject supported it
510+ }
511+
411512 Ok ( Self {
412513 code : CodeObject {
413514 flags : CodeFlags :: from_bits_truncate ( flags) ,
@@ -417,10 +518,10 @@ impl PyCode {
417518 source_path : source_path. as_object ( ) . as_interned_str ( vm) . unwrap ( ) ,
418519 first_line_number,
419520 obj_name : obj_name. as_object ( ) . as_interned_str ( vm) . unwrap ( ) ,
420- qualname : self . code . qualname ,
521+ qualname : qualname . as_object ( ) . as_interned_str ( vm ) . unwrap ( ) ,
421522
422- max_stackdepth : self . code . max_stackdepth ,
423- instructions : self . code . instructions . clone ( ) ,
523+ max_stackdepth,
524+ instructions,
424525 locations : self . code . locations . clone ( ) ,
425526 constants : constants. into_iter ( ) . map ( Literal ) . collect ( ) ,
426527 names : names
@@ -431,8 +532,8 @@ impl PyCode {
431532 . into_iter ( )
432533 . map ( |o| o. as_interned_str ( vm) . unwrap ( ) )
433534 . collect ( ) ,
434- cellvars : self . code . cellvars . clone ( ) ,
435- freevars : self . code . freevars . clone ( ) ,
535+ cellvars,
536+ freevars,
436537 cell2arg : self . code . cell2arg . clone ( ) ,
437538 } ,
438539 } )
0 commit comments