AbstractOperations.cpp 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179
  1. /*
  2. * Copyright (c) 2020-2021, Linus Groh <linusg@serenityos.org>
  3. * Copyright (c) 2021, Andreas Kling <kling@serenityos.org>
  4. *
  5. * SPDX-License-Identifier: BSD-2-Clause
  6. */
  7. #include <AK/Function.h>
  8. #include <AK/Result.h>
  9. #include <LibJS/Runtime/AbstractOperations.h>
  10. #include <LibJS/Runtime/BoundFunction.h>
  11. #include <LibJS/Runtime/DeclarativeEnvironmentRecord.h>
  12. #include <LibJS/Runtime/ErrorTypes.h>
  13. #include <LibJS/Runtime/Function.h>
  14. #include <LibJS/Runtime/GlobalObject.h>
  15. #include <LibJS/Runtime/Object.h>
  16. #include <LibJS/Runtime/ObjectEnvironmentRecord.h>
  17. #include <LibJS/Runtime/PropertyName.h>
  18. #include <LibJS/Runtime/ProxyObject.h>
  19. namespace JS {
  20. // Used in various abstract operations to make it obvious when a non-optional return value must be discarded.
  21. static constexpr double INVALID { 0 };
  22. // 7.2.1 RequireObjectCoercible ( argument ), https://tc39.es/ecma262/#sec-requireobjectcoercible
  23. Value require_object_coercible(GlobalObject& global_object, Value value)
  24. {
  25. auto& vm = global_object.vm();
  26. if (value.is_nullish()) {
  27. vm.throw_exception<TypeError>(global_object, ErrorType::NotObjectCoercible, value.to_string_without_side_effects());
  28. return {};
  29. }
  30. return value;
  31. }
  32. // 7.3.10 GetMethod ( V, P ), https://tc39.es/ecma262/#sec-getmethod
  33. Function* get_method(GlobalObject& global_object, Value value, PropertyName const& property_name)
  34. {
  35. auto& vm = global_object.vm();
  36. auto* object = value.to_object(global_object);
  37. if (vm.exception())
  38. return nullptr;
  39. auto property_value = object->get(property_name);
  40. if (vm.exception())
  41. return nullptr;
  42. if (property_value.is_empty() || property_value.is_nullish())
  43. return nullptr;
  44. if (!property_value.is_function()) {
  45. vm.throw_exception<TypeError>(global_object, ErrorType::NotAFunction, property_value.to_string_without_side_effects());
  46. return nullptr;
  47. }
  48. return &property_value.as_function();
  49. }
  50. // 7.3.18 LengthOfArrayLike ( obj ), https://tc39.es/ecma262/#sec-lengthofarraylike
  51. size_t length_of_array_like(GlobalObject& global_object, Object const& object)
  52. {
  53. auto& vm = global_object.vm();
  54. auto result = object.get(vm.names.length).value_or(js_undefined());
  55. if (vm.exception())
  56. return INVALID;
  57. return result.to_length(global_object);
  58. }
  59. // 7.3.19 CreateListFromArrayLike ( obj [ , elementTypes ] ), https://tc39.es/ecma262/#sec-createlistfromarraylike
  60. MarkedValueList create_list_from_array_like(GlobalObject& global_object, Value value, AK::Function<Result<void, ErrorType>(Value)> check_value)
  61. {
  62. auto& vm = global_object.vm();
  63. auto& heap = global_object.heap();
  64. if (!value.is_object()) {
  65. vm.throw_exception<TypeError>(global_object, ErrorType::NotAnObject, value.to_string_without_side_effects());
  66. return MarkedValueList { heap };
  67. }
  68. auto& array_like = value.as_object();
  69. auto length = length_of_array_like(global_object, array_like);
  70. if (vm.exception())
  71. return MarkedValueList { heap };
  72. auto list = MarkedValueList { heap };
  73. for (size_t i = 0; i < length; ++i) {
  74. auto index_name = String::number(i);
  75. auto next = array_like.get(index_name).value_or(js_undefined());
  76. if (vm.exception())
  77. return MarkedValueList { heap };
  78. if (check_value) {
  79. auto result = check_value(next);
  80. if (result.is_error()) {
  81. vm.throw_exception<TypeError>(global_object, result.release_error());
  82. return MarkedValueList { heap };
  83. }
  84. }
  85. list.append(next);
  86. }
  87. return list;
  88. }
  89. // 7.3.22 SpeciesConstructor ( O, defaultConstructor ), https://tc39.es/ecma262/#sec-speciesconstructor
  90. Function* species_constructor(GlobalObject& global_object, Object const& object, Function& default_constructor)
  91. {
  92. auto& vm = global_object.vm();
  93. auto constructor = object.get(vm.names.constructor).value_or(js_undefined());
  94. if (vm.exception())
  95. return nullptr;
  96. if (constructor.is_undefined())
  97. return &default_constructor;
  98. if (!constructor.is_object()) {
  99. vm.throw_exception<TypeError>(global_object, ErrorType::NotAConstructor, constructor.to_string_without_side_effects());
  100. return nullptr;
  101. }
  102. auto species = constructor.as_object().get(vm.well_known_symbol_species()).value_or(js_undefined());
  103. if (species.is_nullish())
  104. return &default_constructor;
  105. if (species.is_constructor())
  106. return &species.as_function();
  107. vm.throw_exception<TypeError>(global_object, ErrorType::NotAConstructor, species.to_string_without_side_effects());
  108. return nullptr;
  109. }
  110. // 7.3.24 GetFunctionRealm ( obj ), https://tc39.es/ecma262/#sec-getfunctionrealm
  111. GlobalObject* get_function_realm(GlobalObject& global_object, Function const& function)
  112. {
  113. auto& vm = global_object.vm();
  114. // FIXME: not sure how to do this currently.
  115. // 2. If obj has a [[Realm]] internal slot, then
  116. // a. Return obj.[[Realm]].
  117. if (is<BoundFunction>(function)) {
  118. auto& bound_function = static_cast<BoundFunction const&>(function);
  119. auto& target = bound_function.target_function();
  120. return get_function_realm(global_object, target);
  121. }
  122. if (is<ProxyObject>(function)) {
  123. auto& proxy = static_cast<ProxyObject const&>(function);
  124. if (proxy.is_revoked()) {
  125. vm.throw_exception<TypeError>(global_object, ErrorType::ProxyRevoked);
  126. return nullptr;
  127. }
  128. auto& proxy_target = proxy.target();
  129. VERIFY(proxy_target.is_function());
  130. return get_function_realm(global_object, static_cast<Function const&>(proxy_target));
  131. }
  132. // 5. Return the current Realm Record.
  133. return &global_object;
  134. }
  135. // 10.1.14 GetPrototypeFromConstructor ( constructor, intrinsicDefaultProto )
  136. Object* get_prototype_from_constructor(GlobalObject& global_object, Function const& constructor, Object* (GlobalObject::*intrinsic_default_prototype)())
  137. {
  138. auto& vm = global_object.vm();
  139. auto prototype = constructor.get(vm.names.prototype);
  140. if (vm.exception())
  141. return nullptr;
  142. if (!prototype.is_object()) {
  143. auto* realm = get_function_realm(global_object, constructor);
  144. if (vm.exception())
  145. return nullptr;
  146. prototype = (realm->*intrinsic_default_prototype)();
  147. }
  148. return &prototype.as_object();
  149. }
  150. // 9.1.2.2 NewDeclarativeEnvironment ( E ), https://tc39.es/ecma262/#sec-newdeclarativeenvironment
  151. DeclarativeEnvironmentRecord* new_declarative_environment(EnvironmentRecord& environment_record)
  152. {
  153. auto& global_object = environment_record.global_object();
  154. return global_object.heap().allocate<DeclarativeEnvironmentRecord>(global_object, &environment_record);
  155. }
  156. // 9.1.2.3 NewObjectEnvironment ( O, W, E ), https://tc39.es/ecma262/#sec-newobjectenvironment
  157. ObjectEnvironmentRecord* new_object_environment(Object& object, bool is_with_environment, EnvironmentRecord* environment_record)
  158. {
  159. auto& global_object = object.global_object();
  160. if (!is_with_environment) {
  161. TODO();
  162. }
  163. return global_object.heap().allocate<ObjectEnvironmentRecord>(global_object, object, environment_record);
  164. }
  165. }