PropertyDescriptor.cpp 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179
  1. /*
  2. * Copyright (c) 2021, Linus Groh <linusg@serenityos.org>
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #include <LibJS/Runtime/Error.h>
  7. #include <LibJS/Runtime/FunctionObject.h>
  8. #include <LibJS/Runtime/GlobalObject.h>
  9. #include <LibJS/Runtime/Object.h>
  10. #include <LibJS/Runtime/PropertyDescriptor.h>
  11. #include <LibJS/Runtime/Value.h>
  12. namespace JS {
  13. // 6.2.5.1 IsAccessorDescriptor ( Desc ), https://tc39.es/ecma262/#sec-isaccessordescriptor
  14. bool PropertyDescriptor::is_accessor_descriptor() const
  15. {
  16. // 1. If Desc is undefined, return false.
  17. // 2. If both Desc.[[Get]] and Desc.[[Set]] are absent, return false.
  18. if (!get.has_value() && !set.has_value())
  19. return false;
  20. // 3. Return true.
  21. return true;
  22. }
  23. // 6.2.5.2 IsDataDescriptor ( Desc ), https://tc39.es/ecma262/#sec-isdatadescriptor
  24. bool PropertyDescriptor::is_data_descriptor() const
  25. {
  26. // 1. If Desc is undefined, return false.
  27. // 2. If both Desc.[[Value]] and Desc.[[Writable]] are absent, return false.
  28. if (!value.has_value() && !writable.has_value())
  29. return false;
  30. // 3. Return true.
  31. return true;
  32. }
  33. // 6.2.5.3 IsGenericDescriptor ( Desc ), https://tc39.es/ecma262/#sec-isgenericdescriptor
  34. bool PropertyDescriptor::is_generic_descriptor() const
  35. {
  36. // 1. If Desc is undefined, return false.
  37. // 2. If IsAccessorDescriptor(Desc) and IsDataDescriptor(Desc) are both false, return true.
  38. if (!is_accessor_descriptor() && !is_data_descriptor())
  39. return true;
  40. // 3. Return false.
  41. return false;
  42. }
  43. // 6.2.5.4 FromPropertyDescriptor ( Desc ), https://tc39.es/ecma262/#sec-frompropertydescriptor
  44. Value from_property_descriptor(GlobalObject& global_object, Optional<PropertyDescriptor> const& property_descriptor)
  45. {
  46. if (!property_descriptor.has_value())
  47. return js_undefined();
  48. auto& vm = global_object.vm();
  49. auto* object = Object::create(global_object, global_object.object_prototype());
  50. if (property_descriptor->value.has_value())
  51. object->create_data_property_or_throw(vm.names.value, *property_descriptor->value);
  52. if (property_descriptor->writable.has_value())
  53. object->create_data_property_or_throw(vm.names.writable, Value(*property_descriptor->writable));
  54. if (property_descriptor->get.has_value())
  55. object->create_data_property_or_throw(vm.names.get, *property_descriptor->get ? Value(*property_descriptor->get) : js_undefined());
  56. if (property_descriptor->set.has_value())
  57. object->create_data_property_or_throw(vm.names.set, *property_descriptor->set ? Value(*property_descriptor->set) : js_undefined());
  58. if (property_descriptor->enumerable.has_value())
  59. object->create_data_property_or_throw(vm.names.enumerable, Value(*property_descriptor->enumerable));
  60. if (property_descriptor->configurable.has_value())
  61. object->create_data_property_or_throw(vm.names.configurable, Value(*property_descriptor->configurable));
  62. return object;
  63. }
  64. // 6.2.5.5 ToPropertyDescriptor ( Obj ), https://tc39.es/ecma262/#sec-topropertydescriptor
  65. PropertyDescriptor to_property_descriptor(GlobalObject& global_object, Value argument)
  66. {
  67. auto& vm = global_object.vm();
  68. if (!argument.is_object()) {
  69. vm.throw_exception<TypeError>(global_object, ErrorType::NotAnObject, argument.to_string_without_side_effects());
  70. return {};
  71. }
  72. auto& object = argument.as_object();
  73. PropertyDescriptor descriptor;
  74. auto has_enumerable = object.has_property(vm.names.enumerable);
  75. if (vm.exception())
  76. return {};
  77. if (has_enumerable) {
  78. auto enumerable = TRY_OR_DISCARD(object.get(vm.names.enumerable));
  79. descriptor.enumerable = enumerable.to_boolean();
  80. }
  81. auto has_configurable = object.has_property(vm.names.configurable);
  82. if (vm.exception())
  83. return {};
  84. if (has_configurable) {
  85. auto configurable = TRY_OR_DISCARD(object.get(vm.names.configurable));
  86. descriptor.configurable = configurable.to_boolean();
  87. }
  88. auto has_value = object.has_property(vm.names.value);
  89. if (vm.exception())
  90. return {};
  91. if (has_value) {
  92. auto value = TRY_OR_DISCARD(object.get(vm.names.value));
  93. descriptor.value = value;
  94. }
  95. auto has_writable = object.has_property(vm.names.writable);
  96. if (vm.exception())
  97. return {};
  98. if (has_writable) {
  99. auto writable = TRY_OR_DISCARD(object.get(vm.names.writable));
  100. descriptor.writable = writable.to_boolean();
  101. }
  102. auto has_get = object.has_property(vm.names.get);
  103. if (vm.exception())
  104. return {};
  105. if (has_get) {
  106. auto getter = TRY_OR_DISCARD(object.get(vm.names.get));
  107. if (!getter.is_function() && !getter.is_undefined()) {
  108. vm.throw_exception<TypeError>(global_object, ErrorType::AccessorBadField, "get");
  109. return {};
  110. }
  111. descriptor.get = getter.is_function() ? &getter.as_function() : nullptr;
  112. }
  113. auto has_set = object.has_property(vm.names.set);
  114. if (vm.exception())
  115. return {};
  116. if (has_set) {
  117. auto setter = TRY_OR_DISCARD(object.get(vm.names.set));
  118. if (!setter.is_function() && !setter.is_undefined()) {
  119. vm.throw_exception<TypeError>(global_object, ErrorType::AccessorBadField, "set");
  120. return {};
  121. }
  122. descriptor.set = setter.is_function() ? &setter.as_function() : nullptr;
  123. }
  124. if (descriptor.get.has_value() || descriptor.set.has_value()) {
  125. if (descriptor.value.has_value() || descriptor.writable.has_value()) {
  126. vm.throw_exception<TypeError>(global_object, ErrorType::AccessorValueOrWritable);
  127. return {};
  128. }
  129. }
  130. return descriptor;
  131. }
  132. // 6.2.5.6 CompletePropertyDescriptor ( Desc ), https://tc39.es/ecma262/#sec-completepropertydescriptor
  133. void PropertyDescriptor::complete()
  134. {
  135. if (is_generic_descriptor() || is_data_descriptor()) {
  136. if (!value.has_value())
  137. value = Value {};
  138. if (!writable.has_value())
  139. writable = false;
  140. } else {
  141. if (!get.has_value())
  142. get = nullptr;
  143. if (!set.has_value())
  144. set = nullptr;
  145. }
  146. if (!enumerable.has_value())
  147. enumerable = false;
  148. if (!configurable.has_value())
  149. configurable = false;
  150. }
  151. // Non-standard, just a convenient way to get from three Optional<bool> to PropertyAttributes.
  152. PropertyAttributes PropertyDescriptor::attributes() const
  153. {
  154. u8 attributes = 0;
  155. if (writable.value_or(false))
  156. attributes |= Attribute::Writable;
  157. if (enumerable.value_or(false))
  158. attributes |= Attribute::Enumerable;
  159. if (configurable.value_or(false))
  160. attributes |= Attribute::Configurable;
  161. return { attributes };
  162. }
  163. }