Skip to content

Commit

Permalink
Implement spread for objects
Browse files Browse the repository at this point in the history
  • Loading branch information
FrancisMurillo committed Jul 27, 2021
1 parent 8afd50f commit 3edcc91
Show file tree
Hide file tree
Showing 5 changed files with 173 additions and 2 deletions.
20 changes: 20 additions & 0 deletions boa/src/exec/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,26 @@ fn object_field_set() {
assert_eq!(&exec(scenario), "22");
}

#[test]
fn object_spread() {
let mut context = Context::new();

let scenario = r#"
var b = {x: -1, z: -3}
var a = {x: 1, y: 2, ...b};
"#;
forward(&mut context, scenario);

let one = forward(&mut context, "a.x");
assert_eq!(one, String::from("-1"));

let two = forward(&mut context, "a.y");
assert_eq!(two, String::from("2"));

let three = forward(&mut context, "a.z");
assert_eq!(three, String::from("-3"));
}

#[test]
fn spread_with_arguments() {
let scenario = r#"
Expand Down
29 changes: 28 additions & 1 deletion boa/src/syntax/ast/node/object/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,34 @@ impl Executable for Object {
)
}
},
_ => {} //unimplemented!("{:?} type of property", i),
// [spec]: https://tc39.es/ecma262/#sec-runtime-semantics-propertydefinitionevaluation
PropertyDefinition::SpreadObject(node) => {
let val = node.run(context)?;

if val.is_null_or_undefined() {
continue;
}

let from = val.to_object(context)?;

for key in from.__own_property_keys__(context)? {
if let Some(desc) = from.__get_own_property__(&key, context)? {
if let Some(true) = desc.enumerable() {
let property = from.__get__(&key, from.clone().into(), context)?;

obj.set_property(
key.clone(),
PropertyDescriptor::builder()
.value(property)
.writable(true)
.enumerable(true)
.configurable(true),
);
}
}
}
}
_ => {} // unimplemented!("{:?} type of property", i),
}
}

Expand Down
75 changes: 75 additions & 0 deletions boa/src/syntax/ast/node/object/tests.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,78 @@
use crate::exec;

#[test]
fn spread_shallow_clone() {
let scenario = r#"
var a = { x: {} };
var aClone = { ...a };
a.x === aClone.x
"#;
assert_eq!(&exec(scenario), "true");
}

#[test]
fn spread_merge() {
let scenario = r#"
var a = { x: 1, y: 2 };
var b = { x: -1, z: -3, ...a };
(b.x === 1) && (b.y === 2) && (b.z === -3)
"#;
assert_eq!(&exec(scenario), "true");
}

#[test]
fn spread_overriding_properties() {
let scenario = r#"
var a = { x: 0, y: 0 };
var aWithOverrides = { ...a, ...{ x: 1, y: 2 } };
(aWithOverrides.x === 1) && (aWithOverrides.y === 2)
"#;
assert_eq!(&exec(scenario), "true");
}

#[test]
fn spread_getters_in_initializer() {
let scenario = r#"
var a = { x: 42 };
var aWithXGetter = { ...a, get x() { throw new Error('not thrown yet') } };
"#;
assert_eq!(&exec(scenario), "undefined");
}

#[test]
fn spread_getters_in_object() {
let scenario = r#"
var a = { x: 42 };
var aWithXGetter = { ...a, ... { get x() { throw new Error('not thrown yet') } } };
"#;
assert_eq!(&exec(scenario), "\"Error\": \"not thrown yet\"");
}

#[test]
fn spread_setters() {
let scenario = r#"
var z = { set x(nexX) { throw new Error() }, ... { x: 1 } };
"#;
assert_eq!(&exec(scenario), "undefined");
}

#[test]
fn spread_null_and_undefined_ignored() {
let scenario = r#"
var a = { ...null, ...undefined };
var count = 0;
for (key in a) { count++; }
count === 0
"#;

assert_eq!(&exec(scenario), "true");
}

#[test]
fn fmt() {
super::super::test_formatting(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -273,3 +273,24 @@ fn check_object_shorthand_multiple_properties() {
],
);
}

#[test]
fn check_object_spread() {
let object_properties = vec![
PropertyDefinition::property("a", Const::from(1)),
PropertyDefinition::spread_object(Identifier::from("b")),
];

check_parser(
"const x = { a: 1, ...b };
",
vec![DeclarationList::Const(
vec![Declaration::new_with_identifier(
"x",
Some(Object::from(object_properties).into()),
)]
.into(),
)
.into()],
);
}
30 changes: 29 additions & 1 deletion boa/src/syntax/parser/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ use super::Parser;
use crate::syntax::ast::{
node::{
field::GetConstField, ArrowFunctionDecl, Assign, BinOp, Call, Declaration, DeclarationList,
FormalParameter, FunctionDecl, Identifier, If, New, Node, Return, StatementList, UnaryOp,
FormalParameter, FunctionDecl, Identifier, If, New, Node, Object, PropertyDefinition,
Return, StatementList, UnaryOp,
},
op::{self, CompOp, LogOp, NumOp},
Const,
Expand Down Expand Up @@ -299,6 +300,33 @@ fn increment_in_comma_op() {
);
}

#[test]
fn spread_in_object() {
let s = r#"
let x = {
a: 1,
...b,
}
"#;

let object_properties = vec![
PropertyDefinition::property("a", Const::from(1)),
PropertyDefinition::spread_object(Identifier::from("b")),
];

check_parser(
s,
vec![DeclarationList::Let(
vec![Declaration::new_with_identifier::<&str, Option<Node>>(
"x",
Some(Object::from(object_properties).into()),
)]
.into(),
)
.into()],
);
}

#[test]
fn spread_in_arrow_function() {
let s = r#"
Expand Down

0 comments on commit 3edcc91

Please sign in to comment.