@@ -111,11 +111,29 @@ impl<'a> VM<'a> {
111111 HashMap :: with_capacity_and_hasher ( body. names . len ( ) , Default :: default ( ) ) ;
112112 for ( i, n) in body. names . iter ( ) . enumerate ( ) { body_map. insert ( n. as_str ( ) , i) ; }
113113
114- for ( i, param) in params. iter ( ) . enumerate ( ) {
115- if i >= positional. len ( ) { break ; }
116- let pname = format ! ( "{}_0" , param. trim_start_matches( '*' ) ) ;
117- if let Some ( & s) = body_map. get ( pname. as_str ( ) ) {
118- fn_slots[ s] = Some ( positional[ i] ) ;
114+ let mut pos_idx = 0usize ;
115+ for param in params. iter ( ) {
116+ if let Some ( star_name) = param. strip_prefix ( "**" ) {
117+ // **kwargs: not yet supported, skip
118+ let _ = star_name;
119+ } else if let Some ( var_name) = param. strip_prefix ( '*' ) {
120+ // *args: collect all remaining positionals into a list
121+ let rest: Vec < Val > = positional[ pos_idx..] . to_vec ( ) ;
122+ pos_idx = positional. len ( ) ;
123+ let list_val = self . heap . alloc (
124+ HeapObj :: List ( Rc :: new ( RefCell :: new ( rest) ) )
125+ ) ?;
126+ let pname = format ! ( "{}_0" , var_name) ;
127+ if let Some ( & s) = body_map. get ( pname. as_str ( ) ) {
128+ fn_slots[ s] = Some ( list_val) ;
129+ }
130+ } else {
131+ if pos_idx >= positional. len ( ) { continue ; }
132+ let pname = format ! ( "{}_0" , param) ;
133+ if let Some ( & s) = body_map. get ( pname. as_str ( ) ) {
134+ fn_slots[ s] = Some ( positional[ pos_idx] ) ;
135+ }
136+ pos_idx += 1 ;
119137 }
120138 }
121139
@@ -183,13 +201,37 @@ impl<'a> VM<'a> {
183201 self . live_slots . extend ( slots. iter ( ) . flatten ( ) . copied ( ) ) ;
184202 self . observed_impure . push ( false ) ;
185203
186- // Capturar el Result; cleanup corre incondicionalmente antes de propagar Err.
187204 let exec_result = self . exec ( body, & mut fn_slots) ;
188205
189206 let callee_impure = self . observed_impure . pop ( ) . unwrap_or ( true ) ;
190207 self . live_slots . truncate ( snap) ;
191208 self . depth -= 1 ;
192209
210+ // Write back nonlocal variables to the caller's slots.
211+ for base in & body. nonlocals {
212+ // Find the highest-versioned value in the callee's slots.
213+ let best = body. names . iter ( ) . enumerate ( )
214+ . filter_map ( |( i, n) | {
215+ let p = n. rfind ( '_' ) ?;
216+ ( n[ ..p] == * * base) . then_some ( ( ) ) ?;
217+ let ver: u32 = n[ p+1 ..] . parse ( ) . ok ( ) ?;
218+ Some ( ( ver, fn_slots[ i] ?) )
219+ } )
220+ . max_by_key ( |( ver, _) | * ver)
221+ . map ( |( _, val) | val) ;
222+
223+ if let Some ( val) = best {
224+ // Update all versions of this name in the caller's slots.
225+ for ( si, sname) in chunk. names . iter ( ) . enumerate ( ) {
226+ if let Some ( p) = sname. rfind ( '_' ) {
227+ if & sname[ ..p] == base. as_str ( ) && si < slots. len ( ) {
228+ slots[ si] = Some ( val) ;
229+ }
230+ }
231+ }
232+ }
233+ }
234+
193235 let result = exec_result?;
194236 if callee_impure { self . mark_impure ( ) ; }
195237
0 commit comments