LibJS: Use OrdinaryCreateFromConstructor() in a bunch of constructors

Resolves various FIXMEs :^)
This commit is contained in:
Linus Groh 2021-06-20 01:09:39 +01:00 committed by Andreas Kling
parent e5753443ae
commit 8f6ac0db1c
Notes: sideshowbarker 2024-07-18 11:59:23 +09:00
16 changed files with 173 additions and 102 deletions

View file

@ -4,6 +4,7 @@
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <LibJS/Runtime/AbstractOperations.h>
#include <LibJS/Runtime/AggregateError.h>
#include <LibJS/Runtime/AggregateErrorConstructor.h>
#include <LibJS/Runtime/Array.h>
@ -36,16 +37,19 @@ Value AggregateErrorConstructor::call()
}
// 20.5.7.1.1 AggregateError ( errors, message ), https://tc39.es/ecma262/#sec-aggregate-error
Value AggregateErrorConstructor::construct(Function&)
Value AggregateErrorConstructor::construct(Function& new_target)
{
auto& vm = this->vm();
// FIXME: Use OrdinaryCreateFromConstructor(newTarget, "%AggregateError.prototype%")
auto* aggregate_error = AggregateError::create(global_object());
auto& global_object = this->global_object();
auto* aggregate_error = ordinary_create_from_constructor<AggregateError>(global_object, new_target, &GlobalObject::aggregate_error_prototype);
if (vm.exception())
return {};
u8 attr = Attribute::Writable | Attribute::Configurable;
if (!vm.argument(1).is_undefined()) {
auto message = vm.argument(1).to_string(global_object());
auto message = vm.argument(1).to_string(global_object);
if (vm.exception())
return {};
aggregate_error->define_property(vm.names.message, js_string(vm, message), attr);
@ -55,11 +59,11 @@ Value AggregateErrorConstructor::construct(Function&)
if (vm.exception())
return {};
auto errors_list = iterable_to_list(global_object(), vm.argument(0));
auto errors_list = iterable_to_list(global_object, vm.argument(0));
if (vm.exception())
return {};
aggregate_error->define_property(vm.names.errors, Array::create_from(global_object(), errors_list), attr);
aggregate_error->define_property(vm.names.errors, Array::create_from(global_object, errors_list), attr);
return aggregate_error;
}

View file

@ -4,10 +4,9 @@
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <LibJS/Heap/Heap.h>
#include <LibJS/Runtime/AbstractOperations.h>
#include <LibJS/Runtime/BooleanConstructor.h>
#include <LibJS/Runtime/BooleanObject.h>
#include <LibJS/Runtime/BooleanPrototype.h>
#include <LibJS/Runtime/GlobalObject.h>
namespace JS {
@ -35,13 +34,20 @@ BooleanConstructor::~BooleanConstructor()
// 20.3.1.1 Boolean ( value ), https://tc39.es/ecma262/#sec-boolean-constructor-boolean-value
Value BooleanConstructor::call()
{
return Value(vm().argument(0).to_boolean());
auto& vm = this->vm();
auto b = vm.argument(0).to_boolean();
return Value(b);
}
// 20.3.1.1 Boolean ( value ), https://tc39.es/ecma262/#sec-boolean-constructor-boolean-value
Value BooleanConstructor::construct(Function&)
Value BooleanConstructor::construct(Function& new_target)
{
return BooleanObject::create(global_object(), vm().argument(0).to_boolean());
auto& vm = this->vm();
auto& global_object = this->global_object();
auto b = vm.argument(0).to_boolean();
return ordinary_create_from_constructor<BooleanObject>(global_object, new_target, &GlobalObject::boolean_prototype, b);
}
}

View file

@ -4,6 +4,7 @@
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <LibJS/Runtime/AbstractOperations.h>
#include <LibJS/Runtime/DataView.h>
#include <LibJS/Runtime/DataViewConstructor.h>
#include <LibJS/Runtime/Error.h>
@ -40,28 +41,30 @@ Value DataViewConstructor::call()
}
// 25.3.2.1 DataView ( buffer [ , byteOffset [ , byteLength ] ] ), https://tc39.es/ecma262/#sec-dataview-buffer-byteoffset-bytelength
Value DataViewConstructor::construct(Function&)
Value DataViewConstructor::construct(Function& new_target)
{
auto& vm = this->vm();
auto& global_object = this->global_object();
auto buffer = vm.argument(0);
if (!buffer.is_object() || !is<ArrayBuffer>(buffer.as_object())) {
vm.throw_exception<TypeError>(global_object(), ErrorType::IsNotAn, buffer.to_string_without_side_effects(), vm.names.ArrayBuffer);
vm.throw_exception<TypeError>(global_object, ErrorType::IsNotAn, buffer.to_string_without_side_effects(), vm.names.ArrayBuffer);
return {};
}
auto& array_buffer = static_cast<ArrayBuffer&>(buffer.as_object());
auto offset = vm.argument(1).to_index(global_object());
auto offset = vm.argument(1).to_index(global_object);
if (vm.exception())
return {};
if (array_buffer.is_detached()) {
vm.throw_exception<TypeError>(global_object(), ErrorType::DetachedArrayBuffer);
vm.throw_exception<TypeError>(global_object, ErrorType::DetachedArrayBuffer);
return {};
}
auto buffer_byte_length = array_buffer.byte_length();
if (offset > buffer_byte_length) {
vm.throw_exception<RangeError>(global_object(), ErrorType::DataViewOutOfRangeByteOffset, offset, buffer_byte_length);
vm.throw_exception<RangeError>(global_object, ErrorType::DataViewOutOfRangeByteOffset, offset, buffer_byte_length);
return {};
}
@ -69,22 +72,25 @@ Value DataViewConstructor::construct(Function&)
if (vm.argument(2).is_undefined()) {
view_byte_length = buffer_byte_length - offset;
} else {
view_byte_length = vm.argument(2).to_index(global_object());
view_byte_length = vm.argument(2).to_index(global_object);
if (vm.exception())
return {};
if (offset + view_byte_length > buffer_byte_length) {
vm.throw_exception<RangeError>(global_object(), ErrorType::InvalidLength, vm.names.DataView);
vm.throw_exception<RangeError>(global_object, ErrorType::InvalidLength, vm.names.DataView);
return {};
}
}
// FIXME: Use OrdinaryCreateFromConstructor(newTarget, "%DataView.prototype%")
auto* data_view = ordinary_create_from_constructor<DataView>(global_object, new_target, &GlobalObject::data_view_prototype, &array_buffer, view_byte_length, offset);
if (vm.exception())
return {};
if (array_buffer.is_detached()) {
vm.throw_exception<TypeError>(global_object(), ErrorType::DetachedArrayBuffer);
vm.throw_exception<TypeError>(global_object, ErrorType::DetachedArrayBuffer);
return {};
}
return DataView::create(global_object(), &array_buffer, view_byte_length, offset);
return data_view;
}
}

