Browse Source

Implement spread for objects (#1364)

* Implement spread for objects

* Use copy_data_properties for object spread

* Use check_output for object spread test
pull/1536/head
Francis Murillo 3 years ago committed by GitHub
parent
commit
22d0c37b2d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 15
      boa/src/exec/tests.rs
  2. 16
      boa/src/syntax/ast/node/object/mod.rs
  3. 75
      boa/src/syntax/ast/node/object/tests.rs
  4. 21
      boa/src/syntax/parser/expression/primary/object_initializer/tests.rs
  5. 30
      boa/src/syntax/parser/tests.rs

15
boa/src/exec/tests.rs

@ -118,6 +118,21 @@ fn object_field_set() {
assert_eq!(&exec(scenario), "22"); assert_eq!(&exec(scenario), "22");
} }
#[test]
fn object_spread() {
let scenario = r#"
var b = {x: -1, z: -3}
var a = {x: 1, y: 2, ...b};
"#;
check_output(&[
TestAction::Execute(scenario),
TestAction::TestEq("a.x", "-1"),
TestAction::TestEq("a.y", "2"),
TestAction::TestEq("a.z", "-3"),
]);
}
#[test] #[test]
fn spread_with_arguments() { fn spread_with_arguments() {
let scenario = r#" let scenario = r#"

16
boa/src/syntax/ast/node/object/mod.rs

@ -161,7 +161,21 @@ 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;
}
obj.as_object().unwrap().copy_data_properties::<String>(
&val,
vec![],
context,
)?;
}
_ => {} // unimplemented!("{:?} type of property", i),
} }
} }

75
boa/src/syntax/ast/node/object/tests.rs

@ -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] #[test]
fn fmt() { fn fmt() {
super::super::test_formatting( super::super::test_formatting(

21
boa/src/syntax/parser/expression/primary/object_initializer/tests.rs

@ -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
boa/src/syntax/parser/tests.rs

@ -4,7 +4,8 @@ use super::Parser;
use crate::syntax::ast::{ use crate::syntax::ast::{
node::{ node::{
field::GetConstField, ArrowFunctionDecl, Assign, BinOp, Call, Declaration, DeclarationList, 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}, op::{self, CompOp, LogOp, NumOp},
Const, Const,
@ -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] #[test]
fn spread_in_arrow_function() { fn spread_in_arrow_function() {
let s = r#" let s = r#"

Loading…
Cancel
Save