ladybird/Libraries/LibJS/Runtime/FunctionObject.cpp
Andreas Kling b81269e78b Libraries: Clean up UTF-16 source text paths
Store parser errors, source range filenames, source code filenames,
module source, and Rust parser errors as UTF-16 where they flow back
into JavaScript-visible strings. Keep byte-oriented source buffers
byte-backed.

Remove temporary PrimitiveString, ByteString, and UTF-8 detours from
JSON, RegExp, module debug logging, print formatting, and tests.
2026-06-22 19:51:25 +02:00

117 lines
4.5 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* Copyright (c) 2020, Andreas Kling <andreas@ladybird.org>
* Copyright (c) 2021-2022, Linus Groh <linusg@serenityos.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <AK/TypeCasts.h>
#include <LibJS/Runtime/Completion.h>
#include <LibJS/Runtime/FunctionObject.h>
#include <LibJS/Runtime/NativeFunction.h>
#include <LibJS/Runtime/VM.h>
namespace JS {
FunctionObject::FunctionObject(Realm& realm, Object* prototype, MayInterfereWithIndexedPropertyAccess may_interfere_with_indexed_property_access)
: Object(realm, prototype, may_interfere_with_indexed_property_access)
{
set_is_function();
}
FunctionObject::FunctionObject(Object& prototype, MayInterfereWithIndexedPropertyAccess may_interfere_with_indexed_property_access)
: Object(ConstructWithPrototypeTag::Tag, prototype, may_interfere_with_indexed_property_access)
{
set_is_function();
}
// 10.2.9 SetFunctionName ( F, name [ , prefix ] ), https://tc39.es/ecma262/#sec-setfunctionname
GC::Ref<PrimitiveString> FunctionObject::make_function_name(Variant<PropertyKey, PrivateName> const& name_arg, Optional<StringView> const& prefix)
{
auto& vm = this->vm();
Utf16String name;
// 2. If Type(name) is Symbol, then
if (auto const* property_key = name_arg.get_pointer<PropertyKey>(); property_key && property_key->is_symbol()) {
// a. Let description be name's [[Description]] value.
auto const& description = property_key->as_symbol()->description();
// b. If description is undefined, set name to the empty String.
if (!description.has_value())
name = {};
// c. Else, set name to the string-concatenation of "[", description, and "]".
else
name = Utf16String::formatted("[{}]", *description);
}
// 3. Else if name is a Private Name, then
else if (auto const* private_name = name_arg.get_pointer<PrivateName>()) {
// a. Set name to name.[[Description]].
name = private_name->description.to_utf16_string();
}
// NOTE: This is necessary as we use a different parameter name.
else {
name = name_arg.get<PropertyKey>().to_utf16_string();
}
// 4. If F has an [[InitialName]] internal slot, then
auto* native_function = as_if<NativeFunction>(this);
if (native_function) {
// a. Set F.[[InitialName]] to name.
native_function->set_initial_name({}, name);
}
// 5. If prefix is present, then
if (prefix.has_value()) {
// a. Set name to the string-concatenation of prefix, the code unit 0x0020 (SPACE), and name.
name = Utf16String::formatted("{} {}", *prefix, name);
// b. If F has an [[InitialName]] internal slot, then
if (native_function) {
// i. Optionally, set F.[[InitialName]] to name.
native_function->set_initial_name({}, name);
}
}
return PrimitiveString::create(vm, move(name));
}
// 10.2.9 SetFunctionName ( F, name [ , prefix ] ), https://tc39.es/ecma262/#sec-setfunctionname
void FunctionObject::set_function_name(Variant<PropertyKey, PrivateName> const& name_arg, Optional<StringView> const& prefix)
{
auto& vm = this->vm();
// 1. Assert: F is an extensible object that does not have a "name" own property.
VERIFY(extensible());
VERIFY(!storage_has(vm.names.name));
auto name = make_function_name(name_arg, prefix);
// 6. Perform ! DefinePropertyOrThrow(F, "name", PropertyDescriptor { [[Value]]: name, [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: true }).
PropertyDescriptor descriptor { .value = name, .writable = false, .enumerable = false, .configurable = true };
MUST(define_property_or_throw(vm.names.name, descriptor));
// 7. Return unused.
}
// 10.2.10 SetFunctionLength ( F, length ), https://tc39.es/ecma262/#sec-setfunctionlength
void FunctionObject::set_function_length(double length)
{
auto& vm = this->vm();
// "length (a non-negative integer or +∞)"
VERIFY(trunc(length) == length || __builtin_isinf_sign(length) == 1);
// 1. Assert: F is an extensible object that does not have a "length" own property.
VERIFY(extensible());
VERIFY(!storage_has(vm.names.length));
// 2. Perform ! DefinePropertyOrThrow(F, "length", PropertyDescriptor { [[Value]]: 𝔽(length), [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: true }).
PropertyDescriptor descriptor { .value = Value { length }, .writable = false, .enumerable = false, .configurable = true };
MUST(define_property_or_throw(vm.names.length, descriptor));
// 3. Return unused.
}
}