mirror of
https://github.com/pjh456/OxideJS.git
synced 2026-10-23 18:21:13 +08:00
86 lines
3.3 KiB
Rust
86 lines
3.3 KiB
Rust
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<H: VmHost>(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<H: VmHost>(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` 完整转换,
|
||
/// 取 UTF-16 单元序列(不 lossy,孤立 surrogate 保真)。
|
||
///
|
||
/// 对象经 ToPrimitive(string hint) 强制转换,Symbol 抛 TypeError,对象方法
|
||
/// 抛出的原生异常原样传播;缺省参数按 "undefined" 处理。
|
||
fn units_arg_full<H: VmHost>(vm: &mut H, args: &[u8]) -> Result<Vec<u16>, JsValue> {
|
||
if args.len() > 1 {
|
||
match oxide_runtime_api::to_units_full(vm.reg(args[1]), vm) {
|
||
Ok(u) => Ok(u),
|
||
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".encode_utf16().collect())
|
||
}
|
||
}
|
||
|
||
/// 解析两位十六进制单元为字节:逐位严格匹配十六进制数字,不带符号位
|
||
/// (`from_str_radix` 会接受 `+1`/`-1`,`%+1` 这类序列按规范须判非法)。
|
||
fn parse_hex_u8(slice: &[u8]) -> Option<u8> {
|
||
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])?)
|
||
}
|