diff options
Diffstat (limited to 'Userland/Libraries/LibJS/Runtime')
17 files changed, 152 insertions, 100 deletions
diff --git a/Userland/Libraries/LibJS/Runtime/AbstractOperations.cpp b/Userland/Libraries/LibJS/Runtime/AbstractOperations.cpp new file mode 100644 index 0000000000..9e58f28a17 --- /dev/null +++ b/Userland/Libraries/LibJS/Runtime/AbstractOperations.cpp @@ -0,0 +1,115 @@ +/* + * Copyright (c) 2020-2021, Linus Groh <linusg@serenityos.org> + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include <AK/Function.h> +#include <AK/Result.h> +#include <LibJS/Runtime/AbstractOperations.h> +#include <LibJS/Runtime/BoundFunction.h> +#include <LibJS/Runtime/ErrorTypes.h> +#include <LibJS/Runtime/Function.h> +#include <LibJS/Runtime/GlobalObject.h> +#include <LibJS/Runtime/Object.h> +#include <LibJS/Runtime/PropertyName.h> + +namespace JS { + +// Used in various abstract operations to make it obvious when a non-optional return value must be discarded. +static constexpr double INVALID { 0 }; + +// 7.2.1 RequireObjectCoercible ( argument ), https://tc39.es/ecma262/#sec-requireobjectcoercible +Value require_object_coercible(GlobalObject& global_object, Value value) +{ + auto& vm = global_object.vm(); + if (value.is_nullish()) { + vm.throw_exception<TypeError>(global_object, ErrorType::NotObjectCoercible, value.to_string_without_side_effects()); + return {}; + } + return value; +} + +// 7.3.10 GetMethod ( V, P ), https://tc39.es/ecma262/#sec-getmethod +Function* get_method(GlobalObject& global_object, Value value, PropertyName const& property_name) +{ + auto& vm = global_object.vm(); + auto* object = value.to_object(global_object); + if (vm.exception()) + return nullptr; + auto property_value = object->get(property_name); + if (vm.exception()) + return nullptr; + if (property_value.is_empty() || property_value.is_nullish()) + return nullptr; + if (!property_value.is_function()) { + vm.throw_exception<TypeError>(global_object, ErrorType::NotAFunction, property_value.to_string_without_side_effects()); + return nullptr; + } + return &property_value.as_function(); +} + +// 7.3.18 LengthOfArrayLike ( obj ), https://tc39.es/ecma262/#sec-lengthofarraylike +size_t length_of_array_like(GlobalObject& global_object, Object const& object) +{ + auto& vm = global_object.vm(); + auto result = object.get(vm.names.length).value_or(js_undefined()); + if (vm.exception()) + return INVALID; + return result.to_length(global_object); +} + +// 7.3.19 CreateListFromArrayLike ( obj [ , elementTypes ] ), https://tc39.es/ecma262/#sec-createlistfromarraylike +MarkedValueList create_list_from_array_like(GlobalObject& global_object, Value value, AK::Function<Result<void, ErrorType>(Value)> check_value) +{ + auto& vm = global_object.vm(); + auto& heap = global_object.heap(); + if (!value.is_object()) { + vm.throw_exception<TypeError>(global_object, ErrorType::NotAnObject, value.to_string_without_side_effects()); + return MarkedValueList { heap }; + } + auto& array_like = value.as_object(); + auto length = length_of_array_like(global_object, array_like); + if (vm.exception()) + return MarkedValueList { heap }; + auto list = MarkedValueList { heap }; + for (size_t i = 0; i < length; ++i) { + auto index_name = String::number(i); + auto next = array_like.get(index_name).value_or(js_undefined()); + if (vm.exception()) + return MarkedValueList { heap }; + if (check_value) { + auto result = check_value(next); + if (result.is_error()) { + vm.throw_exception<TypeError>(global_object, result.release_error()); + return MarkedValueList { heap }; + } + } + list.append(next); + } + return list; +} + +// 7.3.22 SpeciesConstructor ( O, defaultConstructor ), https://tc39.es/ecma262/#sec-speciesconstructor +Function* species_constructor(GlobalObject& global_object, Object const& object, Function& default_constructor) +{ + auto& vm = global_object.vm(); + auto constructor = object.get(vm.names.constructor).value_or(js_undefined()); + if (vm.exception()) + return nullptr; + if (constructor.is_undefined()) + return &default_constructor; + if (!constructor.is_object()) { + vm.throw_exception<TypeError>(global_object, ErrorType::NotAConstructor, constructor.to_string_without_side_effects()); + return nullptr; + } + auto species = constructor.as_object().get(vm.well_known_symbol_species()).value_or(js_undefined()); + if (species.is_nullish()) + return &default_constructor; + if (species.is_constructor()) + return &species.as_function(); + vm.throw_exception<TypeError>(global_object, ErrorType::NotAConstructor, species.to_string_without_side_effects()); + return nullptr; +} + +} diff --git a/Userland/Libraries/LibJS/Runtime/AbstractOperations.h b/Userland/Libraries/LibJS/Runtime/AbstractOperations.h new file mode 100644 index 0000000000..df9ecf40df --- /dev/null +++ b/Userland/Libraries/LibJS/Runtime/AbstractOperations.h @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2020-2021, Linus Groh <linusg@serenityos.org> + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include <AK/Forward.h> +#include <LibJS/Forward.h> +#include <LibJS/Runtime/Value.h> + +namespace JS { + +Value require_object_coercible(GlobalObject&, Value); +Function* get_method(GlobalObject& global_object, Value, PropertyName const&); +size_t length_of_array_like(GlobalObject&, Object const&); +MarkedValueList create_list_from_array_like(GlobalObject&, Value, AK::Function<Result<void, ErrorType>(Value)> = {}); +Function* species_constructor(GlobalObject&, Object const&, Function& default_constructor); + +} diff --git a/Userland/Libraries/LibJS/Runtime/ArrayBufferPrototype.cpp b/Userland/Libraries/LibJS/Runtime/ArrayBufferPrototype.cpp index 997fc9d2d2..388870406f 100644 --- a/Userland/Libraries/LibJS/Runtime/ArrayBufferPrototype.cpp +++ b/Userland/Libraries/LibJS/Runtime/ArrayBufferPrototype.cpp @@ -6,6 +6,7 @@ */ #include <AK/Function.h> +#include <LibJS/Runtime/AbstractOperations.h> #include <LibJS/Runtime/ArrayBuffer.h> #include <LibJS/Runtime/ArrayBufferConstructor.h> #include <LibJS/Runtime/ArrayBufferPrototype.h> diff --git a/Userland/Libraries/LibJS/Runtime/ArrayPrototype.cpp b/Userland/Libraries/LibJS/Runtime/ArrayPrototype.cpp index fd6f8b28d3..1924d367da 100644 --- a/Userland/Libraries/LibJS/Runtime/ArrayPrototype.cpp +++ b/Userland/Libraries/LibJS/Runtime/ArrayPrototype.cpp @@ -11,6 +11,7 @@ #include <AK/HashTable.h> #include <AK/ScopeGuard.h> #include <AK/StringBuilder.h> +#include <LibJS/Runtime/AbstractOperations.h> #include <LibJS/Runtime/Array.h> #include <LibJS/Runtime/ArrayIterator.h> #include <LibJS/Runtime/ArrayPrototype.h> diff --git a/Userland/Libraries/LibJS/Runtime/FunctionPrototype.cpp b/Userland/Libraries/LibJS/Runtime/FunctionPrototype.cpp index 85c7b2e1fc..dde96e0433 100644 --- a/Userland/Libraries/LibJS/Runtime/FunctionPrototype.cpp +++ b/Userland/Libraries/LibJS/Runtime/FunctionPrototype.cpp @@ -8,6 +8,7 @@ #include <AK/StringBuilder.h> #include <LibJS/AST.h> #include <LibJS/Interpreter.h> +#include <LibJS/Runtime/AbstractOperations.h> #include <LibJS/Runtime/BoundFunction.h> #include <LibJS/Runtime/Error.h> #include <LibJS/Runtime/Function.h> diff --git a/Userland/Libraries/LibJS/Runtime/IteratorOperations.cpp b/Userland/Libraries/LibJS/Runtime/IteratorOperations.cpp index dca658cee3..f7e6a1a9c9 100644 --- a/Userland/Libraries/LibJS/Runtime/IteratorOperations.cpp +++ b/Userland/Libraries/LibJS/Runtime/IteratorOperations.cpp @@ -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> diff --git a/Userland/Libraries/LibJS/Runtime/JSONObject.cpp b/Userland/Libraries/LibJS/Runtime/JSONObject.cpp index 2405e3e46f..736941d39b 100644 --- a/Userland/Libraries/LibJS/Runtime/JSONObject.cpp +++ b/Userland/Libraries/LibJS/Runtime/JSONObject.cpp @@ -9,6 +9,7 @@ #include <AK/JsonObject.h> #include <AK/JsonParser.h> #include <AK/StringBuilder.h> +#include <LibJS/Runtime/AbstractOperations.h> #include <LibJS/Runtime/Array.h> #include <LibJS/Runtime/BigIntObject.h> #include <LibJS/Runtime/BooleanObject.h> diff --git a/Userland/Libraries/LibJS/Runtime/ObjectConstructor.cpp b/Userland/Libraries/LibJS/Runtime/ObjectConstructor.cpp index d59659fce0..c4b917af0e 100644 --- a/Userland/Libraries/LibJS/Runtime/ObjectConstructor.cpp +++ b/Userland/Libraries/LibJS/Runtime/ObjectConstructor.cpp @@ -6,6 +6,7 @@ */ #include <AK/Function.h> +#include <LibJS/Runtime/AbstractOperations.h> #include <LibJS/Runtime/Array.h> #include <LibJS/Runtime/Error.h> #include <LibJS/Runtime/GlobalObject.h> diff --git a/Userland/Libraries/LibJS/Runtime/ObjectPrototype.cpp b/Userland/Libraries/LibJS/Runtime/ObjectPrototype.cpp index 3f1cd5ad6a..d69b242738 100644 --- a/Userland/Libraries/LibJS/Runtime/ObjectPrototype.cpp +++ b/Userland/Libraries/LibJS/Runtime/ObjectPrototype.cpp @@ -6,6 +6,7 @@ #include <AK/Function.h> #include <AK/String.h> +#include <LibJS/Runtime/AbstractOperations.h> #include <LibJS/Runtime/Accessor.h> #include <LibJS/Runtime/BooleanObject.h> #include <LibJS/Runtime/Date.h> diff --git a/Userland/Libraries/LibJS/Runtime/PromisePrototype.cpp b/Userland/Libraries/LibJS/Runtime/PromisePrototype.cpp index 69a31d6477..b071633dcd 100644 --- a/Userland/Libraries/LibJS/Runtime/PromisePrototype.cpp +++ b/Userland/Libraries/LibJS/Runtime/PromisePrototype.cpp @@ -6,6 +6,7 @@ #include <AK/Function.h> #include <LibJS/Interpreter.h> +#include <LibJS/Runtime/AbstractOperations.h> #include <LibJS/Runtime/Error.h> #include <LibJS/Runtime/GlobalObject.h> #include <LibJS/Runtime/Promise.h> diff --git a/Userland/Libraries/LibJS/Runtime/ProxyObject.cpp b/Userland/Libraries/LibJS/Runtime/ProxyObject.cpp index 01844a072b..560f46cbb5 100644 --- a/Userland/Libraries/LibJS/Runtime/ProxyObject.cpp +++ b/Userland/Libraries/LibJS/Runtime/ProxyObject.cpp @@ -5,6 +5,7 @@ * SPDX-License-Identifier: BSD-2-Clause */ +#include <LibJS/Runtime/AbstractOperations.h> #include <LibJS/Runtime/Accessor.h> #include <LibJS/Runtime/Array.h> #include <LibJS/Runtime/Error.h> diff --git a/Userland/Libraries/LibJS/Runtime/ReflectObject.cpp b/Userland/Libraries/LibJS/Runtime/ReflectObject.cpp index 0ef298d202..8598c3f546 100644 --- a/Userland/Libraries/LibJS/Runtime/ReflectObject.cpp +++ b/Userland/Libraries/LibJS/Runtime/ReflectObject.cpp @@ -5,6 +5,7 @@ */ #include <AK/Function.h> +#include <LibJS/Runtime/AbstractOperations.h> #include <LibJS/Runtime/Array.h> #include <LibJS/Runtime/Error.h> #include <LibJS/Runtime/Function.h> diff --git a/Userland/Libraries/LibJS/Runtime/RegExpPrototype.cpp b/Userland/Libraries/LibJS/Runtime/RegExpPrototype.cpp index 3bb2fab46c..f4ee2a6117 100644 --- a/Userland/Libraries/LibJS/Runtime/RegExpPrototype.cpp +++ b/Userland/Libraries/LibJS/Runtime/RegExpPrototype.cpp @@ -6,6 +6,7 @@ */ #include <AK/Function.h> +#include <LibJS/Runtime/AbstractOperations.h> #include <LibJS/Runtime/Array.h> #include <LibJS/Runtime/Error.h> #include <LibJS/Runtime/GlobalObject.h> diff --git a/Userland/Libraries/LibJS/Runtime/StringPrototype.cpp b/Userland/Libraries/LibJS/Runtime/StringPrototype.cpp index 4166cd0356..e324fbb05c 100644 --- a/Userland/Libraries/LibJS/Runtime/StringPrototype.cpp +++ b/Userland/Libraries/LibJS/Runtime/StringPrototype.cpp @@ -9,6 +9,7 @@ #include <AK/Function.h> #include <AK/StringBuilder.h> #include <LibJS/Heap/Heap.h> +#include <LibJS/Runtime/AbstractOperations.h> #include <LibJS/Runtime/Array.h> #include <LibJS/Runtime/Error.h> #include <LibJS/Runtime/GlobalObject.h> diff --git a/Userland/Libraries/LibJS/Runtime/TypedArray.cpp b/Userland/Libraries/LibJS/Runtime/TypedArray.cpp index 76df4fdd2a..9df1b56c2c 100644 --- a/Userland/Libraries/LibJS/Runtime/TypedArray.cpp +++ b/Userland/Libraries/LibJS/Runtime/TypedArray.cpp @@ -6,6 +6,7 @@ */ #include <AK/Checked.h> +#include <LibJS/Runtime/AbstractOperations.h> #include <LibJS/Runtime/ArrayBuffer.h> #include <LibJS/Runtime/GlobalObject.h> #include <LibJS/Runtime/IteratorOperations.h> diff --git a/Userland/Libraries/LibJS/Runtime/Value.cpp b/Userland/Libraries/LibJS/Runtime/Value.cpp index ab045e17a9..1f3de02866 100644 --- a/Userland/Libraries/LibJS/Runtime/Value.cpp +++ b/Userland/Libraries/LibJS/Runtime/Value.cpp @@ -7,13 +7,13 @@ #include <AK/AllOf.h> #include <AK/FlyString.h> -#include <AK/Result.h> #include <AK/String.h> #include <AK/StringBuilder.h> #include <AK/Utf8View.h> #include <LibCrypto/BigInt/SignedBigInteger.h> #include <LibCrypto/NumberTheory/ModularFunctions.h> #include <LibJS/Heap/Heap.h> +#include <LibJS/Runtime/AbstractOperations.h> #include <LibJS/Runtime/Accessor.h> #include <LibJS/Runtime/Array.h> #include <LibJS/Runtime/BigInt.h> @@ -38,7 +38,7 @@ namespace JS { // Used in various abstract operations to make it obvious when a non-optional return value must be discarded. -static const double INVALID { 0 }; +static constexpr double INVALID { 0 }; static inline bool same_type_for_equality(const Value& lhs, const Value& rhs) { @@ -1495,97 +1495,4 @@ TriState abstract_relation(GlobalObject& global_object, bool left_first, Value l return TriState::False; } -// 7.3.10 GetMethod ( V, P ), https://tc39.es/ecma262/#sec-getmethod -Function* get_method(GlobalObject& global_object, Value value, const PropertyName& property_name) -{ - auto& vm = global_object.vm(); - auto* object = value.to_object(global_object); - if (vm.exception()) - return nullptr; - auto property_value = object->get(property_name); - if (vm.exception()) - return nullptr; - if (property_value.is_empty() || property_value.is_nullish()) - return nullptr; - if (!property_value.is_function()) { - vm.throw_exception<TypeError>(global_object, ErrorType::NotAFunction, property_value.to_string_without_side_effects()); - return nullptr; - } - return &property_value.as_function(); -} - -// 7.3.18 LengthOfArrayLike ( obj ), https://tc39.es/ecma262/#sec-lengthofarraylike -size_t length_of_array_like(GlobalObject& global_object, const Object& object) -{ - auto& vm = global_object.vm(); - auto result = object.get(vm.names.length).value_or(js_undefined()); - if (vm.exception()) - return INVALID; - return result.to_length(global_object); -} - -// 7.3.22 SpeciesConstructor ( O, defaultConstructor ), https://tc39.es/ecma262/#sec-speciesconstructor -Function* species_constructor(GlobalObject& global_object, const Object& object, Function& default_constructor) -{ - auto& vm = global_object.vm(); - auto constructor = object.get(vm.names.constructor).value_or(js_undefined()); - if (vm.exception()) - return nullptr; - if (constructor.is_undefined()) - return &default_constructor; - if (!constructor.is_object()) { - vm.throw_exception<TypeError>(global_object, ErrorType::NotAConstructor, constructor.to_string_without_side_effects()); - return nullptr; - } - auto species = constructor.as_object().get(vm.well_known_symbol_species()).value_or(js_undefined()); - if (species.is_nullish()) - return &default_constructor; - if (species.is_constructor()) - return &species.as_function(); - vm.throw_exception<TypeError>(global_object, ErrorType::NotAConstructor, species.to_string_without_side_effects()); - return nullptr; -} - -// 7.2.1 RequireObjectCoercible ( argument ), https://tc39.es/ecma262/#sec-requireobjectcoercible -Value require_object_coercible(GlobalObject& global_object, Value value) -{ - auto& vm = global_object.vm(); - if (value.is_nullish()) { - vm.throw_exception<TypeError>(global_object, ErrorType::NotObjectCoercible, value.to_string_without_side_effects()); - return {}; - } - return value; -} - -// 7.3.19 CreateListFromArrayLike ( obj [ , elementTypes ] ), https://tc39.es/ecma262/#sec-createlistfromarraylike -MarkedValueList create_list_from_array_like(GlobalObject& global_object, Value value, AK::Function<Result<void, ErrorType>(Value)> check_value) -{ - auto& vm = global_object.vm(); - auto& heap = global_object.heap(); - if (!value.is_object()) { - vm.throw_exception<TypeError>(global_object, ErrorType::NotAnObject, value.to_string_without_side_effects()); - return MarkedValueList { heap }; - } - auto& array_like = value.as_object(); - auto length = length_of_array_like(global_object, array_like); - if (vm.exception()) - return MarkedValueList { heap }; - auto list = MarkedValueList { heap }; - for (size_t i = 0; i < length; ++i) { - auto index_name = String::number(i); - auto next = array_like.get(index_name).value_or(js_undefined()); - if (vm.exception()) - return MarkedValueList { heap }; - if (check_value) { - auto result = check_value(next); - if (result.is_error()) { - vm.throw_exception<TypeError>(global_object, result.release_error()); - return MarkedValueList { heap }; - } - } - list.append(next); - } - return list; -} - } diff --git a/Userland/Libraries/LibJS/Runtime/Value.h b/Userland/Libraries/LibJS/Runtime/Value.h index 50fdfaec63..e178c04e9a 100644 --- a/Userland/Libraries/LibJS/Runtime/Value.h +++ b/Userland/Libraries/LibJS/Runtime/Value.h @@ -17,6 +17,7 @@ #include <AK/Types.h> #include <LibJS/Forward.h> #include <LibJS/Runtime/BigInt.h> +#include <LibJS/Runtime/PrimitiveString.h> #include <math.h> // 2 ** 53 - 1 @@ -378,11 +379,6 @@ bool same_value(Value lhs, Value rhs); bool same_value_zero(Value lhs, Value rhs); bool same_value_non_numeric(Value lhs, Value rhs); TriState abstract_relation(GlobalObject&, bool left_first, Value lhs, Value rhs); -Function* get_method(GlobalObject& global_object, Value, const PropertyName&); -size_t length_of_array_like(GlobalObject&, const Object&); -Function* species_constructor(GlobalObject&, const Object&, Function& default_constructor); -Value require_object_coercible(GlobalObject&, Value); -MarkedValueList create_list_from_array_like(GlobalObject&, Value, AK::Function<Result<void, ErrorType>(Value)> = {}); struct ValueTraits : public Traits<Value> { static unsigned hash(Value value) |