avm1: Initial implementation of parseFloat

This commit is contained in:
Mike Welsh 2020-12-18 01:22:56 -08:00
parent 326a5b6212
commit 80d5d9cd0a
1 changed files with 65 additions and 0 deletions

View File

@ -216,6 +216,64 @@ pub fn get_nan<'gc>(
}
}
pub fn parse_float<'gc>(
activation: &mut Activation<'_, 'gc, '_>,
_this: Object<'gc>,
args: &[Value<'gc>],
) -> Result<Value<'gc>, Error<'gc>> {
let s = if let Some(val) = args.get(0) {
val.coerce_to_string(activation)?
} else {
return Ok(f64::NAN.into());
};
let s = s.trim_start().bytes();
let mut out_str = String::with_capacity(s.len());
// TODO: Implementing this in a very janky way for now,
// feeding the string to Rust's float parser.
// Flash's parser is much more lenient, so we have to massage
// the string into an acceptable format.
let mut allow_dot = true;
let mut allow_exp = true;
let mut allow_sign = true;
for c in s {
match c {
b'0'..=b'9' => {
allow_sign = false;
out_str.push(c.into());
}
b'+' | b'-' if allow_sign => {
// Sign allowed at first char and following e
allow_sign = false;
out_str.push(c.into());
}
b'.' if allow_exp => {
// Flash allows multiple . except after e
allow_sign = false;
if allow_dot {
allow_dot = false;
out_str.push(c.into());
} else {
allow_exp = false;
}
}
b'e' | b'E' if allow_exp => {
allow_sign = true;
allow_exp = false;
allow_dot = false;
out_str.push(c.into());
}
// Invalid char, `parseFloat` ignores all trailing garbage.
_ => break,
};
}
let n = out_str.parse::<f64>().unwrap_or(f64::NAN);
Ok(n.into())
}
pub fn set_interval<'gc>(
activation: &mut Activation<'_, 'gc, '_>,
@ -782,6 +840,13 @@ pub fn create_globals<'gc>(
DontEnum,
Some(function_proto),
);
globals.force_set_function(
"parseFloat",
parse_float,
gc_context,
DontEnum,
Some(function_proto),
);
globals.force_set_function("random", random, gc_context, DontEnum, Some(function_proto));
globals.force_set_function(
"ASSetPropFlags",