Skip to content

Commit

Permalink
Merge 2c382c9 into c5b708b
Browse files Browse the repository at this point in the history
  • Loading branch information
HalidOdat committed Aug 15, 2020
2 parents c5b708b + 2c382c9 commit ec33490
Show file tree
Hide file tree
Showing 13 changed files with 284 additions and 544 deletions.
338 changes: 52 additions & 286 deletions boa/src/builtins/function/mod.rs

Large diffs are not rendered by default.

14 changes: 11 additions & 3 deletions boa/src/builtins/map/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -228,10 +228,18 @@ fn recursive_display() {
}

#[test]
#[should_panic]
fn not_a_function() {
let realm = Realm::create();
let mut engine = Interpreter::new(realm);
let init = "let map = Map()";
forward(&mut engine, init);
let init = r"
try {
let map = Map()
} catch(e) {
e.toString()
}
";
assert_eq!(
forward(&mut engine, init),
"\"TypeError: function object is not callable\""
);
}
155 changes: 155 additions & 0 deletions boa/src/builtins/object/gcobject.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,16 @@
//! The `GcObject` is a garbage collected Object.

use super::Object;
use crate::{
builtins::{
function::{create_unmapped_arguments_object, BuiltInFunction, Function},
ResultValue, Value,
},
environment::{
function_environment_record::BindingStatus, lexical_environment::new_function_environment,
},
Executable, Interpreter,
};
use gc::{Finalize, Gc, GcCell, GcCellRef, GcCellRefMut, Trace};
use std::fmt::{self, Display};

Expand Down Expand Up @@ -41,6 +51,151 @@ impl GcObject {
pub fn equals(lhs: &Self, rhs: &Self) -> bool {
std::ptr::eq(lhs.as_ref(), rhs.as_ref())
}

/// This will handle calls for both ordinary and built-in functions
///
/// <https://tc39.es/ecma262/#sec-prepareforordinarycall>
/// <https://tc39.es/ecma262/#sec-ecmascript-function-objects-call-thisargument-argumentslist>
pub fn call(&self, this: &Value, args: &[Value], ctx: &mut Interpreter) -> ResultValue {
let this_function_object = self.clone();
let object = self.borrow();
if let Some(function) = object.as_function() {
if function.is_callable() {
match function {
Function::BuiltIn(BuiltInFunction(function), _) => function(this, args, ctx),
Function::Ordinary {
body,
params,
environment,
flags,
} => {
// Create a new Function environment who's parent is set to the scope of the function declaration (self.environment)
// <https://tc39.es/ecma262/#sec-prepareforordinarycall>
let local_env = new_function_environment(
this_function_object,
if flags.is_lexical_this_mode() {
None
} else {
Some(this.clone())
},
Some(environment.clone()),
// Arrow functions do not have a this binding https://tc39.es/ecma262/#sec-function-environment-records
if flags.is_lexical_this_mode() {
BindingStatus::Lexical
} else {
BindingStatus::Uninitialized
},
);

// Add argument bindings to the function environment
for (i, param) in params.iter().enumerate() {
// Rest Parameters
if param.is_rest_param() {
function.add_rest_param(param, i, args, ctx, &local_env);
break;
}

let value = args.get(i).cloned().unwrap_or_else(Value::undefined);
function.add_arguments_to_environment(param, value, &local_env);
}

// Add arguments object
let arguments_obj = create_unmapped_arguments_object(args);
local_env
.borrow_mut()
.create_mutable_binding("arguments".to_string(), false);
local_env
.borrow_mut()
.initialize_binding("arguments", arguments_obj);

ctx.realm.environment.push(local_env);

// Call body should be set before reaching here
let result = body.run(ctx);

// local_env gets dropped here, its no longer needed
ctx.realm.environment.pop();
result
}
}
} else {
ctx.throw_type_error("function object is not callable")
}
} else {
ctx.throw_type_error("not a function")
}
}

/// <https://tc39.es/ecma262/#sec-ecmascript-function-objects-construct-argumentslist-newtarget>
pub fn construct(&self, this: &Value, args: &[Value], ctx: &mut Interpreter) -> ResultValue {
let this_function_object = self.clone();
let object = self.borrow();
if let Some(function) = object.as_function() {
if function.is_constructable() {
match function {
Function::BuiltIn(BuiltInFunction(function), _) => {
function(this, args, ctx)?;
Ok(this.clone())
}
Function::Ordinary {
body,
params,
environment,
flags,
} => {
// Create a new Function environment who's parent is set to the scope of the function declaration (self.environment)
// <https://tc39.es/ecma262/#sec-prepareforordinarycall>
let local_env = new_function_environment(
this_function_object,
Some(this.clone()),
Some(environment.clone()),
// Arrow functions do not have a this binding https://tc39.es/ecma262/#sec-function-environment-records
if flags.is_lexical_this_mode() {
BindingStatus::Lexical
} else {
BindingStatus::Uninitialized
},
);

// Add argument bindings to the function environment
for (i, param) in params.iter().enumerate() {
// Rest Parameters
if param.is_rest_param() {
function.add_rest_param(param, i, args, ctx, &local_env);
break;
}

let value = args.get(i).cloned().unwrap_or_else(Value::undefined);
function.add_arguments_to_environment(param, value, &local_env);
}

// Add arguments object
let arguments_obj = create_unmapped_arguments_object(args);
local_env
.borrow_mut()
.create_mutable_binding("arguments".to_string(), false);
local_env
.borrow_mut()
.initialize_binding("arguments", arguments_obj);

ctx.realm.environment.push(local_env);

// Call body should be set before reaching here
let _ = body.run(ctx);

// local_env gets dropped here, its no longer needed
let binding = ctx.realm.environment.get_this_binding();
Ok(binding)
}
}
} else {
let name = this.get_field("name").display().to_string();
ctx.throw_type_error(format!("{} is not a constructor", name))
}
} else {
ctx.throw_type_error("not a function")
}
}
}

