diff --git a/boa/src/builtins/function/mod.rs b/boa/src/builtins/function/mod.rs index f7e26bdca8b..4b2ebbc5d38 100644 --- a/boa/src/builtins/function/mod.rs +++ b/boa/src/builtins/function/mod.rs @@ -312,6 +312,25 @@ impl BuiltInFunctionObject { fn prototype(_: &Value, _: &[Value], _: &mut Context) -> Result { Ok(Value::undefined()) } + + /// `Function.prototype.call` + /// + /// The call() method invokes self with the first argument as the `this` value. + /// + /// More information: + /// - [MDN documentation][mdn] + /// - [ECMAScript reference][spec] + /// + /// [spec]: https://tc39.es/ecma262/#sec-function.prototype.call + /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/call + fn call(this: &Value, args: &[Value], context: &mut Context) -> Result { + let func = this; + if !func.is_function() { + return context.throw_type_error("TODO: this is not a function"); + } + let this_arg: Value = args.get(0).map_or_else(Value::default, Value::clone); + context.call(func, &this_arg, &args[1..]) + } } impl BuiltIn for BuiltInFunctionObject { @@ -339,6 +358,7 @@ impl BuiltIn for BuiltInFunctionObject { ) .name(Self::NAME) .length(Self::LENGTH) + .method(Self::call, "call", 1) .build(); (Self::NAME, function_object.into(), Self::attribute()) diff --git a/boa/src/builtins/function/tests.rs b/boa/src/builtins/function/tests.rs index 1bcc7f417c3..c28c5cba6ff 100644 --- a/boa/src/builtins/function/tests.rs +++ b/boa/src/builtins/function/tests.rs @@ -114,3 +114,15 @@ fn function_prototype_length() { assert!(value.is_number()); assert_eq!(value.as_number().unwrap(), 0.0); } + +#[test] +fn function_prototype_call() { + let mut engine = Context::new(); + let func = r#" + let e = new Error() + Object.prototype.toString.call(e) + "#; + let value = forward_val(&mut engine, func).unwrap(); + assert!(value.is_string()); + assert_eq!(value.as_string().unwrap(), "[object Error]"); +}