Skip to content

Commit 2c14dca

Browse files
committed
Refactor Function
- Added call to js object - Removed Function::call - Removed `Function::construct` and added `GcObject::construct` - Made Function an enum - Made the Function into an enum - Removed `InternalState` - Removed `internal_state.rs` file
1 parent d025207 commit 2c14dca

File tree

13 files changed

+288
-554
lines changed

13 files changed

+288
-554
lines changed

boa/src/builtins/function/mod.rs

+53-287
Large diffs are not rendered by default.

boa/src/builtins/map/tests.rs

+11-3
Original file line numberDiff line numberDiff line change
@@ -228,10 +228,18 @@ fn recursive_display() {
228228
}
229229

230230
#[test]
231-
#[should_panic]
232231
fn not_a_function() {
233232
let realm = Realm::create();
234233
let mut engine = Interpreter::new(realm);
235-
let init = "let map = Map()";
236-
forward(&mut engine, init);
234+
let init = r"
235+
try {
236+
let map = Map()
237+
} catch(e) {
238+
e.toString()
239+
}
240+
";
241+
assert_eq!(
242+
forward(&mut engine, init),
243+
"\"TypeError: function object is not callable\""
244+
);
237245
}

boa/src/builtins/object/gcobject.rs

+158-2
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,18 @@
33
//! The `GcObject` is a garbage collected Object.
44
55
use super::Object;
6+
use crate::{
7+
builtins::{
8+
function::{create_unmapped_arguments_object, BuiltInFunction, Function},
9+
Value,
10+
},
11+
environment::{
12+
function_environment_record::BindingStatus, lexical_environment::new_function_environment,
13+
},
14+
Executable, Interpreter, Result,
15+
};
616
use gc::{Finalize, Gc, GcCell, GcCellRef, GcCellRefMut, Trace};
17+
use std::result::Result as StdResult;
718
use std::{
819
cell::RefCell,
920
collections::HashSet,
@@ -31,12 +42,12 @@ impl GcObject {
3142
}
3243

3344
#[inline]
34-
pub fn try_borrow(&self) -> Result<GcCellRef<'_, Object>, BorrowError> {
45+
pub fn try_borrow(&self) -> StdResult<GcCellRef<'_, Object>, BorrowError> {
3546
self.0.try_borrow().map_err(|_| BorrowError)
3647
}
3748

3849
#[inline]
39-
pub fn try_borrow_mut(&self) -> Result<GcCellRefMut<'_, Object>, BorrowMutError> {
50+
pub fn try_borrow_mut(&self) -> StdResult<GcCellRefMut<'_, Object>, BorrowMutError> {
4051
self.0.try_borrow_mut().map_err(|_| BorrowMutError)
4152
}
4253

