1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-25 15:07:45 +00:00

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
16 changed files with 173 additions and 102 deletions

View file

@ -4,6 +4,7 @@
* SPDX-License-Identifier: BSD-2-Clause * SPDX-License-Identifier: BSD-2-Clause
*/ */
#include <LibJS/Runtime/AbstractOperations.h>
#include <LibJS/Runtime/AggregateError.h> #include <LibJS/Runtime/AggregateError.h>
#include <LibJS/Runtime/AggregateErrorConstructor.h> #include <LibJS/Runtime/AggregateErrorConstructor.h>
#include <LibJS/Runtime/Array.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 // 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(); auto& vm = this->vm();
// FIXME: Use OrdinaryCreateFromConstructor(newTarget, "%AggregateError.prototype%") auto& global_object = this->global_object();
auto* aggregate_error = AggregateError::create(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; u8 attr = Attribute::Writable | Attribute::Configurable;
if (!vm.argument(1).is_undefined()) { 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()) if (vm.exception())
return {}; return {};
aggregate_error->define_property(vm.names.message, js_string(vm, message), attr); aggregate_error->define_property(vm.names.message, js_string(vm, message), attr);
@ -55,11 +59,11 @@ Value AggregateErrorConstructor::construct(Function&)
if (vm.exception()) if (vm.exception())
return {}; 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()) if (vm.exception())
return {}; 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; return aggregate_error;
} }

View file

