1use std::rc::Rc;
2
3use crate::parser::ast::{FunctionBodyData, HasMeta, PatternType};
4use crate::runner::ds::env_record::{new_function_environment, EnvironmentRecordType};
5use crate::runner::ds::error::JErrorType;
6use crate::runner::ds::execution_context::{ExecutionContext, ExecutionContextStack};
7use crate::runner::ds::lex_env::JsLexEnvironmentType;
8use crate::runner::ds::object::{JsObject, JsObjectType, ObjectBase};
9use crate::runner::ds::realm::JsCodeRealmType;
10use crate::runner::ds::value::{JsValue, JsValueOrSelf};
11use std::borrow::BorrowMut;
12use std::ptr;
13
14pub enum FunctionKind {
15 Normal,
16 ClassConstructor,
17 Generator,
18}
19
20pub enum ConstructorKind {
21 Base,
22 Derived,
23 None,
24}
25
26pub struct FunctionObjectBase {
27 pub name: String,
28 pub environment: JsLexEnvironmentType,
29 pub formal_parameters: Rc<Vec<PatternType>>,
30 pub body_code: Rc<FunctionBodyData>,
31 pub function_kind: FunctionKind,
32 pub constructor_kind: ConstructorKind,
33 pub is_lexical: bool,
34 pub home_object: Option<JsObjectType>,
35 pub realm: JsCodeRealmType,
36 pub object_base: ObjectBase,
37}
38impl FunctionObjectBase {
39 pub fn new_normal_function(
40 name: String,
41 environment: JsLexEnvironmentType,
42 formal_parameters: Rc<Vec<PatternType>>,
43 body_code: Rc<FunctionBodyData>,
44 home_object: JsObjectType,
45 realm: JsCodeRealmType,
46 ) -> Self {
47 FunctionObjectBase {
48 name,
49 environment,
50 formal_parameters,
51 body_code,
52 home_object: Some(home_object),
53 function_kind: FunctionKind::Normal,
54 constructor_kind: ConstructorKind::Base,
55 is_lexical: false,
56 realm,
57 object_base: ObjectBase::new(),
58 }
59 }
60
61 pub fn new_generator_function(
62 name: String,
63 environment: JsLexEnvironmentType,
64 formal_parameters: Rc<Vec<PatternType>>,
65 body_code: Rc<FunctionBodyData>,
66 home_object: JsObjectType,
67 realm: JsCodeRealmType,
68 ) -> Self {
69 FunctionObjectBase {
70 name,
71 environment,
72 formal_parameters,
73 body_code,
74 home_object: Some(home_object),
75 function_kind: FunctionKind::Generator,
76 constructor_kind: ConstructorKind::None,
77 is_lexical: false,
78 realm,
79 object_base: ObjectBase::new(),
80 }
81 }
82
83 pub fn new_arrow_function(
84 environment: JsLexEnvironmentType,
85 formal_parameters: Rc<Vec<PatternType>>,
86 body_code: Rc<FunctionBodyData>,
87 realm: JsCodeRealmType,
88 ) -> Self {
89 FunctionObjectBase {
90 name: String::new(),
91 environment,
92 formal_parameters,
93 body_code,
94 realm,
95 home_object: None,
96 function_kind: FunctionKind::Normal,
97 constructor_kind: ConstructorKind::None,
98 is_lexical: true,
99 object_base: ObjectBase::new(),
100 }
101 }
102
103 pub fn new_constructor_function(
104 name: String,
105 environment: JsLexEnvironmentType,
106 formal_parameters: Rc<Vec<PatternType>>,
107 body_code: Rc<FunctionBodyData>,
108 home_object: JsObjectType,
109 constructor_kind: ConstructorKind,
110 realm: JsCodeRealmType,
111 ) -> Self {
112 FunctionObjectBase {
113 name,
114 environment,
115 formal_parameters,
116 body_code,
117 home_object: Some(home_object),
118 function_kind: FunctionKind::ClassConstructor,
119 constructor_kind,
120 realm,
121 is_lexical: false,
122 object_base: ObjectBase::new(),
123 }
124 }
125
126 pub fn get_object_base_mut(&mut self) -> &mut ObjectBase {
128 &mut self.object_base
129 }
130
131 pub fn get_object_base(&self) -> &ObjectBase {
132 &self.object_base
133 }
134}
135
136pub trait JsFunctionObject: JsObject {
137 fn get_function_object_base_mut(&mut self) -> &mut FunctionObjectBase;
139
140 fn get_function_object_base(&self) -> &FunctionObjectBase;
141
142 fn as_js_function_object(&self) -> &dyn JsFunctionObject;
143
144 fn as_js_function_object_mut(&mut self) -> &mut dyn JsFunctionObject;
145
146 fn call(
147 &self,
148 fat_self: &JsObjectType,
149 ctx_stack: &mut ExecutionContextStack,
150 _this: JsValueOrSelf,
151 _args: Vec<JsValue>,
152 ) -> Result<JsValue, JErrorType> {
153 debug_assert!(ptr::eq(
154 fat_self.borrow().as_js_object(),
155 self.as_js_object()
156 ));
157
158 if let FunctionKind::ClassConstructor = self.get_function_object_base().function_kind {
159 Err(JErrorType::TypeError(format!(
160 "'{}' is a class constructor",
161 self.get_function_object_base().name
162 )))
163 } else {
164 let _caller_ctx = ctx_stack.get_running_execution_ctx().unwrap();
165
166 todo!()
167 }
168 }
169
170 fn construct(&self, _args: Vec<JsValue>, _o: JsObjectType) -> Result<JsValue, JErrorType> {
171 todo!()
172 }
173}
174
175pub struct BoundFunctionObject {
176 bound_target_function: JsObjectType,
177 bound_this: JsValue,
178 bound_arguments: Vec<JsValue>,
179 function_object: FunctionObjectBase,
180}
181impl JsObject for BoundFunctionObject {
182 fn get_object_base_mut(&mut self) -> &mut ObjectBase {
183 self.function_object.get_object_base_mut()
184 }
185
186 fn get_object_base(&self) -> &ObjectBase {
187 self.function_object.get_object_base()
188 }
189
190 fn as_js_object(&self) -> &dyn JsObject {
191 self
192 }
193
194 fn as_js_object_mut(&mut self) -> &mut dyn JsObject {
195 self
196 }
197
198 fn to_string(&self) -> String {
199 format!(
200 "function [bounded function] ({}) {{ [native code] }}",
201 (*self.get_function_object_base().formal_parameters)
202 .iter()
203 .map(|a| { a.get_meta().to_formatted_code() })
204 .collect::<Vec<String>>()
205 .join(",")
206 )
207 }
208}
209impl JsFunctionObject for BoundFunctionObject {
210 fn get_function_object_base_mut(&mut self) -> &mut FunctionObjectBase {
211 &mut self.function_object
212 }
213
214 fn get_function_object_base(&self) -> &FunctionObjectBase {
215 &self.function_object
216 }
217
218 fn as_js_function_object(&self) -> &dyn JsFunctionObject {
219 self
220 }
221
222 fn as_js_function_object_mut(&mut self) -> &mut dyn JsFunctionObject {
223 self
224 }
225
226 fn call(
227 &self,
228 _fat_self: &JsObjectType,
229 ctx_stack: &mut ExecutionContextStack,
230 _this: JsValueOrSelf,
231 args: Vec<JsValue>,
232 ) -> Result<JsValue, JErrorType> {
233 let mut input_args = args;
234 let mut new_args = self.bound_arguments.clone();
235 new_args.append(&mut input_args);
236 (*self.bound_target_function)
237 .borrow()
238 .as_js_function_object()
239 .call(
240 &self.bound_target_function,
241 ctx_stack,
242 JsValueOrSelf::ValueRef(&self.bound_this),
243 new_args,
244 )
245 }
246
247 fn construct(&self, _args: Vec<JsValue>, _o: JsObjectType) -> Result<JsValue, JErrorType> {
248 todo!()
249 }
250}
251
252pub fn prepare_for_ordinary_call(
253 f: &JsObjectType,
254 new_target: Option<JsObjectType>,
255) -> ExecutionContext {
256 let local_env = new_function_environment(f.clone(), new_target);
257 ExecutionContext {
258 function: Some(f.clone()),
259 realm: (**f)
260 .borrow()
261 .as_js_function_object()
262 .get_function_object_base()
263 .realm
264 .clone(),
265 lex_env: local_env.clone(),
266 var_env: local_env,
267 }
268}
269
270pub fn ordinary_call_bind_this(
271 f: &dyn JsFunctionObject,
272 callee_context: &ExecutionContext,
273 this_argument: JsValue,
274) -> Result<bool, JErrorType> {
275 if !f.get_function_object_base().is_lexical {
276 if let EnvironmentRecordType::Function(ref mut f_env) =
277 (*callee_context.lex_env).borrow_mut().inner.borrow_mut()
278 {
279 return f_env.bind_this_value(this_argument);
280 }
281 }
282 Ok(false)
283}
284
285pub fn function_declaration_instantiation(
297 f: &dyn JsFunctionObject,
298 callee_context: &ExecutionContext,
299 _argument_list: Vec<JsValue>,
300) {
301 let env = &callee_context.lex_env;
302 let _env_rec = env.borrow().inner.as_env_record();
303 let _formals = &f.get_function_object_base().formal_parameters;
304}