impl AsRef<GcCell<Object>> for GcObject {
Expand Down
64 changes: 0 additions & 64 deletions boa/src/builtins/object/internal_state.rs

This file was deleted.

30 changes: 4 additions & 26 deletions boa/src/builtins/object/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,23 +30,19 @@ use std::fmt::{Debug, Display, Error, Formatter};

use super::function::{make_builtin_fn, make_constructor_fn};
use crate::builtins::value::same_value;
pub use internal_state::{InternalState, InternalStateCell};

pub mod gcobject;
pub mod internal_methods;
mod internal_state;
mod gcobject;
mod internal_methods;

pub use gcobject::GcObject;
pub use internal_methods::*;

#[cfg(test)]
mod tests;

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

// /// Static `__proto__`, usually set on Object instances as a key to point to their respective prototype object.
// pub static INSTANCE_PROTOTYPE: &str = "__proto__";

/// The internal representation of an JavaScript object.
#[derive(Debug, Trace, Finalize, Clone)]
pub struct Object {
Expand All @@ -58,8 +54,6 @@ pub struct Object {
symbol_properties: FxHashMap<u32, Property>,
/// Instance prototype `__proto__`.
prototype: Value,
/// Some rust object that stores internal state
state: Option<InternalStateCell>,
/// Whether it can have new properties added to it.
extensible: bool,
}
Expand All @@ -69,7 +63,7 @@ pub struct Object {
pub enum ObjectData {
Array,
Map(OrderedMap<Value, Value>),
RegExp(RegExp),
RegExp(Box<RegExp>),
BigInt(RcBigInt),
Boolean(bool),
Function(Function),
Expand Down Expand Up @@ -115,7 +109,6 @@ impl Default for Object {
properties: FxHashMap::default(),
symbol_properties: FxHashMap::default(),
prototype: Value::null(),
state: None,
extensible: true,
}
}
Expand All @@ -136,7 +129,6 @@ impl Object {
properties: FxHashMap::default(),
symbol_properties: FxHashMap::default(),
prototype,
state: None,
extensible: true,
}
}
Expand All @@ -161,7 +153,6 @@ impl Object {
properties: FxHashMap::default(),
symbol_properties: FxHashMap::default(),
prototype: Value::null(),
state: None,
extensible: true,
}
}
Expand All @@ -173,7 +164,6 @@ impl Object {
properties: FxHashMap::default(),
symbol_properties: FxHashMap::default(),
prototype: Value::null(),
state: None,
extensible: true,
}
}
Expand All @@ -188,7 +178,6 @@ impl Object {
properties: FxHashMap::default(),
symbol_properties: FxHashMap::default(),
prototype: Value::null(),
state: None,
extensible: true,
}
}
Expand All @@ -200,7 +189,6 @@ impl Object {
properties: FxHashMap::default(),
symbol_properties: FxHashMap::default(),
prototype: Value::null(),
state: None,
extensible: true,
}
}
Expand Down Expand Up @@ -419,16 +407,6 @@ impl Object {
&mut self.symbol_properties
}

#[inline]
pub fn state(&self) -> &Option<InternalStateCell> {
&self.state
}

#[inline]
pub fn state_mut(&mut self) -> &mut Option<InternalStateCell> {
&mut self.state
}

pub fn prototype(&self) -> &Value {
&self.prototype
}
Expand Down
6 changes: 2 additions & 4 deletions boa/src/builtins/regexp/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ use regex::Regex;
use super::function::{make_builtin_fn, make_constructor_fn};
use crate::{
builtins::{
object::{InternalState, ObjectData},
object::ObjectData,
property::Property,
value::{RcString, ResultValue, Value},
},
Expand Down Expand Up @@ -64,8 +64,6 @@ unsafe impl Trace for RegExp {
unsafe_empty_trace!();
}

impl InternalState for RegExp {}

impl RegExp {
/// The name of the object.
pub(crate) const NAME: &'static str = "RegExp";
Expand Down Expand Up @@ -156,7 +154,7 @@ impl RegExp {
original_flags: regex_flags,
};

this.set_data(ObjectData::RegExp(regexp));
this.set_data(ObjectData::RegExp(Box::new(regexp)));

Ok(this.clone())
}
Expand Down

0 comments on commit ec33490

Please sign in to comment.