Skip to content

Commit

Permalink
Fix Function.prototype.toString() (#3374)
Browse files Browse the repository at this point in the history
* Fix `Function.prototype.toString()`

* Add doc
  • Loading branch information
HalidOdat authored Oct 11, 2023
1 parent f654ad1 commit 72d2546
Show file tree
Hide file tree
Showing 2 changed files with 29 additions and 19 deletions.
41 changes: 22 additions & 19 deletions boa_engine/src/builtins/function/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -843,13 +843,22 @@ impl BuiltInFunctionObject {
func.call(this_arg, args.get(1..).unwrap_or(&[]), context)
}

/// `Function.prototype.toString()`
///
/// More information:
/// - [MDN documentation][mdn]
/// - [ECMAScript reference][spec]
///
/// [spec]: https://tc39.es/ecma262/#sec-function.prototype.tostring
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/toString
#[allow(clippy::wrong_self_convention)]
fn to_string(this: &JsValue, _: &[JsValue], context: &mut Context<'_>) -> JsResult<JsValue> {
// 1. Let func be the this value.
let func = this;

// 2. If func is an Object, func has a [[SourceText]] internal slot, func.[[SourceText]] is a sequence of Unicode code points,and HostHasSourceTextAvailable(func) is true, then
// a. Return CodePointsToString(func.[[SourceText]]).
// TODO:
// 2. If func is an Object, func has a [[SourceText]] internal slot, func.[[SourceText]] is a sequence of Unicode code points,and HostHasSourceTextAvailable(func) is true, then
// a. Return CodePointsToString(func.[[SourceText]]).

// 3. If func is a built-in function object, return an implementation-defined String source code representation of func.
// The representation must have the syntax of a NativeFunction. Additionally, if func has an [[InitialName]] internal slot and
Expand All @@ -859,11 +868,12 @@ impl BuiltInFunctionObject {
// 4. If func is an Object and IsCallable(func) is true, return an implementation-defined String source code representation of func.
// The representation must have the syntax of a NativeFunction.
// 5. Throw a TypeError exception.
let Some(object) = func.as_object() else {
let Some(object) = func.as_callable() else {
return Err(JsNativeError::typ().with_message("not a function").into());
};

if object.borrow().is_native_function() {
let object = object.borrow();
if object.is_native_function() {
let name = {
// Is there a case here where if there is no name field on a value
// name should default to None? Do all functions have names set?
Expand All @@ -880,29 +890,22 @@ impl BuiltInFunctionObject {
return Ok(
js_string!(utf16!("function "), &name, utf16!("() { [native code] }")).into(),
);
} else if object.is_proxy() || object.is_bound_function() {
return Ok(js_string!(utf16!("function () { [native code] }")).into());
}

let object = object.borrow();
let function = object
.as_function()
.ok_or_else(|| JsNativeError::typ().with_message("not a function"))?;

let code = function.codeblock();

let prefix = match function.kind {
FunctionKind::Ordinary { .. } => {
utf16!("function ")
}
FunctionKind::Async { .. } => {
utf16!("async function ")
}
FunctionKind::Generator { .. } => {
utf16!("function* ")
}
FunctionKind::AsyncGenerator { .. } => utf16!("async function* "),
};

Ok(js_string!(prefix, code.name(), utf16!("() { [native code] }")).into())
Ok(js_string!(
utf16!("function "),
code.name(),
utf16!("() { [native code] }")
)
.into())
}

/// `Function.prototype [ @@hasInstance ] ( V )`
Expand Down
7 changes: 7 additions & 0 deletions boa_engine/src/object/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1336,6 +1336,13 @@ impl Object {
}
}

/// Checks if the object is a `BoundFunction` object.
#[inline]
#[must_use]
pub const fn is_bound_function(&self) -> bool {
matches!(self.kind, ObjectKind::BoundFunction(_))
}

/// Gets the bound function data if the object is a `BoundFunction`.
#[inline]
#[must_use]
Expand Down

0 comments on commit 72d2546

Please sign in to comment.