/src/serenity/Userland/Libraries/LibJS/Runtime/SymbolConstructor.cpp
Line | Count | Source |
1 | | /* |
2 | | * Copyright (c) 2020, Matthew Olsson <mattco@serenityos.org> |
3 | | * Copyright (c) 2022-2023, Linus Groh <linusg@serenityos.org> |
4 | | * |
5 | | * SPDX-License-Identifier: BSD-2-Clause |
6 | | */ |
7 | | |
8 | | #include <LibJS/Runtime/Error.h> |
9 | | #include <LibJS/Runtime/GlobalObject.h> |
10 | | #include <LibJS/Runtime/SymbolConstructor.h> |
11 | | |
12 | | namespace JS { |
13 | | |
14 | | JS_DEFINE_ALLOCATOR(SymbolConstructor); |
15 | | |
16 | | SymbolConstructor::SymbolConstructor(Realm& realm) |
17 | 0 | : NativeFunction(realm.vm().names.Symbol.as_string(), realm.intrinsics().function_prototype()) |
18 | 0 | { |
19 | 0 | } |
20 | | |
21 | | void SymbolConstructor::initialize(Realm& realm) |
22 | 0 | { |
23 | 0 | auto& vm = this->vm(); |
24 | 0 | Base::initialize(realm); |
25 | | |
26 | | // 20.4.2.9 Symbol.prototype, https://tc39.es/ecma262/#sec-symbol.prototype |
27 | 0 | define_direct_property(vm.names.prototype, realm.intrinsics().symbol_prototype(), 0); |
28 | |
|
29 | 0 | u8 attr = Attribute::Writable | Attribute::Configurable; |
30 | 0 | define_native_function(realm, vm.names.for_, for_, 1, attr); |
31 | 0 | define_native_function(realm, vm.names.keyFor, key_for, 1, attr); |
32 | |
|
33 | 0 | #define __JS_ENUMERATE(SymbolName, snake_name) \ |
34 | 0 | define_direct_property(vm.names.SymbolName, vm.well_known_symbol_##snake_name(), 0); |
35 | 0 | JS_ENUMERATE_WELL_KNOWN_SYMBOLS |
36 | 0 | #undef __JS_ENUMERATE |
37 | |
|
38 | 0 | define_direct_property(vm.names.length, Value(0), Attribute::Configurable); |
39 | 0 | } |
40 | | |
41 | | // 20.4.1.1 Symbol ( [ description ] ), https://tc39.es/ecma262/#sec-symbol-description |
42 | | ThrowCompletionOr<Value> SymbolConstructor::call() |
43 | 0 | { |
44 | 0 | auto& vm = this->vm(); |
45 | 0 | auto description = vm.argument(0); |
46 | | |
47 | | // 2. If description is undefined, let descString be undefined. |
48 | | // 3. Else, let descString be ? ToString(description). |
49 | 0 | auto description_string = description.is_undefined() |
50 | 0 | ? Optional<String> {} |
51 | 0 | : TRY(description.to_string(vm)); |
52 | | |
53 | | // 4. Return a new Symbol whose [[Description]] is descString. |
54 | 0 | return Symbol::create(vm, move(description_string), false); |
55 | 0 | } |
56 | | |
57 | | // 20.4.1.1 Symbol ( [ description ] ), https://tc39.es/ecma262/#sec-symbol-description |
58 | | ThrowCompletionOr<NonnullGCPtr<Object>> SymbolConstructor::construct(FunctionObject&) |
59 | 0 | { |
60 | | // 1. If NewTarget is not undefined, throw a TypeError exception. |
61 | 0 | return vm().throw_completion<TypeError>(ErrorType::NotAConstructor, "Symbol"); |
62 | 0 | } |
63 | | |
64 | | // 20.4.2.2 Symbol.for ( key ), https://tc39.es/ecma262/#sec-symbol.for |
65 | | JS_DEFINE_NATIVE_FUNCTION(SymbolConstructor::for_) |
66 | 0 | { |
67 | | // 1. Let stringKey be ? ToString(key). |
68 | 0 | auto string_key = TRY(vm.argument(0).to_string(vm)); |
69 | | |
70 | | // 2. For each element e of the GlobalSymbolRegistry List, do |
71 | 0 | auto result = vm.global_symbol_registry().get(string_key); |
72 | 0 | if (result.has_value()) { |
73 | | // a. If SameValue(e.[[Key]], stringKey) is true, return e.[[Symbol]]. |
74 | 0 | return result.value(); |
75 | 0 | } |
76 | | |
77 | | // 3. Assert: GlobalSymbolRegistry does not currently contain an entry for stringKey. |
78 | 0 | VERIFY(!result.has_value()); |
79 | | |
80 | | // 4. Let newSymbol be a new unique Symbol value whose [[Description]] value is stringKey. |
81 | 0 | auto new_symbol = Symbol::create(vm, string_key, true); |
82 | | |
83 | | // 5. Append the Record { [[Key]]: stringKey, [[Symbol]]: newSymbol } to the GlobalSymbolRegistry List. |
84 | 0 | vm.global_symbol_registry().set(string_key, new_symbol); |
85 | | |
86 | | // 6. Return newSymbol. |
87 | 0 | return new_symbol; |
88 | 0 | } |
89 | | |
90 | | // 20.4.2.6 Symbol.keyFor ( sym ), https://tc39.es/ecma262/#sec-symbol.keyfor |
91 | | JS_DEFINE_NATIVE_FUNCTION(SymbolConstructor::key_for) |
92 | 0 | { |
93 | 0 | auto argument = vm.argument(0); |
94 | | |
95 | | // 1. If sym is not a Symbol, throw a TypeError exception. |
96 | 0 | if (!argument.is_symbol()) |
97 | 0 | return vm.throw_completion<TypeError>(ErrorType::NotASymbol, argument.to_string_without_side_effects()); |
98 | | |
99 | | // 2. Return KeyForSymbol(sym). |
100 | 0 | auto key = argument.as_symbol().key(); |
101 | 0 | return key.has_value() |
102 | 0 | ? PrimitiveString::create(vm, key.release_value()) |
103 | 0 | : js_undefined(); |
104 | 0 | } |
105 | | |
106 | | } |