ReflectObject.cpp 8.9 KB

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