Skip to main content

just_engine/runner/ds/
function_object.rs

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    //noinspection RsSelfConvention
127    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    //noinspection RsSelfConvention
138    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
285///
286/// When an execution context is established for evaluating an ECMAScript function a new
287/// function Environment Record is created and bindings for each formal parameter are instantiated
288/// in that Environment Record. Each declaration in the function body is also instantiated. If the
289/// function’s formal parameters do not include any default value initializers then the body
290/// declarations are instantiated in the same Environment Record as the parameters. If default
291/// value parameter initializers exist, a second Environment Record is created for the body
292/// declarations. Formal parameters and functions are initialized as part of
293/// function_declaration_instantiation. All other bindings are initialized during evaluation of the
294/// function body.
295///
296pub 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}