avm2: Implement `rest` parameters in function calls.
This commit is contained in:
parent
453e013c2c
commit
09f9e99fbb
|
@ -184,11 +184,8 @@ impl<'a, 'gc, 'gc_context> Activation<'a, 'gc, 'gc_context> {
|
|||
.body()
|
||||
.ok_or_else(|| "Cannot execute non-native method without body".into());
|
||||
let num_locals = body?.num_locals;
|
||||
let arg_register = if method.method().needs_arguments_object {
|
||||
1
|
||||
} else {
|
||||
0
|
||||
};
|
||||
let has_rest_or_args = method.method().needs_arguments_object || method.method().needs_rest;
|
||||
let arg_register = if has_rest_or_args { 1 } else { 0 };
|
||||
let num_declared_arguments = method.method().params.len() as u32;
|
||||
let local_registers = GcCell::allocate(
|
||||
context.gc_context,
|
||||
|
@ -219,8 +216,19 @@ impl<'a, 'gc, 'gc_context> Activation<'a, 'gc, 'gc_context> {
|
|||
context,
|
||||
};
|
||||
|
||||
if method.method().needs_arguments_object {
|
||||
let args_array = ArrayStorage::from_args(arguments);
|
||||
if has_rest_or_args {
|
||||
let args_array = if method.method().needs_arguments_object {
|
||||
ArrayStorage::from_args(arguments)
|
||||
} else if method.method().needs_rest {
|
||||
if let Some(rest_args) = arguments.get(num_declared_arguments as usize..) {
|
||||
ArrayStorage::from_args(rest_args)
|
||||
} else {
|
||||
ArrayStorage::new(0)
|
||||
}
|
||||
} else {
|
||||
unreachable!();
|
||||
};
|
||||
|
||||
let mut args_object = ArrayObject::from_array(
|
||||
args_array,
|
||||
activation
|
||||
|
@ -233,12 +241,14 @@ impl<'a, 'gc, 'gc_context> Activation<'a, 'gc, 'gc_context> {
|
|||
activation.context.gc_context,
|
||||
);
|
||||
|
||||
args_object.set_property(
|
||||
args_object,
|
||||
&QName::new(Namespace::public_namespace(), "callee"),
|
||||
callee.into(),
|
||||
&mut activation,
|
||||
)?;
|
||||
if method.method().needs_arguments_object {
|
||||
args_object.set_property(
|
||||
args_object,
|
||||
&QName::new(Namespace::public_namespace(), "callee"),
|
||||
callee.into(),
|
||||
&mut activation,
|
||||
)?;
|
||||
}
|
||||
|
||||
*local_registers
|
||||
.write(activation.context.gc_context)
|
||||
|
|
|
@ -455,6 +455,7 @@ swf_tests! {
|
|||
(as3_event_isdefaultprevented, "avm2/event_isdefaultprevented", 1),
|
||||
(as3_function_call_via_apply, "avm2/function_call_via_apply", 1),
|
||||
(as3_function_call_arguments, "avm2/function_call_arguments", 1),
|
||||
(as3_function_call_rest, "avm2/function_call_rest", 1),
|
||||
}
|
||||
|
||||
// TODO: These tests have some inaccuracies currently, so we use approx_eq to test that numeric values are close enough.
|
||||
|
|
|
@ -0,0 +1,34 @@
|
|||
package {
|
||||
public class Test {}
|
||||
}
|
||||
|
||||
function testrest(arg0, arg1, ...rest) {
|
||||
trace(arg0);
|
||||
trace(arg1);
|
||||
|
||||
trace("///(contents of rest...)");
|
||||
trace(rest.length);
|
||||
|
||||
for (var i = 0; i < rest.length; i += 1) {
|
||||
trace(rest[i]);
|
||||
}
|
||||
}
|
||||
|
||||
function restprops(...rest) {
|
||||
trace("///Array.prototype.test = \"test\";");
|
||||
Array.prototype.test = "test";
|
||||
|
||||
trace("///rest.test");
|
||||
trace(rest.test);
|
||||
}
|
||||
|
||||
trace("///testrest(\"arg1\");");
|
||||
testrest("arg1");
|
||||
|
||||
trace("///testrest(\"arg1\", \"arg2\", \"arg3\");");
|
||||
testrest("arg1", "arg2", "arg3");
|
||||
|
||||
trace("///testrest(\"arg1\", \"arg2\", \"arg3\", \"arg4\", \"arg5\");");
|
||||
testrest("arg1", "arg2", "arg3", "arg4", "arg5");
|
||||
|
||||
restprops();
|
|
@ -0,0 +1,22 @@
|
|||
///testrest("arg1");
|
||||
arg1
|
||||
undefined
|
||||
///(contents of rest...)
|
||||
0
|
||||
///testrest("arg1", "arg2", "arg3");
|
||||
arg1
|
||||
arg2
|
||||
///(contents of rest...)
|
||||
1
|
||||
arg3
|
||||
///testrest("arg1", "arg2", "arg3", "arg4", "arg5");
|
||||
arg1
|
||||
arg2
|
||||
///(contents of rest...)
|
||||
3
|
||||
arg3
|
||||
arg4
|
||||
arg5
|
||||
///Array.prototype.test = "test";
|
||||
///rest.test
|
||||
test
|
Binary file not shown.
Binary file not shown.
Loading…
Reference in New Issue