ReflectObject.cpp 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231
  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 <LibJS/Runtime/Array.h>
  8. #include <LibJS/Runtime/Error.h>
  9. #include <LibJS/Runtime/Function.h>
  10. #include <LibJS/Runtime/GlobalObject.h>
  11. #include <LibJS/Runtime/NativeFunction.h>
  12. #include <LibJS/Runtime/ReflectObject.h>
  13. namespace JS {
  14. static Object* get_target_object_from(GlobalObject& global_object, const String& name)
  15. {
  16. auto& vm = global_object.vm();
  17. auto target = vm.argument(0);
  18. if (!target.is_object()) {
  19. vm.throw_exception<TypeError>(global_object, ErrorType::ReflectArgumentMustBeAnObject, name);
  20. return nullptr;
  21. }
  22. return static_cast<Object*>(&target.as_object());
  23. }
  24. static Function* get_target_function_from(GlobalObject& global_object, const String& name)
  25. {
  26. auto& vm = global_object.vm();
  27. auto target = vm.argument(0);
  28. if (!target.is_function()) {
  29. vm.throw_exception<TypeError>(global_object, ErrorType::ReflectArgumentMustBeAFunction, name);
  30. return nullptr;
  31. }
  32. return &target.as_function();
  33. }
  34. ReflectObject::ReflectObject(GlobalObject& global_object)
  35. : Object(*global_object.object_prototype())
  36. {
  37. }
  38. void ReflectObject::initialize(GlobalObject& global_object)
  39. {
  40. auto& vm = this->vm();
  41. Object::initialize(global_object);
  42. u8 attr = Attribute::Writable | Attribute::Configurable;
  43. define_native_function(vm.names.apply, apply, 3, attr);
  44. define_native_function(vm.names.construct, construct, 2, attr);
  45. define_native_function(vm.names.defineProperty, define_property, 3, attr);
  46. define_native_function(vm.names.deleteProperty, delete_property, 2, attr);
  47. define_native_function(vm.names.get, get, 2, attr);
  48. define_native_function(vm.names.getOwnPropertyDescriptor, get_own_property_descriptor, 2, attr);
  49. define_native_function(vm.names.getPrototypeOf, get_prototype_of, 1, attr);
  50. define_native_function(vm.names.has, has, 2, attr);
  51. define_native_function(vm.names.isExtensible, is_extensible, 1, attr);
  52. define_native_function(vm.names.ownKeys, own_keys, 1, attr);
  53. define_native_function(vm.names.preventExtensions, prevent_extensions, 1, attr);
  54. define_native_function(vm.names.set, set, 3, attr);
  55. define_native_function(vm.names.setPrototypeOf, set_prototype_of, 2, attr);
  56. Object::define_property(vm.well_known_symbol_to_string_tag(), js_string(vm.heap(), "Reflect"), Attribute::Configurable);
  57. }
  58. ReflectObject::~ReflectObject()
  59. {
  60. }
  61. JS_DEFINE_NATIVE_FUNCTION(ReflectObject::apply)
  62. {
  63. auto* target = get_target_function_from(global_object, "apply");
  64. if (!target)
  65. return {};
  66. auto this_arg = vm.argument(1);
  67. auto arguments = create_list_from_array_like(global_object, vm.argument(2));
  68. if (vm.exception())
  69. return {};
  70. return vm.call(*target, this_arg, move(arguments));
  71. }
  72. JS_DEFINE_NATIVE_FUNCTION(ReflectObject::construct)
  73. {
  74. auto* target = get_target_function_from(global_object, "construct");
  75. if (!target)
  76. return {};
  77. auto arguments = create_list_from_array_like(global_object, vm.argument(1));
  78. if (vm.exception())
  79. return {};
  80. auto* new_target = target;
  81. if (vm.argument_count() > 2) {
  82. auto new_target_value = vm.argument(2);
  83. if (!new_target_value.is_function()
  84. || (is<NativeFunction>(new_target_value.as_object()) && !static_cast<NativeFunction&>(new_target_value.as_object()).has_constructor())) {
  85. vm.throw_exception<TypeError>(global_object, ErrorType::ReflectBadNewTarget);
  86. return {};
  87. }
  88. new_target = &new_target_value.as_function();
  89. }
  90. return vm.construct(*target, *new_target, move(arguments));
  91. }
  92. JS_DEFINE_NATIVE_FUNCTION(ReflectObject::define_property)
  93. {
  94. auto* target = get_target_object_from(global_object, "defineProperty");
  95. if (!target)
  96. return {};
  97. auto property_key = vm.argument(1).to_property_key(global_object);
  98. if (vm.exception())
  99. return {};
  100. if (!vm.argument(2).is_object()) {
  101. vm.throw_exception<TypeError>(global_object, ErrorType::ReflectBadDescriptorArgument);
  102. return {};
  103. }
  104. auto& descriptor = vm.argument(2).as_object();
  105. auto success = target->define_property(property_key, descriptor, false);
  106. if (vm.exception())
  107. return {};
  108. return Value(success);
  109. }
  110. JS_DEFINE_NATIVE_FUNCTION(ReflectObject::delete_property)
  111. {
  112. auto* target = get_target_object_from(global_object, "deleteProperty");
  113. if (!target)
  114. return {};
  115. auto property_key = vm.argument(1).to_property_key(global_object);
  116. if (vm.exception())
  117. return {};
  118. return Value(target->delete_property(property_key));
  119. }
  120. JS_DEFINE_NATIVE_FUNCTION(ReflectObject::get)
  121. {
  122. auto* target = get_target_object_from(global_object, "get");
  123. if (!target)
  124. return {};
  125. auto property_key = vm.argument(1).to_property_key(global_object);
  126. if (vm.exception())
  127. return {};
  128. Value receiver = {};
  129. if (vm.argument_count() > 2)
  130. receiver = vm.argument(2);
  131. return target->get(property_key, receiver).value_or(js_undefined());
  132. }
  133. JS_DEFINE_NATIVE_FUNCTION(ReflectObject::get_own_property_descriptor)
  134. {
  135. auto* target = get_target_object_from(global_object, "getOwnPropertyDescriptor");
  136. if (!target)
  137. return {};
  138. auto property_key = vm.argument(1).to_property_key(global_object);
  139. if (vm.exception())
  140. return {};
  141. return target->get_own_property_descriptor_object(property_key);
  142. }
  143. JS_DEFINE_NATIVE_FUNCTION(ReflectObject::get_prototype_of)
  144. {
  145. auto* target = get_target_object_from(global_object, "getPrototypeOf");
  146. if (!target)
  147. return {};
  148. return target->prototype();
  149. }
  150. JS_DEFINE_NATIVE_FUNCTION(ReflectObject::has)
  151. {
  152. auto* target = get_target_object_from(global_object, "has");
  153. if (!target)
  154. return {};
  155. auto property_key = vm.argument(1).to_property_key(global_object);
  156. if (vm.exception())
  157. return {};
  158. return Value(target->has_property(property_key));
  159. }
  160. JS_DEFINE_NATIVE_FUNCTION(ReflectObject::is_extensible)
  161. {
  162. auto* target = get_target_object_from(global_object, "isExtensible");
  163. if (!target)
  164. return {};
  165. return Value(target->is_extensible());
  166. }
  167. JS_DEFINE_NATIVE_FUNCTION(ReflectObject::own_keys)
  168. {
  169. auto* target = get_target_object_from(global_object, "ownKeys");
  170. if (!target)
  171. return {};
  172. return Array::create_from(global_object, target->get_own_properties(PropertyKind::Key));
  173. }
  174. JS_DEFINE_NATIVE_FUNCTION(ReflectObject::prevent_extensions)
  175. {
  176. auto* target = get_target_object_from(global_object, "preventExtensions");
  177. if (!target)
  178. return {};
  179. return Value(target->prevent_extensions());
  180. }
  181. JS_DEFINE_NATIVE_FUNCTION(ReflectObject::set)
  182. {
  183. auto* target = get_target_object_from(global_object, "set");
  184. if (!target)
  185. return {};
  186. auto property_key = vm.argument(1).to_property_key(global_object);
  187. if (vm.exception())
  188. return {};
  189. auto value = vm.argument(2);
  190. Value receiver = {};
  191. if (vm.argument_count() > 3)
  192. receiver = vm.argument(3);
  193. return Value(target->put(property_key, value, receiver));
  194. }
  195. JS_DEFINE_NATIVE_FUNCTION(ReflectObject::set_prototype_of)
  196. {
  197. auto* target = get_target_object_from(global_object, "setPrototypeOf");
  198. if (!target)
  199. return {};
  200. auto prototype_value = vm.argument(1);
  201. if (!prototype_value.is_object() && !prototype_value.is_null()) {
  202. vm.throw_exception<TypeError>(global_object, ErrorType::ObjectPrototypeWrongType);
  203. return {};
  204. }
  205. Object* prototype = nullptr;
  206. if (!prototype_value.is_null())
  207. prototype = const_cast<Object*>(&prototype_value.as_object());
  208. return Value(target->set_prototype(prototype));
  209. }
  210. }