use oxide_runtime_api::{NativeResult, VmHost}; use oxide_types::value::JsValue; mod annex_b; mod uri; /// 全局函数模块:聚合 Annex B 的 `escape`/`unescape` 与 URI 处理函数 /// (`encodeURI`/`decodeURI`/`encodeURIComponent`/`decodeURIComponent`)。 pub use annex_b::{js_escape, js_unescape}; /// URI 编解码全局函数(`encodeURI`/`decodeURI` 等)。 pub use uri::{decode_uri, decode_uri_component, encode_uri, encode_uri_component}; /// `isNaN(x)`:ToNumber 后检查是否为 NaN(隐式类型转换)。 /// /// ToNumber 可抛:Symbol 抛 TypeError,对象 ToPrimitive 触发 valueOf/toString /// 抛出的原生异常原样传播。 pub fn global_is_nan(vm: &mut H, args: &[u8]) -> NativeResult { let n = if args.len() < 2 { f64::NAN } else { match oxide_runtime_api::to_number_full(vm.reg(args[1]), vm) { Ok(n) => n, Err(_) => { if let Some(exc) = vm.take_uncaught_value() { return NativeResult::Err(exc); } return NativeResult::Err(crate::error::create_type_error(vm, "Cannot convert value to a number")); } } }; NativeResult::Ok(JsValue::bool(n.is_nan())) } /// `isFinite(x)`:ToNumber 后检查是否为有限数(隐式类型转换)。 /// /// ToNumber 可抛:Symbol 抛 TypeError,对象 ToPrimitive 触发 valueOf/toString /// 抛出的原生异常原样传播。 pub fn global_is_finite(vm: &mut H, args: &[u8]) -> NativeResult { let n = if args.len() < 2 { f64::NAN } else { match oxide_runtime_api::to_number_full(vm.reg(args[1]), vm) { Ok(n) => n, Err(_) => { if let Some(exc) = vm.take_uncaught_value() { return NativeResult::Err(exc); } return NativeResult::Err(crate::error::create_type_error(vm, "Cannot convert value to a number")); } } }; NativeResult::Ok(JsValue::bool(n.is_finite())) } /// `escape`/`unescape` 的字符串参数:按规范 `? ToString` 完整转换。 /// /// 对象经 ToPrimitive(string hint) 强制转换,Symbol 抛 TypeError,对象方法 /// 抛出的原生异常原样传播;缺省参数按 "undefined" 处理。 fn string_arg_full(vm: &mut H, args: &[u8]) -> Result { if args.len() > 1 { match oxide_runtime_api::to_string_full(vm.reg(args[1]), vm) { Ok(s) => Ok(s), Err(_) => { if let Some(exc) = vm.take_uncaught_value() { return Err(exc); } Err(crate::error::create_type_error(vm, "Cannot convert value to a string")) } } } else { Ok("undefined".to_string()) } } /// 解析两位十六进制单元为字节:逐位严格匹配十六进制数字,不带符号位 /// (`from_str_radix` 会接受 `+1`/`-1`,`%+1` 这类序列按规范须判非法)。 fn parse_hex_u8(slice: &[u8]) -> Option { let digit = |c: u8| match c { b'0'..=b'9' => Some(c - b'0'), b'a'..=b'f' => Some(c - b'a' + 10), b'A'..=b'F' => Some(c - b'A' + 10), _ => None, }; Some(digit(slice[0])? * 16 + digit(slice[1])?) }