(&mut self, a: Val, b: Val)
| 434 | Err(VmErr::TypeMsg(s!("argument of type '", str self.type_name(container), "' is not iterable"))) |
| 435 | } |
| 436 | pub fn add_vals(&mut self, a: Val, b: Val) -> Result<Val, VmErr> { |
| 437 | // Inline-int fast path; overflow falls through to the i128 slow path. |
| 438 | if a.is_int() && b.is_int() |
| 439 | && let Some(r) = a.as_int().checked_add(b.as_int()) |
| 440 | && (Val::INT_MIN..=Val::INT_MAX).contains(&r) { |
| 441 | return Ok(Val::int(r)); |
| 442 | } |
| 443 | if let Some((af, bf)) = coerce_floats(a, b, &self.heap) { return Ok(Val::float(af + bf)); } |
| 444 | // Wide-int slow path; int_to_val picks the narrowest storage class. |
| 445 | if let (Some(ai), Some(bi)) = (as_i128(a, &self.heap), as_i128(b, &self.heap)) { |
| 446 | return self.int_to_val(ai.checked_add(bi)); |
| 447 | } |
| 448 | if a.is_heap() && b.is_heap() { |
| 449 | // Charge the copy cost so growing concatenation in a loop stays bounded (avoids O(n^2)). |
| 450 | let copy_cost = match (self.heap.get(a), self.heap.get(b)) { |
| 451 | (HeapObj::Str(sa), HeapObj::Str(sb)) => Some(sa.len() + sb.len()), |
| 452 | (HeapObj::List(va), HeapObj::List(vb)) => Some(va.borrow().len() + vb.borrow().len()), |
| 453 | (HeapObj::Tuple(va), HeapObj::Tuple(vb)) => Some(va.len() + vb.len()), |
| 454 | _ => None, |
| 455 | }; |
| 456 | if let Some(n) = copy_cost { self.charge_steps(n)?; } |
| 457 | match (self.heap.get(a), self.heap.get(b)) { |
| 458 | (HeapObj::Str(sa), HeapObj::Str(sb)) => { |
| 459 | let sa = sa.clone(); |
| 460 | let sb = sb.clone(); |
| 461 | let mut r = String::with_capacity(sa.len() + sb.len()); |
| 462 | r.push_str(&sa); r.push_str(&sb); |
| 463 | return self.heap.alloc(HeapObj::Str(r)); |
| 464 | } |
| 465 | (HeapObj::List(va), HeapObj::List(vb)) => { |
| 466 | let mut lst = va.borrow().clone(); lst.extend_from_slice(&vb.borrow()); |
| 467 | return self.heap.alloc(HeapObj::List(Rc::new(RefCell::new(lst)))); |
| 468 | } |
| 469 | (HeapObj::Tuple(va), HeapObj::Tuple(vb)) => { |
| 470 | let mut tup = va.clone(); tup.extend_from_slice(vb); |
| 471 | return self.heap.alloc(HeapObj::Tuple(tup)); |
| 472 | } |
| 473 | _ => {} |
| 474 | } |
| 475 | } |
| 476 | Err(VmErr::TypeMsg(s!("unsupported operand type(s) for +: '", str self.type_name(a), "' and '", str self.type_name(b), "'"))) |
| 477 | } |
| 478 | |
| 479 | pub fn sub_vals(&mut self, a: Val, b: Val) -> Result<Val, VmErr> { |
| 480 | if a.is_int() && b.is_int() |
no test coverage detected