@ -4,10 +4,9 @@
* SPDX-License-Identifier: BSD-2-Clause * SPDX-License-Identifier: BSD-2-Clause
*/ */
#include <LibJS/Heap/Heap.h> #include <LibJS/Runtime/AbstractOperations.h>
#include <LibJS/Runtime/BooleanConstructor.h> #include <LibJS/Runtime/BooleanConstructor.h>
#include <LibJS/Runtime/BooleanObject.h> #include <LibJS/Runtime/BooleanObject.h>
#include <LibJS/Runtime/BooleanPrototype.h>
#include <LibJS/Runtime/GlobalObject.h> #include <LibJS/Runtime/GlobalObject.h>
namespace JS { namespace JS {
@ -35,13 +34,20 @@ BooleanConstructor::~BooleanConstructor()
// 20.3.1.1 Boolean ( value ), https://tc39.es/ecma262/#sec-boolean-constructor-boolean-value // 20.3.1.1 Boolean ( value ), https://tc39.es/ecma262/#sec-boolean-constructor-boolean-value
Value BooleanConstructor::call() 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 // 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 * SPDX-License-Identifier: BSD-2-Clause
*/ */
#include <LibJS/Runtime/AbstractOperations.h>
#include <LibJS/Runtime/DataView.h> #include <LibJS/Runtime/DataView.h>
#include <LibJS/Runtime/DataViewConstructor.h> #include <LibJS/Runtime/DataViewConstructor.h>
#include <LibJS/Runtime/Error.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 // 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& vm = this->vm();
auto& global_object = this->global_object();
auto buffer = vm.argument(0); auto buffer = vm.argument(0);
if (!buffer.is_object() || !is<ArrayBuffer>(buffer.as_object())) { 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 {}; return {};
} }
auto& array_buffer = static_cast<ArrayBuffer&>(buffer.as_object()); 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()) if (vm.exception())
return {}; return {};
if (array_buffer.is_detached()) { if (array_buffer.is_detached()) {
vm.throw_exception<TypeError>(global_object(), ErrorType::DetachedArrayBuffer); vm.throw_exception<TypeError>(global_object, ErrorType::DetachedArrayBuffer);
return {}; return {};
} }
auto buffer_byte_length = array_buffer.byte_length(); auto buffer_byte_length = array_buffer.byte_length();
if (offset > 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 {}; return {};
} }
@ -69,22 +72,25 @@ Value DataViewConstructor::construct(Function&)
if (vm.argument(2).is_undefined()) { if (vm.argument(2).is_undefined()) {
view_byte_length = buffer_byte_length - offset; view_byte_length = buffer_byte_length - offset;
} else { } else {
view_byte_length = vm.argument(2).to_index(global_object()); view_byte_length = vm.argument(2).to_index(global_object);
if (vm.exception()) if (vm.exception())
return {}; return {};
if (offset + view_byte_length > buffer_byte_length) { 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 {}; 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()) { if (array_buffer.is_detached()) {
vm.throw_exception<TypeError>(global_object(), ErrorType::DetachedArrayBuffer); vm.throw_exception<TypeError>(global_object, ErrorType::DetachedArrayBuffer);
return {}; 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()); 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) Date::Date(Core::DateTime datetime, i16 milliseconds, bool is_invalid, Object& prototype)
: Object(prototype) : Object(prototype)
, m_datetime(datetime) , m_datetime(datetime)

View file

@ -9,6 +9,7 @@
#include <AK/CharacterTypes.h> #include <AK/CharacterTypes.h>
#include <AK/GenericLexer.h> #include <AK/GenericLexer.h>
#include <LibCore/DateTime.h> #include <LibCore/DateTime.h>
#include <LibJS/Runtime/AbstractOperations.h>
#include <LibJS/Runtime/Date.h> #include <LibJS/Runtime/Date.h>
#include <LibJS/Runtime/DateConstructor.h> #include <LibJS/Runtime/DateConstructor.h>
#include <LibJS/Runtime/GlobalObject.h> #include <LibJS/Runtime/GlobalObject.h>
@ -144,23 +145,43 @@ DateConstructor::~DateConstructor()
{ {
} }
// 21.4.2.1 Date ( ...values ), https://tc39.es/ecma262/#sec-date struct DatetimeAndMilliseconds {
Value DateConstructor::call() 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 // 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(); auto& vm = this->vm();
if (vm.argument_count() == 0) auto& global_object = this->global_object();
return Date::now(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 datetime = Core::DateTime::create(1970, 1, 1, 0, 0, 0);
auto milliseconds = static_cast<i16>(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) { if (vm.argument_count() == 1) {
@ -168,7 +189,7 @@ Value DateConstructor::construct(Function&)
if (value.is_string()) if (value.is_string())
value = parse_simplified_iso8601(value.as_string().string()); value = parse_simplified_iso8601(value.as_string().string());
else else
value = value.to_number(global_object()); value = value.to_number(global_object);
if (vm.exception()) if (vm.exception())
return {}; return {};
@ -183,13 +204,15 @@ Value DateConstructor::construct(Function&)
return create_invalid_date(); return create_invalid_date();
auto datetime = Core::DateTime::from_timestamp(static_cast<time_t>(value_as_double / 1000)); auto datetime = Core::DateTime::from_timestamp(static_cast<time_t>(value_as_double / 1000));
auto milliseconds = static_cast<i16>(fmod(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. // 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()) if (vm.exception())
return {}; return {};
if (!year_value.is_finite_number()) { if (!year_value.is_finite_number()) {
@ -197,7 +220,7 @@ Value DateConstructor::construct(Function&)
} }
auto year = year_value.as_i32(); 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()) if (vm.exception())
return {}; return {};
if (!month_index_value.is_finite_number()) { if (!month_index_value.is_finite_number()) {
@ -256,10 +279,10 @@ Value DateConstructor::construct(Function&)
year += 1900; year += 1900;
int month = month_index + 1; int month = month_index + 1;
auto datetime = Core::DateTime::create(year, month, day, hours, minutes, seconds); auto datetime = Core::DateTime::create(year, month, day, hours, minutes, seconds);
auto* date = Date::create(global_object(), datetime, milliseconds); auto time = datetime.timestamp() * 1000.0 + milliseconds;
if (date->time() > Date::time_clip) if (time > Date::time_clip)
return create_invalid_date(); 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 // 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 * SPDX-License-Identifier: BSD-2-Clause
*/ */
#include <LibJS/Runtime/AbstractOperations.h>
#include <LibJS/Runtime/Error.h> #include <LibJS/Runtime/Error.h>
#include <LibJS/Runtime/ErrorConstructor.h> #include <LibJS/Runtime/ErrorConstructor.h>
#include <LibJS/Runtime/GlobalObject.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 // 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(); auto& vm = this->vm();
// FIXME: Use OrdinaryCreateFromConstructor(newTarget, "%Error.prototype%") auto& global_object = this->global_object();
auto* error = Error::create(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; u8 attr = Attribute::Writable | Attribute::Configurable;
if (!vm.argument(0).is_undefined()) { 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()) if (vm.exception())
return {}; return {};
error->define_property(vm.names.message, js_string(vm, message), attr); 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 */ \ /* 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(); \ auto& vm = this->vm(); \
/* FIXME: Use OrdinaryCreateFromConstructor( \ auto& global_object = this->global_object(); \
* FIXME: newTarget, "%NativeError.prototype%"). */ \ \
auto* error = ClassName::create(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; \ u8 attr = Attribute::Writable | Attribute::Configurable; \
\ \
if (!vm.argument(0).is_undefined()) { \ 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()) \ if (vm.exception()) \
return {}; \ return {}; \
error->define_property(vm.names.message, js_string(vm, message), attr); \ error->define_property(vm.names.message, js_string(vm, message), attr); \

View file

@ -4,6 +4,7 @@
* SPDX-License-Identifier: BSD-2-Clause * SPDX-License-Identifier: BSD-2-Clause
*/ */
#include <LibJS/Runtime/AbstractOperations.h>
#include <LibJS/Runtime/Error.h> #include <LibJS/Runtime/Error.h>
#include <LibJS/Runtime/FinalizationRegistry.h> #include <LibJS/Runtime/FinalizationRegistry.h>
#include <LibJS/Runtime/FinalizationRegistryConstructor.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 // 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& vm = this->vm();
auto& global_object = this->global_object();
auto cleanup_callback = vm.argument(0); auto cleanup_callback = vm.argument(0);
if (!cleanup_callback.is_function()) { 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 {}; return {};
} }
return ordinary_create_from_constructor<FinalizationRegistry>(global_object, new_target, &GlobalObject::finalization_registry_prototype, cleanup_callback.as_function());
// FIXME: Use OrdinaryCreateFromConstructor(NewTarget, "%FinalizationRegistry.prototype%")
return FinalizationRegistry::create(global_object(), cleanup_callback.as_function());
} }
} }

View file

@ -4,6 +4,7 @@
* SPDX-License-Identifier: BSD-2-Clause * SPDX-License-Identifier: BSD-2-Clause
*/ */
#include <LibJS/Runtime/AbstractOperations.h>
#include <LibJS/Runtime/Error.h> #include <LibJS/Runtime/Error.h>
#include <LibJS/Runtime/GlobalObject.h> #include <LibJS/Runtime/GlobalObject.h>
#include <LibJS/Runtime/IteratorOperations.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 // 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& 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()) if (vm.argument(0).is_nullish())
return map; return map;
@ -56,14 +60,14 @@ Value MapConstructor::construct(Function&)
if (vm.exception()) if (vm.exception())
return {}; return {};
if (!adder.is_function()) { 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 {}; 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()) if (vm.exception())
return IterationDecision::Break; return IterationDecision::Break;
if (!iterator_value.is_object()) { 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; return IterationDecision::Break;
} }
auto key = iterator_value.as_object().get(0).value_or(js_undefined()); auto key = iterator_value.as_object().get(0).value_or(js_undefined());

View file

@ -4,6 +4,7 @@
* SPDX-License-Identifier: BSD-2-Clause * SPDX-License-Identifier: BSD-2-Clause
*/ */
#include <LibJS/Runtime/AbstractOperations.h>
#include <LibJS/Runtime/Error.h> #include <LibJS/Runtime/Error.h>
#include <LibJS/Runtime/GlobalObject.h> #include <LibJS/Runtime/GlobalObject.h>
#include <LibJS/Runtime/NumberConstructor.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 // 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& vm = this->vm();
auto& global_object = this->global_object(); auto& global_object = this->global_object();
@ -102,8 +103,7 @@ Value NumberConstructor::construct(Function&)
auto number = get_value_from_constructor_argument(global_object); auto number = get_value_from_constructor_argument(global_object);
if (vm.exception()) if (vm.exception())
return {}; return {};
// FIXME: Use OrdinaryCreateFromConstructor(NewTarget, "%Number.prototype%") return ordinary_create_from_constructor<NumberObject>(global_object, new_target, &GlobalObject::number_prototype, number.as_double());
return NumberObject::create(global_object, number.as_double());
} }
// 21.1.2.2 Number.isFinite ( number ), https://tc39.es/ecma262/#sec-number.isfinite // 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 // 20.1.1.1 Object ( [ value ] ), https://tc39.es/ecma262/#sec-object-value
Value ObjectConstructor::call() 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& vm = this->vm();
auto& global_object = this->global_object(); 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); auto value = vm.argument(0);
if (value.is_nullish()) if (value.is_nullish())
return Object::create(global_object, global_object.object_prototype()); return Object::create(global_object, global_object.object_prototype());
return value.to_object(global_object); 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 // 20.1.2.10 Object.getOwnPropertyNames ( O ), https://tc39.es/ecma262/#sec-object.getownpropertynames
JS_DEFINE_NATIVE_FUNCTION(ObjectConstructor::get_own_property_names) JS_DEFINE_NATIVE_FUNCTION(ObjectConstructor::get_own_property_names)
{ {

View file

@ -5,6 +5,7 @@
*/ */
#include <LibJS/Interpreter.h> #include <LibJS/Interpreter.h>
#include <LibJS/Runtime/AbstractOperations.h>
#include <LibJS/Runtime/Error.h> #include <LibJS/Runtime/Error.h>
#include <LibJS/Runtime/Function.h> #include <LibJS/Runtime/Function.h>
#include <LibJS/Runtime/GlobalObject.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 // 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& vm = this->vm();
auto& global_object = this->global_object();
auto executor = vm.argument(0); auto executor = vm.argument(0);
if (!executor.is_function()) { if (!executor.is_function()) {
vm.throw_exception<TypeError>(global_object(), ErrorType::PromiseExecutorNotAFunction); vm.throw_exception<TypeError>(global_object, ErrorType::PromiseExecutorNotAFunction);
return {}; 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 [resolve_function, reject_function] = promise->create_resolving_functions();
auto completion_value = vm.call(executor.as_function(), js_undefined(), &resolve_function, &reject_function); 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()) if (vm.exception())
return {}; return {};
} }
// FIXME: Use RegExpAlloc (which uses OrdinaryCreateFromConstructor)
return RegExpObject::create(global_object(), pattern, flags); return RegExpObject::create(global_object(), pattern, flags);
} }

