avm2: Re-use code in `coerce_to_number`
Use `string_to_f64` and `string_to_int`, as [`MathUtils::convertStringToNumber`](858d034a3b/core/MathUtils.cpp (L453-L466)
)
in avmplus does.
This commit is contained in:
parent
265dcd2e8d
commit
9c1a05aaaf
|
@ -54,82 +54,6 @@ pub fn is_nan<'gc>(
|
|||
}
|
||||
}
|
||||
|
||||
/// Converts a `WStr` to an integer (as an `f64`).
|
||||
///
|
||||
/// This function might fail for some invalid inputs, by returning `f64::NAN`.
|
||||
///
|
||||
/// `radix` is only valid in the range `2..=36`, plus the special `0` value, which means the
|
||||
/// radix is inferred from the string; hexadecimal if it starts with a `0x` prefix (case
|
||||
/// insensitive), or decimal otherwise.
|
||||
/// `strict` tells whether to fail on trailing garbage, or ignore it.
|
||||
fn string_to_int(mut s: &WStr, mut radix: i32, strict: bool) -> f64 {
|
||||
// Allow leading whitespace.
|
||||
skip_spaces(&mut s);
|
||||
|
||||
let is_negative = parse_sign(&mut s);
|
||||
|
||||
if radix == 16 || radix == 0 {
|
||||
if let Some(after_0x) = s
|
||||
.strip_prefix(WStr::from_units(b"0x"))
|
||||
.or_else(|| s.strip_prefix(WStr::from_units(b"0X")))
|
||||
{
|
||||
// Consume hexadecimal prefix.
|
||||
s = after_0x;
|
||||
|
||||
// Explicit hexadecimal.
|
||||
radix = 16;
|
||||
} else if radix == 0 {
|
||||
// Default to decimal.
|
||||
radix = 10;
|
||||
}
|
||||
}
|
||||
|
||||
// Fail on invalid radix or blank string.
|
||||
if !(2..=36).contains(&radix) || s.is_empty() {
|
||||
return f64::NAN;
|
||||
}
|
||||
|
||||
// Actual number parsing.
|
||||
let mut result = 0.0;
|
||||
let start = s;
|
||||
s = s.trim_start_matches(|c| {
|
||||
match u8::try_from(c)
|
||||
.ok()
|
||||
.and_then(|c| char::from(c).to_digit(radix as u32))
|
||||
{
|
||||
Some(digit) => {
|
||||
result *= f64::from(radix);
|
||||
result += f64::from(digit);
|
||||
true
|
||||
}
|
||||
None => false,
|
||||
}
|
||||
});
|
||||
|
||||
// Fail if we got no digits.
|
||||
// TODO: Compare by reference instead?
|
||||
if s.len() == start.len() {
|
||||
return f64::NAN;
|
||||
}
|
||||
|
||||
if strict {
|
||||
// Allow trailing whitespace.
|
||||
skip_spaces(&mut s);
|
||||
|
||||
// Fail if we got digits, but we're in strict mode and not at end of string.
|
||||
if !s.is_empty() {
|
||||
return f64::NAN;
|
||||
}
|
||||
}
|
||||
|
||||
// Apply sign.
|
||||
if is_negative {
|
||||
result = -result;
|
||||
}
|
||||
|
||||
result
|
||||
}
|
||||
|
||||
pub fn parse_int<'gc>(
|
||||
activation: &mut Activation<'_, 'gc, '_>,
|
||||
_this: Option<Object<'gc>>,
|
||||
|
@ -145,224 +69,10 @@ pub fn parse_int<'gc>(
|
|||
None => 0,
|
||||
};
|
||||
|
||||
let result = string_to_int(&string, radix, false);
|
||||
let result = crate::avm2::value::string_to_int(&string, radix, false);
|
||||
Ok(result.into())
|
||||
}
|
||||
|
||||
/// Strips leading whitespace.
|
||||
fn skip_spaces(s: &mut &WStr) {
|
||||
*s = s.trim_start_matches(|c| {
|
||||
matches!(
|
||||
c,
|
||||
0x20 | 0x09 | 0x0d | 0x0a | 0x0c | 0x0b | 0x2000
|
||||
..=0x200b | 0x2028 | 0x2029 | 0x205f | 0x3000
|
||||
)
|
||||
});
|
||||
}
|
||||
|
||||
/// Consumes an optional sign character.
|
||||
/// Returns whether a minus sign was consumed.
|
||||
fn parse_sign(s: &mut &WStr) -> bool {
|
||||
if let Some(after_sign) = s.strip_prefix(b'-') {
|
||||
*s = after_sign;
|
||||
true
|
||||
} else if let Some(after_sign) = s.strip_prefix(b'+') {
|
||||
*s = after_sign;
|
||||
false
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
/// Converts a `WStr` to an `f64`.
|
||||
///
|
||||
/// This function might fail for some invalid inputs, by returning `None`.
|
||||
///
|
||||
/// `strict` typically tells whether to behave like `Number()` or `parseFloat()`:
|
||||
/// * `strict == true` fails on trailing garbage, but interprets blank strings (which are empty or consist only of whitespace) as zero.
|
||||
/// * `strict == false` ignores trailing garbage, but fails on blank strings.
|
||||
fn string_to_f64(mut s: &WStr, swf_version: u8, strict: bool) -> Option<f64> {
|
||||
fn is_ascii_digit(c: u16) -> bool {
|
||||
u8::try_from(c).map_or(false, |c| c.is_ascii_digit())
|
||||
}
|
||||
|
||||
// Allow leading whitespace.
|
||||
skip_spaces(&mut s);
|
||||
|
||||
// Handle blank strings as described above.
|
||||
if s.is_empty() {
|
||||
return if strict { Some(0.0) } else { None };
|
||||
}
|
||||
|
||||
// Parse sign.
|
||||
let is_negative = parse_sign(&mut s);
|
||||
let after_sign = s;
|
||||
|
||||
// Count digits before decimal point.
|
||||
s = s.trim_start_matches(is_ascii_digit);
|
||||
let mut total_digits = after_sign.len() - s.len();
|
||||
|
||||
// Count digits after decimal point.
|
||||
if let Some(after_dot) = s.strip_prefix(b'.') {
|
||||
s = after_dot;
|
||||
s = s.trim_start_matches(is_ascii_digit);
|
||||
total_digits += after_dot.len() - s.len();
|
||||
}
|
||||
|
||||
// Handle exponent.
|
||||
let mut exponent: i32 = 0;
|
||||
if let Some(after_e) = s.strip_prefix(b"eE".as_ref()) {
|
||||
s = after_e;
|
||||
|
||||
// Parse exponent sign.
|
||||
let exponent_is_negative = parse_sign(&mut s);
|
||||
|
||||
// Fail if string ends with "e-" with no exponent value specified.
|
||||
if exponent_is_negative && s.is_empty() {
|
||||
return None;
|
||||
}
|
||||
|
||||
// Parse exponent itself.
|
||||
s = s.trim_start_matches(|c| {
|
||||
match u8::try_from(c)
|
||||
.ok()
|
||||
.and_then(|c| char::from(c).to_digit(10))
|
||||
{
|
||||
Some(digit) => {
|
||||
exponent = exponent.wrapping_mul(10);
|
||||
exponent = exponent.wrapping_add(digit as i32);
|
||||
true
|
||||
}
|
||||
None => false,
|
||||
}
|
||||
});
|
||||
|
||||
// Apply exponent sign.
|
||||
if exponent_is_negative {
|
||||
exponent = exponent.wrapping_neg();
|
||||
}
|
||||
}
|
||||
|
||||
// Allow trailing whitespace.
|
||||
skip_spaces(&mut s);
|
||||
|
||||
// If we got no digits, check for Infinity/-Infinity. Otherwise fail.
|
||||
if total_digits == 0 {
|
||||
if let Some(after_infinity) = s.strip_prefix(WStr::from_units(b"Infinity")) {
|
||||
s = after_infinity;
|
||||
|
||||
// Allow end of string or a whitespace. Otherwise fail.
|
||||
if !s.is_empty() {
|
||||
skip_spaces(&mut s);
|
||||
// TODO: Compare by reference instead?
|
||||
if s.len() == after_infinity.len() {
|
||||
return None;
|
||||
}
|
||||
}
|
||||
|
||||
let result = if is_negative {
|
||||
f64::NEG_INFINITY
|
||||
} else {
|
||||
f64::INFINITY
|
||||
};
|
||||
return Some(result);
|
||||
}
|
||||
return None;
|
||||
}
|
||||
|
||||
// Fail if we got digits, but we're in strict mode and not at end of string or at a null character.
|
||||
if strict && !s.is_empty() && !s.starts_with(b'\0') {
|
||||
return None;
|
||||
}
|
||||
|
||||
// Bug compatibility: https://bugzilla.mozilla.org/show_bug.cgi?id=513018
|
||||
let s = if swf_version >= 11 {
|
||||
&after_sign[..after_sign.len() - s.len()]
|
||||
} else {
|
||||
after_sign
|
||||
};
|
||||
|
||||
// Finally, calculate the result.
|
||||
let mut result = if total_digits > 15 {
|
||||
// With more than 15 digits, avmplus uses integer arithmetic to avoid rounding errors.
|
||||
let mut result: i64 = 0;
|
||||
let mut decimal_digits = -1;
|
||||
for c in s {
|
||||
if let Some(digit) = u8::try_from(c)
|
||||
.ok()
|
||||
.and_then(|c| char::from(c).to_digit(10))
|
||||
{
|
||||
if decimal_digits != -1 {
|
||||
decimal_digits += 1;
|
||||
}
|
||||
|
||||
result *= 10;
|
||||
result += i64::from(digit);
|
||||
} else if c == b'.' as u16 {
|
||||
decimal_digits = 0;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if decimal_digits > 0 {
|
||||
exponent -= decimal_digits;
|
||||
}
|
||||
|
||||
if exponent > 0 {
|
||||
result *= i64::pow(10, exponent as u32);
|
||||
}
|
||||
|
||||
result as f64
|
||||
} else {
|
||||
let mut result = 0.0;
|
||||
let mut decimal_digits = -1;
|
||||
for c in s {
|
||||
if let Some(digit) = u8::try_from(c)
|
||||
.ok()
|
||||
.and_then(|c| char::from(c).to_digit(10))
|
||||
{
|
||||
if decimal_digits != -1 {
|
||||
decimal_digits += 1;
|
||||
}
|
||||
|
||||
result *= 10.0;
|
||||
result += digit as f64;
|
||||
} else if c == b'.' as u16 {
|
||||
decimal_digits = 0;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if decimal_digits > 0 {
|
||||
exponent -= decimal_digits;
|
||||
}
|
||||
|
||||
if exponent > 0 {
|
||||
result *= f64::powi(10.0, exponent);
|
||||
}
|
||||
|
||||
result
|
||||
};
|
||||
|
||||
if exponent < 0 {
|
||||
if exponent < -307 {
|
||||
let diff = exponent + 307;
|
||||
result /= f64::powi(10.0, -diff);
|
||||
exponent = -307;
|
||||
}
|
||||
result /= f64::powi(10.0, -exponent);
|
||||
}
|
||||
|
||||
// Apply sign.
|
||||
if is_negative {
|
||||
result = -result;
|
||||
}
|
||||
|
||||
Some(result)
|
||||
}
|
||||
|
||||
pub fn parse_float<'gc>(
|
||||
activation: &mut Activation<'_, 'gc, '_>,
|
||||
_this: Option<Object<'gc>>,
|
||||
|
@ -371,7 +81,7 @@ pub fn parse_float<'gc>(
|
|||
if let Some(value) = args.get(0) {
|
||||
let string = value.coerce_to_string(activation)?;
|
||||
let swf_version = activation.context.swf.version();
|
||||
if let Some(result) = string_to_f64(&string, swf_version, false) {
|
||||
if let Some(result) = crate::avm2::value::string_to_f64(&string, swf_version, false) {
|
||||
return Ok(result.into());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -138,6 +138,295 @@ impl PartialEq for Value<'_> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Strips leading whitespace.
|
||||
fn skip_spaces(s: &mut &WStr) {
|
||||
*s = s.trim_start_matches(|c| {
|
||||
matches!(
|
||||
c,
|
||||
0x20 | 0x09 | 0x0d | 0x0a | 0x0c | 0x0b | 0x2000
|
||||
..=0x200b | 0x2028 | 0x2029 | 0x205f | 0x3000
|
||||
)
|
||||
});
|
||||
}
|
||||
|
||||
/// Consumes an optional sign character.
|
||||
/// Returns whether a minus sign was consumed.
|
||||
fn parse_sign(s: &mut &WStr) -> bool {
|
||||
if let Some(after_sign) = s.strip_prefix(b'-') {
|
||||
*s = after_sign;
|
||||
true
|
||||
} else if let Some(after_sign) = s.strip_prefix(b'+') {
|
||||
*s = after_sign;
|
||||
false
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
/// Converts a `WStr` to an integer (as an `f64`).
|
||||
///
|
||||
/// This function might fail for some invalid inputs, by returning `f64::NAN`.
|
||||
///
|
||||
/// `radix` is only valid in the range `2..=36`, plus the special `0` value, which means the
|
||||
/// radix is inferred from the string; hexadecimal if it starts with a `0x` prefix (case
|
||||
/// insensitive), or decimal otherwise.
|
||||
/// `strict` tells whether to fail on trailing garbage, or ignore it.
|
||||
pub fn string_to_int(mut s: &WStr, mut radix: i32, strict: bool) -> f64 {
|
||||
// Allow leading whitespace.
|
||||
skip_spaces(&mut s);
|
||||
|
||||
let is_negative = parse_sign(&mut s);
|
||||
|
||||
if radix == 16 || radix == 0 {
|
||||
if let Some(after_0x) = s
|
||||
.strip_prefix(WStr::from_units(b"0x"))
|
||||
.or_else(|| s.strip_prefix(WStr::from_units(b"0X")))
|
||||
{
|
||||
// Consume hexadecimal prefix.
|
||||
s = after_0x;
|
||||
|
||||
// Explicit hexadecimal.
|
||||
radix = 16;
|
||||
} else if radix == 0 {
|
||||
// Default to decimal.
|
||||
radix = 10;
|
||||
}
|
||||
}
|
||||
|
||||
// Fail on invalid radix or blank string.
|
||||
if !(2..=36).contains(&radix) || s.is_empty() {
|
||||
return f64::NAN;
|
||||
}
|
||||
|
||||
// Actual number parsing.
|
||||
let mut result = 0.0;
|
||||
let start = s;
|
||||
s = s.trim_start_matches(|c| {
|
||||
match u8::try_from(c)
|
||||
.ok()
|
||||
.and_then(|c| char::from(c).to_digit(radix as u32))
|
||||
{
|
||||
Some(digit) => {
|
||||
result *= f64::from(radix);
|
||||
result += f64::from(digit);
|
||||
true
|
||||
}
|
||||
None => false,
|
||||
}
|
||||
});
|
||||
|
||||
// Fail if we got no digits.
|
||||
// TODO: Compare by reference instead?
|
||||
if s.len() == start.len() {
|
||||
return f64::NAN;
|
||||
}
|
||||
|
||||
if strict {
|
||||
// Allow trailing whitespace.
|
||||
skip_spaces(&mut s);
|
||||
|
||||
// Fail if we got digits, but we're in strict mode and not at end of string.
|
||||
if !s.is_empty() {
|
||||
return f64::NAN;
|
||||
}
|
||||
}
|
||||
|
||||
// Apply sign.
|
||||
if is_negative {
|
||||
result = -result;
|
||||
}
|
||||
|
||||
// We should only return integers and +/-Infinity.
|
||||
debug_assert!(result.is_infinite() || result.fract() == 0.0);
|
||||
result
|
||||
}
|
||||
|
||||
/// Converts a `WStr` to an `f64`.
|
||||
///
|
||||
/// This function might fail for some invalid inputs, by returning `None`.
|
||||
///
|
||||
/// `strict` typically tells whether to behave like `Number()` or `parseFloat()`:
|
||||
/// * `strict == true` fails on trailing garbage, but interprets blank strings (which are empty or consist only of whitespace) as zero.
|
||||
/// * `strict == false` ignores trailing garbage, but fails on blank strings.
|
||||
pub fn string_to_f64(mut s: &WStr, swf_version: u8, strict: bool) -> Option<f64> {
|
||||
fn is_ascii_digit(c: u16) -> bool {
|
||||
u8::try_from(c).map_or(false, |c| c.is_ascii_digit())
|
||||
}
|
||||
|
||||
fn to_decimal_digit(c: u16) -> Option<u32> {
|
||||
u8::try_from(c)
|
||||
.ok()
|
||||
.and_then(|c| char::from(c).to_digit(10))
|
||||
}
|
||||
|
||||
// Allow leading whitespace.
|
||||
skip_spaces(&mut s);
|
||||
|
||||
// Handle blank strings as described above.
|
||||
if s.is_empty() {
|
||||
return if strict { Some(0.0) } else { None };
|
||||
}
|
||||
|
||||
// Parse sign.
|
||||
let is_negative = parse_sign(&mut s);
|
||||
let after_sign = s;
|
||||
|
||||
// Count digits before decimal point.
|
||||
s = s.trim_start_matches(is_ascii_digit);
|
||||
let mut total_digits = after_sign.len() - s.len();
|
||||
|
||||
// Count digits after decimal point.
|
||||
if let Some(after_dot) = s.strip_prefix(b'.') {
|
||||
s = after_dot;
|
||||
s = s.trim_start_matches(is_ascii_digit);
|
||||
total_digits += after_dot.len() - s.len();
|
||||
}
|
||||
|
||||
// Handle exponent.
|
||||
let mut exponent: i32 = 0;
|
||||
if let Some(after_e) = s.strip_prefix(b"eE".as_ref()) {
|
||||
s = after_e;
|
||||
|
||||
// Parse exponent sign.
|
||||
let exponent_is_negative = parse_sign(&mut s);
|
||||
|
||||
// Fail if string ends with "e-" with no exponent value specified.
|
||||
if exponent_is_negative && s.is_empty() {
|
||||
return None;
|
||||
}
|
||||
|
||||
// Parse exponent itself.
|
||||
s = s.trim_start_matches(|c| match to_decimal_digit(c) {
|
||||
Some(digit) => {
|
||||
exponent = exponent.wrapping_mul(10);
|
||||
exponent = exponent.wrapping_add(digit as i32);
|
||||
true
|
||||
}
|
||||
None => false,
|
||||
});
|
||||
|
||||
// Apply exponent sign.
|
||||
if exponent_is_negative {
|
||||
exponent = exponent.wrapping_neg();
|
||||
}
|
||||
}
|
||||
|
||||
// Allow trailing whitespace.
|
||||
skip_spaces(&mut s);
|
||||
|
||||
// If we got no digits, check for Infinity/-Infinity. Otherwise fail.
|
||||
if total_digits == 0 {
|
||||
if let Some(after_infinity) = s.strip_prefix(WStr::from_units(b"Infinity")) {
|
||||
s = after_infinity;
|
||||
|
||||
// Allow end of string or a whitespace. Otherwise fail.
|
||||
if !s.is_empty() {
|
||||
skip_spaces(&mut s);
|
||||
// TODO: Compare by reference instead?
|
||||
if s.len() == after_infinity.len() {
|
||||
return None;
|
||||
}
|
||||
}
|
||||
|
||||
let result = if is_negative {
|
||||
f64::NEG_INFINITY
|
||||
} else {
|
||||
f64::INFINITY
|
||||
};
|
||||
return Some(result);
|
||||
}
|
||||
return None;
|
||||
}
|
||||
|
||||
// Fail if we got digits, but we're in strict mode and not at end of string or at a null character.
|
||||
if strict && !s.is_empty() && !s.starts_with(b'\0') {
|
||||
return None;
|
||||
}
|
||||
|
||||
// Bug compatibility: https://bugzilla.mozilla.org/show_bug.cgi?id=513018
|
||||
let s = if swf_version >= 11 {
|
||||
&after_sign[..after_sign.len() - s.len()]
|
||||
} else {
|
||||
after_sign
|
||||
};
|
||||
|
||||
// Finally, calculate the result.
|
||||
let mut result = if total_digits > 15 {
|
||||
// With more than 15 digits, avmplus uses integer arithmetic to avoid rounding errors.
|
||||
let mut result: i64 = 0;
|
||||
let mut decimal_digits = -1;
|
||||
for c in s {
|
||||
if let Some(digit) = to_decimal_digit(c) {
|
||||
if decimal_digits != -1 {
|
||||
decimal_digits += 1;
|
||||
}
|
||||
|
||||
result *= 10;
|
||||
result += i64::from(digit);
|
||||
} else if c == b'.' as u16 {
|
||||
decimal_digits = 0;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if decimal_digits > 0 {
|
||||
exponent -= decimal_digits;
|
||||
}
|
||||
|
||||
if exponent > 0 {
|
||||
result *= i64::pow(10, exponent as u32);
|
||||
}
|
||||
|
||||
result as f64
|
||||
} else {
|
||||
let mut result = 0.0;
|
||||
let mut decimal_digits = -1;
|
||||
for c in s {
|
||||
if let Some(digit) = to_decimal_digit(c) {
|
||||
if decimal_digits != -1 {
|
||||
decimal_digits += 1;
|
||||
}
|
||||
|
||||
result *= 10.0;
|
||||
result += digit as f64;
|
||||
} else if c == b'.' as u16 {
|
||||
decimal_digits = 0;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if decimal_digits > 0 {
|
||||
exponent -= decimal_digits;
|
||||
}
|
||||
|
||||
if exponent > 0 {
|
||||
result *= f64::powi(10.0, exponent);
|
||||
}
|
||||
|
||||
result
|
||||
};
|
||||
|
||||
if exponent < 0 {
|
||||
if exponent < -307 {
|
||||
let diff = exponent + 307;
|
||||
result /= f64::powi(10.0, -diff);
|
||||
exponent = -307;
|
||||
}
|
||||
result /= f64::powi(10.0, -exponent);
|
||||
}
|
||||
|
||||
// Apply sign.
|
||||
if is_negative {
|
||||
result = -result;
|
||||
}
|
||||
|
||||
// We shouldn't return `NaN` after a successful parsing.
|
||||
debug_assert!(!result.is_nan());
|
||||
Some(result)
|
||||
}
|
||||
|
||||
pub fn abc_int(translation_unit: TranslationUnit<'_>, index: Index<i32>) -> Result<i32, Error> {
|
||||
if index.0 == 0 {
|
||||
return Ok(0);
|
||||
|
@ -384,44 +673,8 @@ impl<'gc> Value<'gc> {
|
|||
Value::Unsigned(u) => *u as f64,
|
||||
Value::Integer(i) => *i as f64,
|
||||
Value::String(s) => {
|
||||
let strim = s.trim();
|
||||
if strim.is_empty() {
|
||||
0.0
|
||||
} else if strim.starts_with(WStr::from_units(b"0x"))
|
||||
|| strim.starts_with(WStr::from_units(b"0X"))
|
||||
{
|
||||
let mut n: f64 = 0.0;
|
||||
for c in &strim[2..] {
|
||||
let digit = u8::try_from(c).ok().and_then(|c| (c as char).to_digit(16));
|
||||
if let Some(digit) = digit {
|
||||
n = 16.0 * n + f64::from(digit);
|
||||
} else {
|
||||
return Ok(f64::NAN);
|
||||
}
|
||||
}
|
||||
|
||||
n
|
||||
} else {
|
||||
let (sign, digits) = if let Some(stripped) = strim.strip_prefix(b'+') {
|
||||
(1.0, stripped)
|
||||
} else if let Some(stripped) = strim.strip_prefix(b'-') {
|
||||
(-1.0, stripped)
|
||||
} else {
|
||||
(1.0, strim)
|
||||
};
|
||||
|
||||
if digits == b"Infinity" {
|
||||
return Ok(sign * f64::INFINITY);
|
||||
} else if digits.starts_with([b'i', b'I'].as_ref()) {
|
||||
// Avoid Rust f64::parse accepting "inf" and "infinity"
|
||||
return Ok(f64::NAN);
|
||||
}
|
||||
|
||||
//TODO: This is slightly more permissive than ES3 spec, as
|
||||
//Rust documentation claims it will accept "inf" as f64
|
||||
//infinity.
|
||||
sign * digits.parse().unwrap_or(f64::NAN)
|
||||
}
|
||||
let swf_version = activation.context.swf.version();
|
||||
string_to_f64(s, swf_version, true).unwrap_or_else(|| string_to_int(s, 0, true))
|
||||
}
|
||||
Value::Object(_) => self
|
||||
.coerce_to_primitive(Some(Hint::Number), activation)?
|
||||
|
|
Loading…
Reference in New Issue