From 03db51015ec1879e6386281833ed635ea4300464 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=88=B1=E7=89=B9=E6=AF=8F=E7=BE=8A=E9=98=9F?= Date: Mon, 29 Jun 2026 00:37:51 +0800 Subject: [PATCH] fix: as_string uses to_string_full, split regex fallback, undefined sep (cherry picked from commit 7078a65b9d7055b97bb97232e3426ced4789c26f) --- crates/oxide_builtins/src/string.rs | 67 ++++++++++++++--------------- 1 file changed, 32 insertions(+), 35 deletions(-) diff --git a/crates/oxide_builtins/src/string.rs b/crates/oxide_builtins/src/string.rs index 6b39454..0e73caf 100644 --- a/crates/oxide_builtins/src/string.rs +++ b/crates/oxide_builtins/src/string.rs @@ -9,7 +9,12 @@ use crate::builtins_debug; use crate::builtins_error; fn this_string(vm: &H, args: &[u8]) -> String { - oxide_runtime_api::to_string(vm.reg(args[0])) + let this_val = vm.reg(args[0]); + if this_val.is_null() || this_val.is_undefined() { + String::new() // caller should check and throw TypeError + } else { + oxide_runtime_api::to_string(this_val) + } } pub fn string_from_char_code(vm: &mut H, args: &[u8]) -> NativeResult { @@ -116,8 +121,8 @@ fn make_string_array(vm: &mut H, parts: &[String]) -> JsValue { JsValue::from_js_object(arr) } -fn as_string(_vm: &H, val: JsValue) -> String { - oxide_runtime_api::to_string(val) +fn as_string(vm: &mut H, val: JsValue) -> String { + oxide_runtime_api::to_string_full(val, vm).unwrap_or_else(|_| oxide_runtime_api::to_string(val)) } fn char_len(s: &str) -> usize { @@ -515,52 +520,44 @@ pub fn string_ends_with(vm: &mut H, args: &[u8]) -> NativeResult { pub fn string_split(vm: &mut H, args: &[u8]) -> NativeResult { builtins_debug!("String.prototype.split called with {} args", args.len()); let s = this_string(vm, args); - if args.len() < 2 { + // Spec: if separator is undefined, return [string] + if args.len() < 2 || vm.reg(args[1]).is_undefined() { let parts = vec![s.clone()]; return NativeResult::Ok(make_string_array(vm, &parts)); } let sep_val = vm.reg(args[1]); + // ToUint32(limit), default 2^32-1 let limit = if args.len() > 2 { - oxide_runtime_api::to_integer_or_infinity(vm.reg(args[2])) as usize + let l = oxide_runtime_api::to_integer_or_infinity(vm.reg(args[2])); + if l.is_infinite() { u32::MAX as usize } else { (l.max(0.0).trunc() as u64).min(u32::MAX as u64) as usize } } else { - usize::MAX + u32::MAX as usize }; if is_regexp_obj(sep_val, vm) { let re_ptr = sep_val.as_js_object_ptr(); let re = unsafe { &*re_ptr }; - let fn_ptr = match re.native_fn() { - Some(p) => p, - None => { - let parts = vec![s.clone()]; - return NativeResult::Ok(make_string_array(vm, &parts)); - } - }; - let regex = unsafe { &*(fn_ptr.as_ptr() as *const regex::Regex) }; - let mut parts: Vec = Vec::new(); - let mut last_end = 0; - for caps in regex.captures_iter(&s) { - if parts.len() >= limit { - break; - } - let full = caps.get(0).unwrap(); - parts.push(s[last_end..full.start()].to_string()); - if parts.len() >= limit { - break; - } - for i in 1..caps.len() { - if parts.len() >= limit { - break; + if let Some(fn_ptr) = re.native_fn() { + let regex = unsafe { &*(fn_ptr.as_ptr() as *const regex::Regex) }; + let mut parts: Vec = Vec::new(); + let mut last_end = 0; + for caps in regex.captures_iter(&s) { + if parts.len() >= limit { break; } + let full = caps.get(0).unwrap(); + parts.push(s[last_end..full.start()].to_string()); + if parts.len() >= limit { break; } + for i in 1..caps.len() { + if parts.len() >= limit { break; } + parts.push(caps.get(i).map(|m| m.as_str()).unwrap_or("").to_string()); } - let cap = caps.get(i).map(|m| m.as_str()).unwrap_or(""); - parts.push(cap.to_string()); + last_end = full.end(); } - last_end = full.end(); + if last_end <= s.len() && parts.len() < limit { + parts.push(s[last_end..].to_string()); + } + return NativeResult::Ok(make_string_array(vm, &parts)); } - if last_end <= s.len() && parts.len() < limit { - parts.push(s[last_end..].to_string()); - } - return NativeResult::Ok(make_string_array(vm, &parts)); + // Fall back to string path for regex-like objects without native engine regex } let sep = as_string(vm, sep_val);