Splice for `xs[a:b] = items` and `del xs[a:b]`. step=1 resizes; step≠1 demands exact-length RHS. Lists only, tuples/strings are immutable. */
(&mut self, cont: Val,start: Val, stop: Val, step: Val, new_items: Vec<Val>)
| 271 | |
| 272 | /* Splice for `xs[a:b] = items` and `del xs[a:b]`. step=1 resizes; step≠1 demands exact-length RHS. Lists only, tuples/strings are immutable. */ |
| 273 | fn store_slice(&mut self, cont: Val,start: Val, stop: Val, step: Val, new_items: Vec<Val>) -> Result<(), VmErr> { |
| 274 | let st = if step.is_none() { 1 } |
| 275 | else if step.is_int() { step.as_int() } |
| 276 | else { return Err(cold_type("slice step must be an integer")); }; |
| 277 | if st == 0 { return Err(cold_value("slice step cannot be zero")); } |
| 278 | |
| 279 | let HeapObj::List(rc) = self.heap.get_mut(cont) else { |
| 280 | return Err(cold_type("object does not support slice assignment")); |
| 281 | }; |
| 282 | let mut b = rc.borrow_mut(); |
| 283 | let len = b.len() as i64; |
| 284 | |
| 285 | let clamp = |v: Val, def: i64| -> i64 { |
| 286 | if v.is_none() { def } |
| 287 | else if v.is_int() { let i = v.as_int(); if i < 0 { (len + i).max(0) } else { i.min(len) } } |
| 288 | else { def } |
| 289 | }; |
| 290 | |
| 291 | if st == 1 { |
| 292 | let s = clamp(start, 0).max(0) as usize; |
| 293 | let e = clamp(stop, len).max(s as i64) as usize; |
| 294 | b.splice(s..e, new_items); |
| 295 | return Ok(()); |
| 296 | } |
| 297 | |
| 298 | // Extended slice (step!=1): collect indices; RHS length must match exactly. |
| 299 | // Negative-step start caps at len-1; clamp's min(len) alone would yield an out-of-range len. |
| 300 | let (s, e) = if st > 0 { (clamp(start, 0), clamp(stop, len)) } else { (clamp(start, len - 1).min(len - 1), clamp(stop, -1)) }; |
| 301 | let mut indices: Vec<usize> = Vec::new(); |
| 302 | let mut cur = s; |
| 303 | if st > 0 { while cur < e { indices.push(cur as usize); cur += st; } } |
| 304 | else { while cur > e { indices.push(cur as usize); cur += st; } } |
| 305 | |
| 306 | if new_items.is_empty() { |
| 307 | // Remove highest-index first so earlier indices stay valid. |
| 308 | let mut sorted = indices.clone(); |
| 309 | sorted.sort_unstable(); |
| 310 | for &i in sorted.iter().rev() { b.remove(i); } |
| 311 | return Ok(()); |
| 312 | } |
| 313 | if new_items.len() != indices.len() { |
| 314 | return Err(cold_value("attempt to assign sequence of one size to extended slice of another")); |
| 315 | } |
| 316 | for (i, v) in indices.into_iter().zip(new_items) { b[i] = v; } |
| 317 | Ok(()) |
| 318 | } |
| 319 | |
| 320 | // `slice(stop)` | `slice(start, stop)` | `slice(start, stop, step)`, builtin; usable as a sequence index. |
| 321 | pub fn call_slice(&mut self, argc: u16) -> Result<(), VmErr> { |