/src/serenity/Userland/Libraries/LibJS/Runtime/Reference.h
Line | Count | Source |
1 | | /* |
2 | | * Copyright (c) 2020-2021, Andreas Kling <kling@serenityos.org> |
3 | | * |
4 | | * SPDX-License-Identifier: BSD-2-Clause |
5 | | */ |
6 | | |
7 | | #pragma once |
8 | | |
9 | | #include <LibJS/Runtime/Environment.h> |
10 | | #include <LibJS/Runtime/EnvironmentCoordinate.h> |
11 | | #include <LibJS/Runtime/PropertyKey.h> |
12 | | #include <LibJS/Runtime/Value.h> |
13 | | |
14 | | namespace JS { |
15 | | |
16 | | Reference make_private_reference(VM&, Value base_value, DeprecatedFlyString const& private_identifier); |
17 | | |
18 | | class Reference { |
19 | | public: |
20 | | enum class BaseType : u8 { |
21 | | Unresolvable, |
22 | | Value, |
23 | | Environment, |
24 | | }; |
25 | | |
26 | | Reference() = default; |
27 | | Reference(BaseType type, PropertyKey name, bool strict) |
28 | 0 | : m_base_type(type) |
29 | 0 | , m_name(move(name)) |
30 | 0 | , m_strict(strict) |
31 | 0 | { |
32 | 0 | } |
33 | | |
34 | | Reference(Value base, PropertyKey name, Value this_value, bool strict = false) |
35 | 0 | : m_base_type(BaseType::Value) |
36 | 0 | , m_base_value(base) |
37 | 0 | , m_name(move(name)) |
38 | 0 | , m_this_value(this_value) |
39 | 0 | , m_strict(strict) |
40 | 0 | { |
41 | 0 | } |
42 | | |
43 | | Reference(Environment& base, DeprecatedFlyString referenced_name, bool strict = false, Optional<EnvironmentCoordinate> environment_coordinate = {}) |
44 | 0 | : m_base_type(BaseType::Environment) |
45 | 0 | , m_base_environment(&base) |
46 | 0 | , m_name(move(referenced_name)) |
47 | 0 | , m_strict(strict) |
48 | 0 | , m_environment_coordinate(move(environment_coordinate)) |
49 | 0 | { |
50 | 0 | } |
51 | | |
52 | | Reference(Value base, PrivateName name) |
53 | 0 | : m_base_type(BaseType::Value) |
54 | 0 | , m_base_value(base) |
55 | 0 | , m_this_value(Value {}) |
56 | 0 | , m_strict(true) |
57 | 0 | , m_is_private(true) |
58 | 0 | , m_private_name(move(name)) |
59 | 0 | { |
60 | 0 | } |
61 | | |
62 | | Value base() const |
63 | 0 | { |
64 | 0 | VERIFY(m_base_type == BaseType::Value); |
65 | 0 | return m_base_value; |
66 | 0 | } |
67 | | |
68 | | Environment& base_environment() const |
69 | 0 | { |
70 | 0 | VERIFY(m_base_type == BaseType::Environment); |
71 | 0 | return *m_base_environment; |
72 | 0 | } |
73 | | |
74 | 0 | PropertyKey const& name() const { return m_name; } |
75 | 0 | bool is_strict() const { return m_strict; } |
76 | | |
77 | | // 6.2.4.2 IsUnresolvableReference ( V ), https://tc39.es/ecma262/#sec-isunresolvablereference |
78 | 0 | bool is_unresolvable() const { return m_base_type == BaseType::Unresolvable; } |
79 | | |
80 | | // 6.2.4.1 IsPropertyReference ( V ), https://tc39.es/ecma262/#sec-ispropertyreference |
81 | | bool is_property_reference() const |
82 | 0 | { |
83 | 0 | if (is_unresolvable()) |
84 | 0 | return false; |
85 | 0 | if (m_base_type == BaseType::Environment) |
86 | 0 | return false; |
87 | 0 | return true; |
88 | 0 | } |
89 | | |
90 | | // 6.2.4.7 GetThisValue ( V ), https://tc39.es/ecma262/#sec-getthisvalue |
91 | | Value get_this_value() const |
92 | 0 | { |
93 | 0 | VERIFY(is_property_reference()); |
94 | 0 | if (is_super_reference()) |
95 | 0 | return m_this_value; |
96 | 0 | return m_base_value; |
97 | 0 | } |
98 | | |
99 | | // 6.2.4.3 IsSuperReference ( V ), https://tc39.es/ecma262/#sec-issuperreference |
100 | | bool is_super_reference() const |
101 | 0 | { |
102 | 0 | return !m_this_value.is_empty(); |
103 | 0 | } |
104 | | |
105 | | // 6.2.4.4 IsPrivateReference ( V ), https://tc39.es/ecma262/#sec-isprivatereference |
106 | | bool is_private_reference() const |
107 | 0 | { |
108 | 0 | return m_is_private; |
109 | 0 | } |
110 | | |
111 | | // Note: Non-standard helper. |
112 | | bool is_environment_reference() const |
113 | 0 | { |
114 | 0 | return m_base_type == BaseType::Environment; |
115 | 0 | } |
116 | | |
117 | | ThrowCompletionOr<void> initialize_referenced_binding(VM&, Value value, Environment::InitializeBindingHint hint = Environment::InitializeBindingHint::Normal) const; |
118 | | |
119 | | ThrowCompletionOr<void> put_value(VM&, Value); |
120 | | ThrowCompletionOr<Value> get_value(VM&) const; |
121 | | ThrowCompletionOr<bool> delete_(VM&); |
122 | | |
123 | 0 | bool is_valid_reference() const { return m_name.is_valid() || m_is_private; } |
124 | | |
125 | 0 | Optional<EnvironmentCoordinate> environment_coordinate() const { return m_environment_coordinate; } |
126 | | |
127 | | private: |
128 | | Completion throw_reference_error(VM&) const; |
129 | | |
130 | | BaseType m_base_type { BaseType::Unresolvable }; |
131 | | union { |
132 | | Value m_base_value {}; |
133 | | mutable Environment* m_base_environment; |
134 | | }; |
135 | | PropertyKey m_name; |
136 | | Value m_this_value; |
137 | | bool m_strict { false }; |
138 | | |
139 | | bool m_is_private { false }; |
140 | | // FIXME: This can (probably) be an union with m_name. |
141 | | PrivateName m_private_name; |
142 | | |
143 | | Optional<EnvironmentCoordinate> m_environment_coordinate; |
144 | | }; |
145 | | |
146 | | } |