SymbolPrototype.cpp 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100
  1. /*
  2. * Copyright (c) 2020, Matthew Olsson <mattco@serenityos.org>
  3. * Copyright (c) 2021-2023, Linus Groh <linusg@serenityos.org>
  4. *
  5. * SPDX-License-Identifier: BSD-2-Clause
  6. */
  7. #include <AK/Function.h>
  8. #include <AK/TypeCasts.h>
  9. #include <LibJS/Runtime/Completion.h>
  10. #include <LibJS/Runtime/Error.h>
  11. #include <LibJS/Runtime/GlobalObject.h>
  12. #include <LibJS/Runtime/Object.h>
  13. #include <LibJS/Runtime/PrimitiveString.h>
  14. #include <LibJS/Runtime/SymbolObject.h>
  15. #include <LibJS/Runtime/SymbolPrototype.h>
  16. #include <LibJS/Runtime/Value.h>
  17. namespace JS {
  18. GC_DEFINE_ALLOCATOR(SymbolPrototype);
  19. SymbolPrototype::SymbolPrototype(Realm& realm)
  20. : Object(ConstructWithPrototypeTag::Tag, realm.intrinsics().object_prototype())
  21. {
  22. }
  23. void SymbolPrototype::initialize(Realm& realm)
  24. {
  25. auto& vm = this->vm();
  26. Base::initialize(realm);
  27. u8 attr = Attribute::Writable | Attribute::Configurable;
  28. define_native_function(realm, vm.names.toString, to_string, 0, attr);
  29. define_native_function(realm, vm.names.valueOf, value_of, 0, attr);
  30. define_native_accessor(realm, vm.names.description, description_getter, {}, Attribute::Configurable);
  31. define_native_function(realm, vm.well_known_symbol_to_primitive(), symbol_to_primitive, 1, Attribute::Configurable);
  32. // 20.4.3.6 Symbol.prototype [ @@toStringTag ], https://tc39.es/ecma262/#sec-symbol.prototype-@@tostringtag
  33. define_direct_property(vm.well_known_symbol_to_string_tag(), PrimitiveString::create(vm, "Symbol"_string), Attribute::Configurable);
  34. }
  35. // thisSymbolValue ( value ), https://tc39.es/ecma262/#thissymbolvalue
  36. static ThrowCompletionOr<GC::Ref<Symbol>> this_symbol_value(VM& vm, Value value)
  37. {
  38. // 1. If value is a Symbol, return value.
  39. if (value.is_symbol())
  40. return value.as_symbol();
  41. // 2. If value is an Object and value has a [[SymbolData]] internal slot, then
  42. if (value.is_object() && is<SymbolObject>(value.as_object())) {
  43. // a. Let s be value.[[SymbolData]].
  44. // b. Assert: s is a Symbol.
  45. // c. Return s.
  46. return static_cast<SymbolObject&>(value.as_object()).primitive_symbol();
  47. }
  48. // 3. Throw a TypeError exception.
  49. return vm.throw_completion<TypeError>(ErrorType::NotAnObjectOfType, "Symbol");
  50. }
  51. // 20.4.3.2 get Symbol.prototype.description, https://tc39.es/ecma262/#sec-symbol.prototype.description
  52. JS_DEFINE_NATIVE_FUNCTION(SymbolPrototype::description_getter)
  53. {
  54. // 1. Let s be the this value.
  55. // 2. Let sym be ? thisSymbolValue(s).
  56. auto symbol = TRY(this_symbol_value(vm, vm.this_value()));
  57. // 3. Return sym.[[Description]].
  58. auto& description = symbol->description();
  59. return description.has_value()
  60. ? PrimitiveString::create(vm, *description)
  61. : js_undefined();
  62. }
  63. // 20.4.3.3 Symbol.prototype.toString ( ), https://tc39.es/ecma262/#sec-symbol.prototype.tostring
  64. JS_DEFINE_NATIVE_FUNCTION(SymbolPrototype::to_string)
  65. {
  66. // 1. Let sym be ? thisSymbolValue(this value).
  67. auto symbol = TRY(this_symbol_value(vm, vm.this_value()));
  68. // 2. Return SymbolDescriptiveString(sym).
  69. return PrimitiveString::create(vm, TRY_OR_THROW_OOM(vm, symbol->descriptive_string()));
  70. }
  71. // 20.4.3.4 Symbol.prototype.valueOf ( ), https://tc39.es/ecma262/#sec-symbol.prototype.valueof
  72. JS_DEFINE_NATIVE_FUNCTION(SymbolPrototype::value_of)
  73. {
  74. // 1. Return ? thisSymbolValue(this value).
  75. return TRY(this_symbol_value(vm, vm.this_value()));
  76. }
  77. // 20.4.3.5 Symbol.prototype [ @@toPrimitive ] ( hint ), https://tc39.es/ecma262/#sec-symbol.prototype-@@toprimitive
  78. JS_DEFINE_NATIVE_FUNCTION(SymbolPrototype::symbol_to_primitive)
  79. {
  80. // 1. Return ? thisSymbolValue(this value).
  81. // NOTE: The argument is ignored.
  82. return TRY(this_symbol_value(vm, vm.this_value()));
  83. }
  84. }