ReflectObject.cpp 9.2 KB

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