@@ -45,6 +56,151 @@ impl GcObject {
4556
pub fn equals(lhs: &Self, rhs: &Self) -> bool {
4657
std::ptr::eq(lhs.as_ref(), rhs.as_ref())
4758
}
59+
60+
/// This will handle calls for both ordinary and built-in functions
61+
///
62+
/// <https://tc39.es/ecma262/#sec-prepareforordinarycall>
63+
/// <https://tc39.es/ecma262/#sec-ecmascript-function-objects-call-thisargument-argumentslist>
64+
pub fn call(&self, this: &Value, args: &[Value], ctx: &mut Interpreter) -> Result<Value> {
65+
let this_function_object = self.clone();
66+
let object = self.borrow();
67+
if let Some(function) = object.as_function() {
68+
if function.is_callable() {
69+
match function {
70+
Function::BuiltIn(BuiltInFunction(function), _) => function(this, args, ctx),
71+
Function::Ordinary {
72+
body,
73+
params,
74+
environment,
75+
flags,
76+
} => {
77+
// Create a new Function environment who's parent is set to the scope of the function declaration (self.environment)
78+
// <https://tc39.es/ecma262/#sec-prepareforordinarycall>
79+
let local_env = new_function_environment(
80+
this_function_object,
81+
if flags.is_lexical_this_mode() {
82+
None
83+
} else {
84+
Some(this.clone())
85+
},
86+
Some(environment.clone()),
87+
// Arrow functions do not have a this binding https://tc39.es/ecma262/#sec-function-environment-records
88+
if flags.is_lexical_this_mode() {
89+
BindingStatus::Lexical
90+
} else {
91+
BindingStatus::Uninitialized
92+
},
93+
);
94+
95+
// Add argument bindings to the function environment
96+
for (i, param) in params.iter().enumerate() {
97+
// Rest Parameters
98+
if param.is_rest_param() {
99+
function.add_rest_param(param, i, args, ctx, &local_env);
100+
break;
101+
}
102+
103+
let value = args.get(i).cloned().unwrap_or_else(Value::undefined);
104+
function.add_arguments_to_environment(param, value, &local_env);
105+
}
106+
107+
// Add arguments object
108+
let arguments_obj = create_unmapped_arguments_object(args);
109+
local_env
110+
.borrow_mut()
111+
.create_mutable_binding("arguments".to_string(), false);
112+
local_env
113+
.borrow_mut()
114+
.initialize_binding("arguments", arguments_obj);
115+
116+
ctx.realm.environment.push(local_env);
117+
118+
// Call body should be set before reaching here
119+
let result = body.run(ctx);
120+
121+
// local_env gets dropped here, its no longer needed
122+
ctx.realm.environment.pop();
123+
result
124+
}
125+
}
126+
} else {
127+
ctx.throw_type_error("function object is not callable")
128+
}
129+
} else {
130+
ctx.throw_type_error("not a function")
131+
}
132+
}
133+
134+
/// <https://tc39.es/ecma262/#sec-ecmascript-function-objects-construct-argumentslist-newtarget>
135+
pub fn construct(&self, this: &Value, args: &[Value], ctx: &mut Interpreter) -> Result<Value> {
136+
let this_function_object = self.clone();
137+
let object = self.borrow();
138+
if let Some(function) = object.as_function() {
139+
if function.is_constructable() {
140+
match function {
141+
Function::BuiltIn(BuiltInFunction(function), _) => {
142+
function(this, args, ctx)?;
143+
Ok(this.clone())
144+
}
145+
Function::Ordinary {
146+
body,
147+
params,
148+
environment,
149+
flags,
150+
} => {
151+
// Create a new Function environment who's parent is set to the scope of the function declaration (self.environment)
152+
// <https://tc39.es/ecma262/#sec-prepareforordinarycall>
153+
let local_env = new_function_environment(
154+
this_function_object,
155+
Some(this.clone()),
156+
Some(environment.clone()),
157+
// Arrow functions do not have a this binding https://tc39.es/ecma262/#sec-function-environment-records
158+
if flags.is_lexical_this_mode() {
159+
BindingStatus::Lexical
160+
} else {
161+
BindingStatus::Uninitialized
162+
},
163+
);
164+
165+
// Add argument bindings to the function environment
166+
for (i, param) in params.iter().enumerate() {
167+
// Rest Parameters
168+
if param.is_rest_param() {
169+
function.add_rest_param(param, i, args, ctx, &local_env);
170+
break;
171+
}
172+
173+
let value = args.get(i).cloned().unwrap_or_else(Value::undefined);
174+
function.add_arguments_to_environment(param, value, &local_env);
175+
}
176+
177+
// Add arguments object
178+
let arguments_obj = create_unmapped_arguments_object(args);
179+
local_env
180+
.borrow_mut()
181+
.create_mutable_binding("arguments".to_string(), false);
182+
local_env
183+
.borrow_mut()
184+
.initialize_binding("arguments", arguments_obj);
185+
186+
ctx.realm.environment.push(local_env);
187+
188+
// Call body should be set before reaching here
189+
let _ = body.run(ctx);
190+
191+
// local_env gets dropped here, its no longer needed
192+
let binding = ctx.realm.environment.get_this_binding();
193+
Ok(binding)
194+
}
195+
}
196+
} else {
197+
let name = this.get_field("name").display().to_string();
198+
ctx.throw_type_error(format!("{} is not a constructor", name))
199+
}
200+
} else {
201+
ctx.throw_type_error("not a function")
202+
}
203+
}
48204
}
49205

