AbstractOperations.cpp 5.5 KB

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