1use gc::Gc;
12
13use crate::{
14 environment::{
15 declarative_environment_record::DeclarativeEnvironmentRecord,
16 environment_record_trait::EnvironmentRecordTrait,
17 lexical_environment::{Environment, EnvironmentType, VariableScope},
18 },
19 gc::{empty_trace, Finalize, Trace},
20 object::JsObject,
21 Context, JsResult, JsValue,
22};
23
24#[derive(Copy, Finalize, Debug, Clone)]
27pub enum BindingStatus {
28 Lexical,
30 Initialized,
32 Uninitialized,
34}
35
36unsafe impl Trace for BindingStatus {
37 empty_trace!();
38}
39
40#[derive(Debug, Trace, Finalize, Clone)]
42pub struct FunctionEnvironmentRecord {
43 pub declarative_record: DeclarativeEnvironmentRecord,
44 pub this_value: JsValue,
46 pub this_binding_status: BindingStatus,
48 pub function: JsObject,
50 pub home_object: JsValue,
54 pub new_target: JsValue,
58}
59
60impl FunctionEnvironmentRecord {
61 pub fn new(
62 f: JsObject,
63 this: Option<JsValue>,
64 outer: Option<Environment>,
65 binding_status: BindingStatus,
66 new_target: JsValue,
67 context: &mut Context,
68 ) -> JsResult<FunctionEnvironmentRecord> {
69 let mut func_env = FunctionEnvironmentRecord {
70 declarative_record: DeclarativeEnvironmentRecord::new(outer), function: f,
72 this_binding_status: binding_status,
73 home_object: JsValue::undefined(),
74 new_target,
75 this_value: JsValue::undefined(),
76 };
77 if let Some(v) = this {
79 func_env.bind_this_value(v, context)?;
80 }
81 Ok(func_env)
82 }
83
84 pub fn bind_this_value(&mut self, value: JsValue, context: &mut Context) -> JsResult<JsValue> {
91 match self.this_binding_status {
92 BindingStatus::Lexical => {
94 panic!("Cannot bind to an arrow function!");
95 }
96 BindingStatus::Initialized => {
98 context.throw_reference_error("Cannot bind to an initialized function!")
99 }
100 BindingStatus::Uninitialized => {
101 self.this_value = value.clone();
103 self.this_binding_status = BindingStatus::Initialized;
105 Ok(value)
107 }
108 }
109 }
110
111 pub fn get_super_base(&self) -> JsValue {
118 let home = &self.home_object;
120
121 if home.is_undefined() {
123 JsValue::undefined()
124 } else {
125 assert!(home.is_object());
127
128 home.as_object()
130 .expect("home_object must be an Object")
131 .prototype_instance()
132 }
133 }
134}
135
136impl EnvironmentRecordTrait for FunctionEnvironmentRecord {
137 fn has_binding(&self, name: &str, context: &mut Context) -> JsResult<bool> {
138 self.declarative_record.has_binding(name, context)
139 }
140
141 fn create_mutable_binding(
142 &self,
143 name: &str,
144 deletion: bool,
145 allow_name_reuse: bool,
146 context: &mut Context,
147 ) -> JsResult<()> {
148 self.declarative_record
149 .create_mutable_binding(name, deletion, allow_name_reuse, context)
150 }
151
152 fn create_immutable_binding(
153 &self,
154 name: &str,
155 strict: bool,
156 context: &mut Context,
157 ) -> JsResult<()> {
158 self.declarative_record
159 .create_immutable_binding(name, strict, context)
160 }
161
162 fn initialize_binding(
163 &self,
164 name: &str,
165 value: JsValue,
166 context: &mut Context,
167 ) -> JsResult<()> {
168 self.declarative_record
169 .initialize_binding(name, value, context)
170 }
171
172 fn set_mutable_binding(
173 &self,
174 name: &str,
175 value: JsValue,
176 strict: bool,
177 context: &mut Context,
178 ) -> JsResult<()> {
179 self.declarative_record
180 .set_mutable_binding(name, value, strict, context)
181 }
182
183 fn get_binding_value(
184 &self,
185 name: &str,
186 strict: bool,
187 context: &mut Context,
188 ) -> JsResult<JsValue> {
189 self.declarative_record
190 .get_binding_value(name, strict, context)
191 }
192
193 fn delete_binding(&self, name: &str, context: &mut Context) -> JsResult<bool> {
194 self.declarative_record.delete_binding(name, context)
195 }
196
197 fn has_this_binding(&self) -> bool {
204 !matches!(self.this_binding_status, BindingStatus::Lexical)
206 }
207
208 fn has_super_binding(&self) -> bool {
215 if let BindingStatus::Lexical = self.this_binding_status {
218 false
219 } else {
220 !self.home_object.is_undefined()
221 }
222 }
223
224 fn get_this_binding(&self, context: &mut Context) -> JsResult<JsValue> {
231 match self.this_binding_status {
232 BindingStatus::Lexical => {
234 panic!("There is no this for a lexical function record");
235 }
236 BindingStatus::Uninitialized => {
238 context.throw_reference_error("Uninitialized binding for this function")
239 }
240 BindingStatus::Initialized => Ok(self.this_value.clone()),
242 }
243 }
244
245 fn with_base_object(&self) -> Option<JsObject> {
246 None
247 }
248
249 fn get_outer_environment_ref(&self) -> Option<&Environment> {
250 self.declarative_record.get_outer_environment_ref()
251 }
252
253 fn set_outer_environment(&mut self, env: Environment) {
254 self.declarative_record.set_outer_environment(env)
255 }
256
257 fn get_environment_type(&self) -> EnvironmentType {
258 EnvironmentType::Function
259 }
260
261 fn recursive_create_mutable_binding(
262 &self,
263 name: &str,
264 deletion: bool,
265 _scope: VariableScope,
266 context: &mut Context,
267 ) -> JsResult<()> {
268 self.create_mutable_binding(name, deletion, false, context)
269 }
270
271 fn recursive_create_immutable_binding(
272 &self,
273 name: &str,
274 deletion: bool,
275 _scope: VariableScope,
276 context: &mut Context,
277 ) -> JsResult<()> {
278 self.create_immutable_binding(name, deletion, context)
279 }
280}
281
282impl From<FunctionEnvironmentRecord> for Environment {
283 fn from(env: FunctionEnvironmentRecord) -> Environment {
284 Gc::new(Box::new(env))
285 }
286}