avm2: Implement `Array.slice`.

This commit is contained in:
David Wendt 2020-08-31 23:15:03 -04:00 committed by Mike Welsh
parent 685fbc12e0
commit 53b564bb52
6 changed files with 171 additions and 0 deletions

View File

@ -612,6 +612,59 @@ pub fn unshift<'gc>(
Ok(Value::Undefined) Ok(Value::Undefined)
} }
/// Implements `Array.slice`
pub fn slice<'gc>(
activation: &mut Activation<'_, 'gc, '_>,
this: Option<Object<'gc>>,
args: &[Value<'gc>],
) -> Result<Value<'gc>, Error> {
if let Some(this) = this {
let array_length = this.as_array_storage().map(|a| a.length());
if let Some(array_length) = array_length {
let start = args
.get(0)
.cloned()
.unwrap_or_else(|| 0.into())
.coerce_to_i32(activation)?;
let end = args
.get(1)
.cloned()
.unwrap_or_else(|| 0xFFFFFF.into())
.coerce_to_i32(activation)?;
let actual_start = if start < 0 {
(array_length as isize).saturating_add(start as isize) as usize
} else {
start as usize
};
let actual_end = if end < 0 {
(array_length as isize).saturating_add(end as isize) as usize
} else {
end as usize
};
let mut new_array = ArrayStorage::new(0);
for i in actual_start..actual_end {
if i >= array_length {
break;
}
new_array.push(resolve_array_hole(
activation,
this,
i,
this.as_array_storage().unwrap().get(i),
)?);
}
return build_array(activation, new_array);
}
}
Ok(Value::Undefined)
}
/// Construct `Array`'s class. /// Construct `Array`'s class.
pub fn create_class<'gc>(mc: MutationContext<'gc, '_>) -> GcCell<'gc, Class<'gc>> { pub fn create_class<'gc>(mc: MutationContext<'gc, '_>) -> GcCell<'gc, Class<'gc>> {
let class = Class::new( let class = Class::new(
@ -707,5 +760,10 @@ pub fn create_class<'gc>(mc: MutationContext<'gc, '_>) -> GcCell<'gc, Class<'gc>
Method::from_builtin(unshift), Method::from_builtin(unshift),
)); ));
class.write(mc).define_instance_trait(Trait::from_method(
QName::new(Namespace::public_namespace(), "slice"),
Method::from_builtin(slice),
));
class class
} }

View File

@ -376,6 +376,7 @@ swf_tests! {
(as3_array_reverse, "avm2/array_reverse", 1), (as3_array_reverse, "avm2/array_reverse", 1),
(as3_array_shift, "avm2/array_shift", 1), (as3_array_shift, "avm2/array_shift", 1),
(as3_array_unshift, "avm2/array_unshift", 1), (as3_array_unshift, "avm2/array_unshift", 1),
(as3_array_slice, "avm2/array_slice", 1),
} }
// TODO: These tests have some inaccuracies currently, so we use approx_eq to test that numeric values are close enough. // TODO: These tests have some inaccuracies currently, so we use approx_eq to test that numeric values are close enough.

View File

@ -0,0 +1,73 @@
package {
public class Test {
}
}
function assert_array(a) {
for (var i = 0; i < a.length; i += 1) {
trace(a[i]);
}
}
trace("//var a = new Array(8)");
var a = new Array(8);
trace("//Array.prototype[0] = 999");
Array.prototype[0] = 999;
trace("//Array.prototype[1] = 998");
Array.prototype[1] = 998;
trace("//a[2] = 2");
a[2] = 2;
trace("//Array.prototype[3] = 997");
Array.prototype[3] = 997;
trace("//a[4] = 4");
a[4] = 4;
trace("//Array.prototype[5] = 996");
Array.prototype[5] = 996;
trace("//a[6] = 6");
a[6] = 6;
trace("//Array.prototype[7] = 995");
Array.prototype[7] = 995;
trace("//var b = a.slice();");
var b = a.slice();
trace("//(contents of b)");
assert_array(b);
trace("//var c = a.slice(0, 3);");
var c = a.slice(0, 3);
trace("//(contents of c)");
assert_array(c);
trace("//var d = a.slice(-1, 3);");
var d = a.slice(-1, 3);
trace("//(contents of d)");
assert_array(d);
trace("//var e = a.slice(0, 3);");
var e = a.slice(0, -3);
trace("//(contents of e)");
assert_array(e);
trace("//var f = a.slice(-1, -3);");
var f = a.slice(-1, -3);
trace("//(contents of f)");
assert_array(f);
trace("//var g = a.slice(-3, -1);");
var g = a.slice(-3, -1);
trace("//(contents of g)");
assert_array(g);

View File

@ -0,0 +1,39 @@
//var a = new Array(8)
//Array.prototype[0] = 999
//Array.prototype[1] = 998
//a[2] = 2
//Array.prototype[3] = 997
//a[4] = 4
//Array.prototype[5] = 996
//a[6] = 6
//Array.prototype[7] = 995
//var b = a.slice();
//(contents of b)
999
998
2
997
4
996
6
995
//var c = a.slice(0, 3);
//(contents of c)
999
998
2
//var d = a.slice(-1, 3);
//(contents of d)
//var e = a.slice(0, 3);
//(contents of e)
999
998
2
997
4
//var f = a.slice(-1, -3);
//(contents of f)
//var g = a.slice(-3, -1);
//(contents of g)
996
6

Binary file not shown.

Binary file not shown.