diff --git a/Userland/Libraries/LibJS/Runtime/Symbol.cpp b/Userland/Libraries/LibJS/Runtime/Symbol.cpp index 65750d1e6c..0fe3e705ef 100644 --- a/Userland/Libraries/LibJS/Runtime/Symbol.cpp +++ b/Userland/Libraries/LibJS/Runtime/Symbol.cpp @@ -34,4 +34,20 @@ ErrorOr Symbol::descriptive_string() const return String::formatted("Symbol({})", description); } +// 20.4.5.1 KeyForSymbol ( sym ), https://tc39.es/ecma262/#sec-keyforsymbol +Optional Symbol::key() const +{ + // 1. For each element e of the GlobalSymbolRegistry List, do + // a. If SameValue(e.[[Symbol]], sym) is true, return e.[[Key]]. + if (m_is_global) { + // NOTE: Global symbols should always have a description string + VERIFY(m_description.has_value()); + return m_description; + } + + // 2. Assert: GlobalSymbolRegistry does not currently contain an entry for sym. + // 3. Return undefined. + return {}; +} + } diff --git a/Userland/Libraries/LibJS/Runtime/Symbol.h b/Userland/Libraries/LibJS/Runtime/Symbol.h index 6da84100d7..c75bd9f97f 100644 --- a/Userland/Libraries/LibJS/Runtime/Symbol.h +++ b/Userland/Libraries/LibJS/Runtime/Symbol.h @@ -24,6 +24,7 @@ public: bool is_global() const { return m_is_global; } ErrorOr descriptive_string() const; + Optional key() const; private: Symbol(Optional, bool); diff --git a/Userland/Libraries/LibJS/Runtime/SymbolConstructor.cpp b/Userland/Libraries/LibJS/Runtime/SymbolConstructor.cpp index 5e033bae9f..dec3bf65fe 100644 --- a/Userland/Libraries/LibJS/Runtime/SymbolConstructor.cpp +++ b/Userland/Libraries/LibJS/Runtime/SymbolConstructor.cpp @@ -42,14 +42,22 @@ ThrowCompletionOr SymbolConstructor::initialize(Realm& realm) ThrowCompletionOr SymbolConstructor::call() { auto& vm = this->vm(); - if (vm.argument(0).is_undefined()) - return Symbol::create(vm, {}, false); - return Symbol::create(vm, TRY(vm.argument(0).to_string(vm)), false); + auto description = vm.argument(0); + + // 2. If description is undefined, let descString be undefined. + // 3. Else, let descString be ? ToString(description). + auto description_string = description.is_undefined() + ? Optional {} + : TRY(description.to_string(vm)); + + // 4. Return a new Symbol whose [[Description]] is descString. + return Symbol::create(vm, move(description_string), false); } // 20.4.1.1 Symbol ( [ description ] ), https://tc39.es/ecma262/#sec-symbol-description ThrowCompletionOr> SymbolConstructor::construct(FunctionObject&) { + // 1. If NewTarget is not undefined, throw a TypeError exception. return vm().throw_completion(ErrorType::NotAConstructor, "Symbol"); } @@ -83,16 +91,16 @@ JS_DEFINE_NATIVE_FUNCTION(SymbolConstructor::for_) JS_DEFINE_NATIVE_FUNCTION(SymbolConstructor::key_for) { auto argument = vm.argument(0); + + // 1. If sym is not a Symbol, throw a TypeError exception. if (!argument.is_symbol()) return vm.throw_completion(ErrorType::NotASymbol, TRY_OR_THROW_OOM(vm, argument.to_string_without_side_effects())); - auto& symbol = argument.as_symbol(); - if (symbol.is_global()) { - // NOTE: Global symbols should always have a description string - return PrimitiveString::create(vm, *symbol.description()); - } - - return js_undefined(); + // 2. Return KeyForSymbol(sym). + auto key = argument.as_symbol().key(); + return key.has_value() + ? PrimitiveString::create(vm, key.release_value()) + : js_undefined(); } }