fix: parseInt/parseFloat 对象参数按 ToString 完整转换并传播异常
对象参数走 ToPrimitive(string hint) 后取串解析(toString 结果可见), Symbol 抛 TypeError,对象方法抛出的原始异常原样传播。
This commit is contained in:
@@ -117,7 +117,17 @@ pub fn number_parse_int<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
|||||||
if args.len() < 2 {
|
if args.len() < 2 {
|
||||||
return NativeResult::Ok(JsValue::float(f64::NAN));
|
return NativeResult::Ok(JsValue::float(f64::NAN));
|
||||||
}
|
}
|
||||||
let s = oxide_runtime_api::to_string(vm.reg(args[1]));
|
// 参数按 ToString 完整转换:对象经 ToPrimitive(string hint),Symbol 抛
|
||||||
|
// TypeError;对象方法抛出的原生异常原样传播。
|
||||||
|
let s = match oxide_runtime_api::to_string_full(vm.reg(args[1]), vm) {
|
||||||
|
Ok(s) => s,
|
||||||
|
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 string"));
|
||||||
|
}
|
||||||
|
};
|
||||||
let s = s.trim_start_matches(is_js_ws).trim_end_matches(is_js_ws);
|
let s = s.trim_start_matches(is_js_ws).trim_end_matches(is_js_ws);
|
||||||
|
|
||||||
// radix 经 ToInt32:缺省参数视为 undefined(ToInt32 → 0)。
|
// radix 经 ToInt32:缺省参数视为 undefined(ToInt32 → 0)。
|
||||||
@@ -212,7 +222,17 @@ pub fn number_parse_float<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
|||||||
if args.len() < 2 {
|
if args.len() < 2 {
|
||||||
return NativeResult::Ok(JsValue::float(f64::NAN));
|
return NativeResult::Ok(JsValue::float(f64::NAN));
|
||||||
}
|
}
|
||||||
let s = oxide_runtime_api::to_string(vm.reg(args[1]));
|
// 参数按 ToString 完整转换:对象经 ToPrimitive(string hint),Symbol 抛
|
||||||
|
// TypeError;对象方法抛出的原生异常原样传播。
|
||||||
|
let s = match oxide_runtime_api::to_string_full(vm.reg(args[1]), vm) {
|
||||||
|
Ok(s) => s,
|
||||||
|
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 string"));
|
||||||
|
}
|
||||||
|
};
|
||||||
let s = s.trim_start_matches(is_js_ws).trim_end_matches(is_js_ws);
|
let s = s.trim_start_matches(is_js_ws).trim_end_matches(is_js_ws);
|
||||||
|
|
||||||
// 读符号;`Infinity` 大小写敏感,其后可带任意后缀(取最长合法前缀)。
|
// 读符号;`Infinity` 大小写敏感,其后可带任意后缀(取最长合法前缀)。
|
||||||
|
|||||||
@@ -145,6 +145,26 @@ fn parse_float_prefix_semantics() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn parse_parse_int_object_arg_tostring() {
|
||||||
|
let mut vm = Vm::new();
|
||||||
|
// 对象参数经 ToString 完整转换:取 toString 结果再解析。
|
||||||
|
let result = eval(&mut vm, "parseInt({toString: () => '42'})").unwrap();
|
||||||
|
assert_eq!(result.as_int(), 42);
|
||||||
|
#[allow(clippy::approx_constant)]
|
||||||
|
let expected = 3.14;
|
||||||
|
let result = eval(&mut vm, "parseFloat({toString: () => '3.14abc'})").unwrap();
|
||||||
|
assert!((result.as_double() - expected).abs() < 0.001);
|
||||||
|
// Symbol 参数按规范抛 TypeError。
|
||||||
|
let err = eval(&mut vm, "parseInt(Symbol())").unwrap_err();
|
||||||
|
assert!(err.contains("TypeError"), "got: {}", err);
|
||||||
|
let err = eval(&mut vm, "parseFloat(Symbol('x'))").unwrap_err();
|
||||||
|
assert!(err.contains("TypeError"), "got: {}", err);
|
||||||
|
// 对象 toString 抛出的原始异常原样传播(保留异常对象)。
|
||||||
|
let err = eval(&mut vm, "try { parseInt({toString(){ throw 42 }}) } catch (e) { e }").unwrap();
|
||||||
|
assert_eq!(err.as_int(), 42);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn number_constructor() {
|
fn number_constructor() {
|
||||||
let mut vm = Vm::new();
|
let mut vm = Vm::new();
|
||||||
|
|||||||
Reference in New Issue
Block a user