View file

@ -4,6 +4,7 @@
* SPDX-License-Identifier: BSD-2-Clause * SPDX-License-Identifier: BSD-2-Clause
*/ */
#include <LibJS/Runtime/AbstractOperations.h>
#include <LibJS/Runtime/Error.h> #include <LibJS/Runtime/Error.h>
#include <LibJS/Runtime/GlobalObject.h> #include <LibJS/Runtime/GlobalObject.h>
#include <LibJS/Runtime/IteratorOperations.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 // 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(); auto& vm = this->vm();
if (vm.argument(0).is_nullish()) auto& global_object = this->global_object();
return Set::create(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); auto adder = set->get(vm.names.add);
if (vm.exception()) if (vm.exception())
return {}; return {};
if (!adder.is_function()) { 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 {}; 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()) if (vm.exception())
return IterationDecision::Break; return IterationDecision::Break;
(void)vm.call(adder.as_function(), Value(set), iterator_value); (void)vm.call(adder.as_function(), Value(set), iterator_value);

View file

@ -4,6 +4,7 @@
* SPDX-License-Identifier: BSD-2-Clause * SPDX-License-Identifier: BSD-2-Clause
*/ */
#include <LibJS/Runtime/AbstractOperations.h>
#include <LibJS/Runtime/Error.h> #include <LibJS/Runtime/Error.h>
#include <LibJS/Runtime/GlobalObject.h> #include <LibJS/Runtime/GlobalObject.h>
#include <LibJS/Runtime/IteratorOperations.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 // 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(); auto& vm = this->vm();
if (vm.argument(0).is_nullish()) auto& global_object = this->global_object();
return WeakMap::create(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); auto adder = weak_map->get(vm.names.set);
if (vm.exception()) if (vm.exception())
return {}; return {};
if (!adder.is_function()) { 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 {}; 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()) if (vm.exception())
return IterationDecision::Break; return IterationDecision::Break;
if (!iterator_value.is_object()) { 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; return IterationDecision::Break;
} }
auto key = iterator_value.as_object().get(0).value_or(js_undefined()); auto key = iterator_value.as_object().get(0).value_or(js_undefined());

