use crate::executor::VirtualMachine;
use crate::executor::v2_handlers::v2_array_detect::{as_v2_typed_array, concat_arrays};
use crate::executor::vm_impl::stack::drop_with_kind;
use shape_value::heap_value::HeapKind;
use shape_value::{NativeKind, VMError};
use std::sync::Arc;
impl VirtualMachine {
#[inline]
pub(in crate::executor) fn op_string_concat(&mut self) -> Result<(), VMError> {
let (b_bits, b_kind) = self.pop_kinded()?;
let (a_bits, a_kind) = self.pop_kinded()?;
let result = match (read_string_or_char(a_bits, a_kind), read_string_or_char(b_bits, b_kind)) {
(Some(a), Some(b)) => format!("{}{}", a, b),
_ => {
drop_with_kind(a_bits, a_kind);
drop_with_kind(b_bits, b_kind);
return Err(VMError::TypeError {
expected: "string or char operands for StringConcat",
got: "non-string non-char",
});
}
};
drop_with_kind(a_bits, a_kind);
drop_with_kind(b_bits, b_kind);
let arc: Arc<String> = Arc::new(result);
let bits = Arc::into_raw(arc) as u64;
self.push_kinded(bits, NativeKind::String)
}
#[inline]
pub(in crate::executor) fn op_array_concat(&mut self) -> Result<(), VMError> {
let (b_bits, b_kind) = self.pop_kinded()?;
let (a_bits, a_kind) = self.pop_kinded()?;
let kinds_ok = matches!(
(a_kind, b_kind),
(
NativeKind::Ptr(HeapKind::TypedArray),
NativeKind::Ptr(HeapKind::TypedArray),
)
);
if !kinds_ok {
drop_with_kind(b_bits, b_kind);
drop_with_kind(a_bits, a_kind);
return Err(VMError::TypeError {
expected: "two TypedArray operands for ArrayConcat",
got: "non-TypedArray kind",
});
}
let view_a = as_v2_typed_array(a_bits, a_kind).ok_or_else(|| {
drop_with_kind(b_bits, b_kind);
drop_with_kind(a_bits, a_kind);
VMError::RuntimeError(
"ArrayConcat: operand A is not a v2 TypedArray (header mismatch)".into(),
)
})?;
let view_b = as_v2_typed_array(b_bits, b_kind).ok_or_else(|| {
drop_with_kind(b_bits, b_kind);
drop_with_kind(a_bits, a_kind);
VMError::RuntimeError(
"ArrayConcat: operand B is not a v2 TypedArray (header mismatch)".into(),
)
})?;
let result = concat_arrays(&view_a, &view_b);
drop_with_kind(b_bits, b_kind);
drop_with_kind(a_bits, a_kind);
let new_ptr = result.map_err(|e| VMError::RuntimeError(format!("ArrayConcat: {}", e)))?;
self.push_kinded(new_ptr as usize as u64, NativeKind::Ptr(HeapKind::TypedArray))
}
}
#[inline]
fn read_string_or_char(bits: u64, kind: NativeKind) -> Option<String> {
match kind {
NativeKind::String => unsafe {
Arc::increment_strong_count(bits as *const String);
let arc: Arc<String> = Arc::from_raw(bits as *const String);
let s = (*arc).clone();
drop(arc);
Some(s)
},
NativeKind::Ptr(HeapKind::String) => unsafe {
Arc::increment_strong_count(bits as *const String);
let arc: Arc<String> = Arc::from_raw(bits as *const String);
let s = (*arc).clone();
drop(arc);
Some(s)
},
NativeKind::Ptr(HeapKind::Char) => {
char::from_u32(bits as u32).map(|c| c.to_string())
}
_ => None,
}
}