50206
impl AsRef<GcCell<Object>> for GcObject {

boa/src/builtins/object/internal_state.rs

-64
This file was deleted.

boa/src/builtins/object/mod.rs

+4-26
Original file line numberDiff line numberDiff line change
@@ -31,23 +31,19 @@ use std::result::Result as StdResult;
3131

3232
use super::function::{make_builtin_fn, make_constructor_fn};
3333
use crate::builtins::value::same_value;
34-
pub use internal_state::{InternalState, InternalStateCell};
3534

36-
pub mod gcobject;
37-
pub mod internal_methods;
38-
mod internal_state;
35+
mod gcobject;
36+
mod internal_methods;
3937

4038
pub use gcobject::GcObject;
39+
pub use internal_methods::*;
4140

4241
#[cfg(test)]
4342
mod tests;
4443

4544
/// Static `prototype`, usually set on constructors as a key to point to their respective prototype object.
4645
pub static PROTOTYPE: &str = "prototype";
4746

48-
// /// Static `__proto__`, usually set on Object instances as a key to point to their respective prototype object.
49-
// pub static INSTANCE_PROTOTYPE: &str = "__proto__";
50-
5147
/// The internal representation of an JavaScript object.
5248
#[derive(Debug, Trace, Finalize, Clone)]
5349
pub struct Object {
@@ -59,8 +55,6 @@ pub struct Object {
5955
symbol_properties: FxHashMap<u32, Property>,
6056
/// Instance prototype `__proto__`.
6157
prototype: Value,
62-
/// Some rust object that stores internal state
63-
state: Option<InternalStateCell>,
6458
/// Whether it can have new properties added to it.
6559
extensible: bool,
6660
}
@@ -70,7 +64,7 @@ pub struct Object {
7064
pub enum ObjectData {
7165
Array,
7266
Map(OrderedMap<Value, Value>),
73-
RegExp(RegExp),
67+
RegExp(Box<RegExp>),
7468
BigInt(RcBigInt),
7569
Boolean(bool),
7670
Function(Function),
@@ -116,7 +110,6 @@ impl Default for Object {
116110
properties: FxHashMap::default(),
117111
symbol_properties: FxHashMap::default(),
118112
prototype: Value::null(),
119-
state: None,
120113
extensible: true,
121114
}
122115
}
@@ -137,7 +130,6 @@ impl Object {
137130
properties: FxHashMap::default(),
138131
symbol_properties: FxHashMap::default(),
139132
prototype,
140-
state: None,
141133
extensible: true,
142134
}
143135
}
@@ -162,7 +154,6 @@ impl Object {
162154
properties: FxHashMap::default(),
163155
symbol_properties: FxHashMap::default(),
164156
prototype: Value::null(),
165-
state: None,
166157
extensible: true,
167158
}
168159
}
@@ -174,7 +165,6 @@ impl Object {
174165
properties: FxHashMap::default(),
175166
symbol_properties: FxHashMap::default(),
176167
prototype: Value::null(),
177-
state: None,
178168
extensible: true,
179169
}
180170
}
@@ -189,7 +179,6 @@ impl Object {
189179
properties: FxHashMap::default(),
190180
symbol_properties: FxHashMap::default(),
191181
prototype: Value::null(),
192-
state: None,
193182
extensible: true,
194183
}
195184
}
@@ -201,7 +190,6 @@ impl Object {
201190
properties: FxHashMap::default(),
202191
symbol_properties: FxHashMap::default(),
203192
prototype: Value::null(),
204-
state: None,
205193
extensible: true,
206194
}
207195
}
@@ -420,16 +408,6 @@ impl Object {
420408
&mut self.symbol_properties
421409
}
422410

423-
#[inline]
424-
pub fn state(&self) -> &Option<InternalStateCell> {
425-
&self.state
426-
}
427-
428-
#[inline]
429-
pub fn state_mut(&mut self) -> &mut Option<InternalStateCell> {
430-
&mut self.state
431-
}
432-
433411
pub fn prototype(&self) -> &Value {
434412
&self.prototype
435413
}

0 commit comments

Comments
 (0)