View file

@ -4,6 +4,7 @@
* SPDX-License-Identifier: BSD-2-Clause * SPDX-License-Identifier: BSD-2-Clause
*/ */
#include <LibJS/Runtime/AbstractOperations.h>
#include <LibJS/Runtime/Error.h> #include <LibJS/Runtime/Error.h>
#include <LibJS/Runtime/GlobalObject.h> #include <LibJS/Runtime/GlobalObject.h>
#include <LibJS/Runtime/WeakRef.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 // 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& vm = this->vm();
auto& global_object = this->global_object();
auto target = vm.argument(0); auto target = vm.argument(0);
if (!target.is_object()) { 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 {}; return {};
} }
return ordinary_create_from_constructor<WeakRef>(global_object, new_target, &GlobalObject::weak_ref_prototype, &target.as_object());
// FIXME: Use OrdinaryCreateFromConstructor(newTarget, "%WeakRef.prototype%")
return WeakRef::create(global_object(), &target.as_object());
} }
} }

View file

@ -4,6 +4,7 @@
* SPDX-License-Identifier: BSD-2-Clause * SPDX-License-Identifier: BSD-2-Clause
*/ */
#include <LibJS/Runtime/AbstractOperations.h>
#include <LibJS/Runtime/Error.h> #include <LibJS/Runtime/Error.h>
#include <LibJS/Runtime/GlobalObject.h> #include <LibJS/Runtime/GlobalObject.h>
#include <LibJS/Runtime/IteratorOperations.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 // 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(); auto& vm = this->vm();
if (vm.argument(0).is_nullish()) auto& global_object = this->global_object();
return WeakSet::create(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); auto adder = weak_set->get(vm.names.add);
if (vm.exception()) if (vm.exception())
return {}; return {};
if (!adder.is_function()) { 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 {}; 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()) if (vm.exception())
return IterationDecision::Break; return IterationDecision::Break;
(void)vm.call(adder.as_function(), Value(weak_set), iterator_value); (void)vm.call(adder.as_function(), Value(weak_set), iterator_value);