View file

@ -19,15 +19,6 @@ Date* Date::create(GlobalObject& global_object, Core::DateTime datetime, i16 mil
return global_object.heap().allocate<Date>(global_object, datetime, milliseconds, is_invalid, *global_object.date_prototype());
}
Date* Date::now(GlobalObject& global_object)
{
struct timeval tv;
gettimeofday(&tv, nullptr);
auto datetime = Core::DateTime::now();
auto milliseconds = static_cast<i16>(tv.tv_usec / 1000);
return create(global_object, datetime, milliseconds);
}
Date::Date(Core::DateTime datetime, i16 milliseconds, bool is_invalid, Object& prototype)
: Object(prototype)
, m_datetime(datetime)

View file

@ -9,6 +9,7 @@
#include <AK/CharacterTypes.h>
#include <AK/GenericLexer.h>
#include <LibCore/DateTime.h>
#include <LibJS/Runtime/AbstractOperations.h>
#include <LibJS/Runtime/Date.h>
#include <LibJS/Runtime/DateConstructor.h>
#include <LibJS/Runtime/GlobalObject.h>
@ -144,23 +145,43 @@ DateConstructor::~DateConstructor()
{
}
// 21.4.2.1 Date ( ...values ), https://tc39.es/ecma262/#sec-date
Value DateConstructor::call()
struct DatetimeAndMilliseconds {
Core::DateTime datetime;
i16 milliseconds { 0 };
};
static DatetimeAndMilliseconds now()
{
return js_string(heap(), Date::now(global_object())->string());
struct timeval tv;
gettimeofday(&tv, nullptr);
auto datetime = Core::DateTime::now();
auto milliseconds = static_cast<i16>(tv.tv_usec / 1000);
return { datetime, milliseconds };
}
// 21.4.2.1 Date ( ...values ), https://tc39.es/ecma262/#sec-date
Value DateConstructor::construct(Function&)
Value DateConstructor::call()
{
auto [datetime, milliseconds] = JS::now();
auto* date = Date::create(global_object(), datetime, milliseconds);
return js_string(heap(), date->string());
}
// 21.4.2.1 Date ( ...values ), https://tc39.es/ecma262/#sec-date
Value DateConstructor::construct(Function& new_target)
{
auto& vm = this->vm();
if (vm.argument_count() == 0)
return Date::now(global_object());
auto& global_object = this->global_object();
auto create_invalid_date = [this]() {
if (vm.argument_count() == 0) {
auto [datetime, milliseconds] = JS::now();
return ordinary_create_from_constructor<Date>(global_object, new_target, &GlobalObject::date_prototype, datetime, milliseconds, false);
}
auto create_invalid_date = [&global_object, &new_target]() {
auto datetime = Core::DateTime::create(1970, 1, 1, 0, 0, 0);
auto milliseconds = static_cast<i16>(0);
return Date::create(global_object(), datetime, milliseconds, true);
return ordinary_create_from_constructor<Date>(global_object, new_target, &GlobalObject::date_prototype, datetime, milliseconds, true);
};
if (vm.argument_count() == 1) {
@ -168,7 +189,7 @@ Value DateConstructor::construct(Function&)
if (value.is_string())
value = parse_simplified_iso8601(value.as_string().string());
else
value = value.to_number(global_object());
value = value.to_number(global_object);
if (vm.exception())
return {};
@ -183,13 +204,15 @@ Value DateConstructor::construct(Function&)
return create_invalid_date();
auto datetime = Core::DateTime::from_timestamp(static_cast<time_t>(value_as_double / 1000));
auto milliseconds = static_cast<i16>(fmod(value_as_double, 1000));
return Date::create(global_object(), datetime, milliseconds);
return ordinary_create_from_constructor<Date>(global_object, new_target, &GlobalObject::date_prototype, datetime, milliseconds, false);
}
// A date/time in components, in local time.
auto arg_or = [&vm, this](size_t i, i32 fallback) { return vm.argument_count() > i ? vm.argument(i).to_number(global_object()) : Value(fallback); };
auto arg_or = [&vm, &global_object](size_t i, i32 fallback) {
return vm.argument_count() > i ? vm.argument(i).to_number(global_object) : Value(fallback);
};
auto year_value = vm.argument(0).to_number(global_object());
auto year_value = vm.argument(0).to_number(global_object);
if (vm.exception())
return {};
if (!year_value.is_finite_number()) {
@ -197,7 +220,7 @@ Value DateConstructor::construct(Function&)
}
auto year = year_value.as_i32();
auto month_index_value = vm.argument(1).to_number(global_object());
auto month_index_value = vm.argument(1).to_number(global_object);
if (vm.exception())
return {};
if (!month_index_value.is_finite_number()) {
@ -256,10 +279,10 @@ Value DateConstructor::construct(Function&)
year += 1900;
int month = month_index + 1;
auto datetime = Core::DateTime::create(year, month, day, hours, minutes, seconds);
auto* date = Date::create(global_object(), datetime, milliseconds);
if (date->time() > Date::time_clip)
auto time = datetime.timestamp() * 1000.0 + milliseconds;
if (time > Date::time_clip)
return create_invalid_date();
return date;
return ordinary_create_from_constructor<Date>(global_object, new_target, &GlobalObject::date_prototype, datetime, milliseconds, false);
}
// 21.4.3.1 Date.now ( ), https://tc39.es/ecma262/#sec-date.now

View file

@ -4,6 +4,7 @@
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <LibJS/Runtime/AbstractOperations.h>
#include <LibJS/Runtime/Error.h>
#include <LibJS/Runtime/ErrorConstructor.h>
#include <LibJS/Runtime/GlobalObject.h>
@ -33,16 +34,19 @@ Value ErrorConstructor::call()
}
// 20.5.1.1 Error ( message ), https://tc39.es/ecma262/#sec-error-message
Value ErrorConstructor::construct(Function&)
Value ErrorConstructor::construct(Function& new_target)
{
auto& vm = this->vm();
// FIXME: Use OrdinaryCreateFromConstructor(newTarget, "%Error.prototype%")
auto* error = Error::create(global_object());
auto& global_object = this->global_object();
auto* error = ordinary_create_from_constructor<Error>(global_object, new_target, &GlobalObject::error_prototype);
if (vm.exception())
return {};
u8 attr = Attribute::Writable | Attribute::Configurable;
if (!vm.argument(0).is_undefined()) {
auto message = vm.argument(0).to_string(global_object());
auto message = vm.argument(0).to_string(global_object);
if (vm.exception())
return {};
error->define_property(vm.names.message, js_string(vm, message), attr);
@ -82,17 +86,20 @@ Value ErrorConstructor::construct(Function&)
} \
\
/* 20.5.6.1.1 NativeError ( message ), https://tc39.es/ecma262/#sec-nativeerror */ \
Value ConstructorName::construct(Function&) \
Value ConstructorName::construct(Function& new_target) \
{ \
auto& vm = this->vm(); \
/* FIXME: Use OrdinaryCreateFromConstructor( \
* FIXME: newTarget, "%NativeError.prototype%"). */ \
auto* error = ClassName::create(global_object()); \
auto& global_object = this->global_object(); \
\
auto* error = ordinary_create_from_constructor<ClassName>( \
global_object, new_target, &GlobalObject::snake_name##_prototype); \
if (vm.exception()) \
return {}; \
\
u8 attr = Attribute::Writable | Attribute::Configurable; \
\
if (!vm.argument(0).is_undefined()) { \
auto message = vm.argument(0).to_string(global_object()); \
auto message = vm.argument(0).to_string(global_object); \
if (vm.exception()) \
return {}; \
error->define_property(vm.names.message, js_string(vm, message), attr); \

View file

@ -4,6 +4,7 @@
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <LibJS/Runtime/AbstractOperations.h>
#include <LibJS/Runtime/Error.h>
#include <LibJS/Runtime/FinalizationRegistry.h>
#include <LibJS/Runtime/FinalizationRegistryConstructor.h>
@ -40,17 +41,17 @@ Value FinalizationRegistryConstructor::call()
}
// 26.2.1.1 FinalizationRegistry ( cleanupCallback ), https://tc39.es/ecma262/#sec-finalization-registry-cleanup-callback
Value FinalizationRegistryConstructor::construct(Function&)
Value FinalizationRegistryConstructor::construct(Function& new_target)
{
auto& vm = this->vm();
auto& global_object = this->global_object();
auto cleanup_callback = vm.argument(0);
if (!cleanup_callback.is_function()) {
vm.throw_exception<TypeError>(global_object(), ErrorType::NotAFunction, cleanup_callback.to_string_without_side_effects());
vm.throw_exception<TypeError>(global_object, ErrorType::NotAFunction, cleanup_callback.to_string_without_side_effects());
return {};
}
// FIXME: Use OrdinaryCreateFromConstructor(NewTarget, "%FinalizationRegistry.prototype%")
return FinalizationRegistry::create(global_object(), cleanup_callback.as_function());
return ordinary_create_from_constructor<FinalizationRegistry>(global_object, new_target, &GlobalObject::finalization_registry_prototype, cleanup_callback.as_function());
}
}

View file

@ -4,6 +4,7 @@
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <LibJS/Runtime/AbstractOperations.h>
#include <LibJS/Runtime/Error.h>
#include <LibJS/Runtime/GlobalObject.h>
#include <LibJS/Runtime/IteratorOperations.h>
@ -43,12 +44,15 @@ Value MapConstructor::call()
}
// 24.1.1.1 Map ( [ iterable ] ), https://tc39.es/ecma262/#sec-map-iterable
Value MapConstructor::construct(Function&)
Value MapConstructor::construct(Function& new_target)
{
auto& vm = this->vm();
auto& global_object = this->global_object();
auto* map = ordinary_create_from_constructor<Map>(global_object, new_target, &GlobalObject::map_prototype);
if (vm.exception())
return {};
// FIXME: Use OrdinaryCreateFromConstructor(newTarget, "%Map.prototype%")
auto* map = Map::create(global_object());
if (vm.argument(0).is_nullish())
return map;
@ -56,14 +60,14 @@ Value MapConstructor::construct(Function&)
if (vm.exception())
return {};
if (!adder.is_function()) {
vm.throw_exception<TypeError>(global_object(), ErrorType::NotAFunction, "'set' property of Map");
vm.throw_exception<TypeError>(global_object, ErrorType::NotAFunction, "'set' property of Map");
return {};
}
get_iterator_values(global_object(), vm.argument(0), [&](Value iterator_value) {
get_iterator_values(global_object, vm.argument(0), [&](Value iterator_value) {
if (vm.exception())
return IterationDecision::Break;
if (!iterator_value.is_object()) {
vm.throw_exception<TypeError>(global_object(), ErrorType::NotAnObject, String::formatted("Iterator value {}", iterator_value.to_string_without_side_effects()));
vm.throw_exception<TypeError>(global_object, ErrorType::NotAnObject, String::formatted("Iterator value {}", iterator_value.to_string_without_side_effects()));
return IterationDecision::Break;
}
auto key = iterator_value.as_object().get(0).value_or(js_undefined());

View file

@ -4,6 +4,7 @@
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <LibJS/Runtime/AbstractOperations.h>
#include <LibJS/Runtime/Error.h>
#include <LibJS/Runtime/GlobalObject.h>
#include <LibJS/Runtime/NumberConstructor.h>
@ -94,7 +95,7 @@ Value NumberConstructor::call()
}
// 21.1.1.1 Number ( value ), https://tc39.es/ecma262/#sec-number-constructor-number-value
Value NumberConstructor::construct(Function&)
Value NumberConstructor::construct(Function& new_target)
{
auto& vm = this->vm();
auto& global_object = this->global_object();
@ -102,8 +103,7 @@ Value NumberConstructor::construct(Function&)
auto number = get_value_from_constructor_argument(global_object);
if (vm.exception())
return {};
// FIXME: Use OrdinaryCreateFromConstructor(NewTarget, "%Number.prototype%")
return NumberObject::create(global_object, number.as_double());
return ordinary_create_from_constructor<NumberObject>(global_object, new_target, &GlobalObject::number_prototype, number.as_double());
}
// 21.1.2.2 Number.isFinite ( number ), https://tc39.es/ecma262/#sec-number.isfinite

View file

@ -62,22 +62,24 @@ ObjectConstructor::~ObjectConstructor()
// 20.1.1.1 Object ( [ value ] ), https://tc39.es/ecma262/#sec-object-value
Value ObjectConstructor::call()
{
return construct(*this);
}
// 20.1.1.1 Object ( [ value ] ), https://tc39.es/ecma262/#sec-object-value
Value ObjectConstructor::construct(Function& new_target)
{
auto& vm = this->vm();
auto& global_object = this->global_object();
if (&new_target != this)
return ordinary_create_from_constructor<Object>(global_object, new_target, &GlobalObject::object_prototype);
auto value = vm.argument(0);
if (value.is_nullish())
return Object::create(global_object, global_object.object_prototype());
return value.to_object(global_object);
}
// 20.1.1.1 Object ( [ value ] ), https://tc39.es/ecma262/#sec-object-value
Value ObjectConstructor::construct(Function&)
{
return call();
}
// 20.1.2.10 Object.getOwnPropertyNames ( O ), https://tc39.es/ecma262/#sec-object.getownpropertynames
JS_DEFINE_NATIVE_FUNCTION(ObjectConstructor::get_own_property_names)
{

View file

@ -5,6 +5,7 @@
*/
#include <LibJS/Interpreter.h>
#include <LibJS/Runtime/AbstractOperations.h>
#include <LibJS/Runtime/Error.h>
#include <LibJS/Runtime/Function.h>
#include <LibJS/Runtime/GlobalObject.h>
@ -50,15 +51,21 @@ Value PromiseConstructor::call()
}
// 27.2.3.1 Promise ( executor ), https://tc39.es/ecma262/#sec-promise-executor
Value PromiseConstructor::construct(Function&)
Value PromiseConstructor::construct(Function& new_target)
{
auto& vm = this->vm();
auto& global_object = this->global_object();
auto executor = vm.argument(0);
if (!executor.is_function()) {
vm.throw_exception<TypeError>(global_object(), ErrorType::PromiseExecutorNotAFunction);
vm.throw_exception<TypeError>(global_object, ErrorType::PromiseExecutorNotAFunction);
return {};
}
auto* promise = Promise::create(global_object());
auto* promise = ordinary_create_from_constructor<Promise>(global_object, new_target, &GlobalObject::promise_prototype);
if (vm.exception())
return {};
auto [resolve_function, reject_function] = promise->create_resolving_functions();
auto completion_value = vm.call(executor.as_function(), js_undefined(), &resolve_function, &reject_function);

View file

@ -55,6 +55,7 @@ Value RegExpConstructor::construct(Function&)
if (vm.exception())
return {};
}
// FIXME: Use RegExpAlloc (which uses OrdinaryCreateFromConstructor)
return RegExpObject::create(global_object(), pattern, flags);
}

View file

@ -4,6 +4,7 @@
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <LibJS/Runtime/AbstractOperations.h>
#include <LibJS/Runtime/Error.h>
#include <LibJS/Runtime/GlobalObject.h>
#include <LibJS/Runtime/IteratorOperations.h>
@ -43,21 +44,26 @@ Value SetConstructor::call()
}
// 24.2.1.1 Set ( [ iterable ] ), https://tc39.es/ecma262/#sec-set-iterable
Value SetConstructor::construct(Function&)
Value SetConstructor::construct(Function& new_target)
{
auto& vm = this->vm();
if (vm.argument(0).is_nullish())
return Set::create(global_object());
auto& global_object = this->global_object();
auto* set = ordinary_create_from_constructor<Set>(global_object, new_target, &GlobalObject::set_prototype);
if (vm.exception())
return {};
if (vm.argument(0).is_nullish())
return set;
auto* set = Set::create(global_object());
auto adder = set->get(vm.names.add);
if (vm.exception())
return {};
if (!adder.is_function()) {
vm.throw_exception<TypeError>(global_object(), ErrorType::NotAFunction, "'add' property of Set");
vm.throw_exception<TypeError>(global_object, ErrorType::NotAFunction, "'add' property of Set");
return {};
}
get_iterator_values(global_object(), vm.argument(0), [&](Value iterator_value) {
get_iterator_values(global_object, vm.argument(0), [&](Value iterator_value) {
if (vm.exception())
return IterationDecision::Break;
(void)vm.call(adder.as_function(), Value(set), iterator_value);

View file

@ -4,6 +4,7 @@
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <LibJS/Runtime/AbstractOperations.h>
#include <LibJS/Runtime/Error.h>
#include <LibJS/Runtime/GlobalObject.h>
#include <LibJS/Runtime/IteratorOperations.h>
@ -41,25 +42,30 @@ Value WeakMapConstructor::call()
}
// 24.3.1.1 WeakMap ( [ iterable ] ), https://tc39.es/ecma262/#sec-weakmap-iterable
Value WeakMapConstructor::construct(Function&)
Value WeakMapConstructor::construct(Function& new_target)
{
auto& vm = this->vm();
if (vm.argument(0).is_nullish())
return WeakMap::create(global_object());
auto& global_object = this->global_object();
auto* weak_map = ordinary_create_from_constructor<WeakMap>(global_object, new_target, &GlobalObject::weak_map_prototype);
if (vm.exception())
return {};
if (vm.argument(0).is_nullish())
return weak_map;
auto* weak_map = WeakMap::create(global_object());
auto adder = weak_map->get(vm.names.set);
if (vm.exception())
return {};
if (!adder.is_function()) {
vm.throw_exception<TypeError>(global_object(), ErrorType::NotAFunction, "'set' property of WeakMap");
vm.throw_exception<TypeError>(global_object, ErrorType::NotAFunction, "'set' property of WeakMap");
return {};
}
get_iterator_values(global_object(), vm.argument(0), [&](Value iterator_value) {
get_iterator_values(global_object, vm.argument(0), [&](Value iterator_value) {
if (vm.exception())
return IterationDecision::Break;
if (!iterator_value.is_object()) {
vm.throw_exception<TypeError>(global_object(), ErrorType::NotAnObject, String::formatted("Iterator value {}", iterator_value.to_string_without_side_effects()));
vm.throw_exception<TypeError>(global_object, ErrorType::NotAnObject, String::formatted("Iterator value {}", iterator_value.to_string_without_side_effects()));
return IterationDecision::Break;
}
auto key = iterator_value.as_object().get(0).value_or(js_undefined());

View file

@ -4,6 +4,7 @@
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <LibJS/Runtime/AbstractOperations.h>
#include <LibJS/Runtime/Error.h>
#include <LibJS/Runtime/GlobalObject.h>
#include <LibJS/Runtime/WeakRef.h>
@ -40,17 +41,17 @@ Value WeakRefConstructor::call()
}
// 26.1.1.1 WeakRef ( target ), https://tc39.es/ecma262/#sec-weak-ref-target
Value WeakRefConstructor::construct(Function&)
Value WeakRefConstructor::construct(Function& new_target)
{
auto& vm = this->vm();
auto& global_object = this->global_object();
auto target = vm.argument(0);
if (!target.is_object()) {
vm.throw_exception<TypeError>(global_object(), ErrorType::NotAnObject, target.to_string_without_side_effects());
vm.throw_exception<TypeError>(global_object, ErrorType::NotAnObject, target.to_string_without_side_effects());
return {};
}
// FIXME: Use OrdinaryCreateFromConstructor(newTarget, "%WeakRef.prototype%")
return WeakRef::create(global_object(), &target.as_object());
return ordinary_create_from_constructor<WeakRef>(global_object, new_target, &GlobalObject::weak_ref_prototype, &target.as_object());
}
}

View file

@ -4,6 +4,7 @@
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <LibJS/Runtime/AbstractOperations.h>
#include <LibJS/Runtime/Error.h>
#include <LibJS/Runtime/GlobalObject.h>
#include <LibJS/Runtime/IteratorOperations.h>
@ -41,21 +42,26 @@ Value WeakSetConstructor::call()
}
// 24.4.1.1 WeakSet ( [ iterable ] ), https://tc39.es/ecma262/#sec-weakset-iterable
Value WeakSetConstructor::construct(Function&)
Value WeakSetConstructor::construct(Function& new_target)
{
auto& vm = this->vm();
if (vm.argument(0).is_nullish())
return WeakSet::create(global_object());
auto& global_object = this->global_object();
auto* weak_set = ordinary_create_from_constructor<WeakSet>(global_object, new_target, &GlobalObject::weak_set_prototype);
if (vm.exception())
return {};
if (vm.argument(0).is_nullish())
return weak_set;
auto* weak_set = WeakSet::create(global_object());
auto adder = weak_set->get(vm.names.add);
if (vm.exception())
return {};
if (!adder.is_function()) {
vm.throw_exception<TypeError>(global_object(), ErrorType::NotAFunction, "'add' property of WeakSet");
vm.throw_exception<TypeError>(global_object, ErrorType::NotAFunction, "'add' property of WeakSet");
return {};
}
get_iterator_values(global_object(), vm.argument(0), [&](Value iterator_value) {
get_iterator_values(global_object, vm.argument(0), [&](Value iterator_value) {
if (vm.exception())
return IterationDecision::Break;
(void)vm.call(adder.as_function(), Value(weak_set), iterator_value);