From 7ffc0c8abd8ae04cbfdfbe985d2bc2685acd3461 Mon Sep 17 00:00:00 2001 From: Paul Lancaster Date: Tue, 26 May 2020 14:03:49 +0100 Subject: [PATCH 01/42] Adding Object Execution trait --- boa/src/exec/mod.rs | 32 ++--------------------- boa/src/exec/object/mod.rs | 42 +++++++++++++++++++++++++++++++ boa/src/syntax/ast/node/mod.rs | 24 +++--------------- boa/src/syntax/ast/node/object.rs | 37 +++++++++++++++++++++++++++ 4 files changed, 85 insertions(+), 50 deletions(-) create mode 100644 boa/src/exec/object/mod.rs create mode 100644 boa/src/syntax/ast/node/object.rs diff --git a/boa/src/exec/mod.rs b/boa/src/exec/mod.rs index f7db20501c2..2b296c52055 100644 --- a/boa/src/exec/mod.rs +++ b/boa/src/exec/mod.rs @@ -5,6 +5,7 @@ mod block; mod declaration; mod expression; mod iteration; +mod object; mod operator; mod statement_list; #[cfg(test)] @@ -447,36 +448,7 @@ impl Executable for Node { } Ok(result) } - Node::Object(ref properties) => { - let global_val = &interpreter - .realm() - .environment - .get_global_object() - .expect("Could not get the global object"); - let obj = Value::new_object(Some(global_val)); - - // TODO: Implement the rest of the property types. - for property in properties.iter() { - match property { - PropertyDefinition::Property(key, value) => { - obj.borrow() - .set_field(&key.clone(), value.run(interpreter)?); - } - PropertyDefinition::MethodDefinition(kind, name, func) => { - if let MethodDefinitionKind::Ordinary = kind { - obj.borrow() - .set_field(&name.clone(), func.run(interpreter)?); - } else { - // TODO: Implement other types of MethodDefinitionKinds. - unimplemented!("other types of property method definitions."); - } - } - i => unimplemented!("{:?} type of property", i), - } - } - - Ok(obj) - } + Node::Object(ref obj) => obj.run(interpreter), Node::ArrayDecl(ref arr) => arr.run(interpreter), // Node::FunctionDecl(ref decl) => decl.run(interpreter), diff --git a/boa/src/exec/object/mod.rs b/boa/src/exec/object/mod.rs new file mode 100644 index 00000000000..a8d53f4db54 --- /dev/null +++ b/boa/src/exec/object/mod.rs @@ -0,0 +1,42 @@ +//! Object execution. + +use super::{Executable, Interpreter}; +use crate::{ + builtins::V + builtins::value::ResultValue, + environment::lexical_environment::{new_declarative_environment, VariableScope}, + syntax::ast::node::{Object, PropertyDefinition}, +}; + +impl Executable for Object { + fn run(&self, interpreter: &mut Interpreter) -> ResultValue { + let global_val = &interpreter + .realm() + .environment + .get_global_object() + .expect("Could not get the global object"); + let obj = Value::new_object(Some(global_val)); + + // TODO: Implement the rest of the property types. + for property in properties.iter() { + match property { + PropertyDefinition::Property(key, value) => { + obj.borrow() + .set_field(&key.clone(), value.run(interpreter)?); + } + PropertyDefinition::MethodDefinition(kind, name, func) => { + if let MethodDefinitionKind::Ordinary = kind { + obj.borrow() + .set_field(&name.clone(), func.run(interpreter)?); + } else { + // TODO: Implement other types of MethodDefinitionKinds. + unimplemented!("other types of property method definitions."); + } + } + i => unimplemented!("{:?} type of property", i), + } + } + + Ok(obj) + } +} \ No newline at end of file diff --git a/boa/src/syntax/ast/node/mod.rs b/boa/src/syntax/ast/node/mod.rs index 536685ddf1b..2e4c5d63705 100644 --- a/boa/src/syntax/ast/node/mod.rs +++ b/boa/src/syntax/ast/node/mod.rs @@ -9,6 +9,7 @@ pub mod iteration; pub mod operator; pub mod statement_list; pub mod try_node; +pub mod object; pub use self::{ array::ArrayDecl, @@ -23,6 +24,7 @@ pub use self::{ operator::{Assign, BinOp, UnaryOp}, statement_list::StatementList, try_node::{Catch, Finally, Try}, + object::Object }; use super::Const; use gc::{Finalize, Trace}; @@ -214,26 +216,8 @@ pub enum Node { /// A `new` expression. [More information](./expression/struct.New.html). New(New), - /// Objects in JavaScript may be defined as an unordered collection of related data, of - /// primitive or reference types, in the form of “key: value” pairs. - /// - /// Objects can be initialized using `new Object()`, `Object.create()`, or using the literal - /// notation. - /// - /// An object initializer is an expression that describes the initialization of an - /// [`Object`][object]. Objects consist of properties, which are used to describe an object. - /// Values of object properties can either contain [`primitive`][primitive] data types or other - /// objects. - /// - /// More information: - /// - [ECMAScript reference][spec] - /// - [MDN documentation][mdn] - /// - /// [spec]: https://tc39.es/ecma262/#prod-ObjectLiteral - /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Object_initializer - /// [object]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object - /// [primitive]: https://developer.mozilla.org/en-US/docs/Glossary/primitive - Object(Box<[PropertyDefinition]>), + /// An object. [More information](./object/struct.Object.html). + Object(Object), /// The `return` statement ends function execution and specifies a value to be returned to the /// function caller. diff --git a/boa/src/syntax/ast/node/object.rs b/boa/src/syntax/ast/node/object.rs new file mode 100644 index 00000000000..0c36953b957 --- /dev/null +++ b/boa/src/syntax/ast/node/object.rs @@ -0,0 +1,37 @@ +//! Object node. + +use super::Node; +use gc::{Finalize, Trace}; +use std::fmt; + +use crate::syntax::ast::node::PropertyDefinition; + +#[cfg(feature = "serde")] +use serde::{Deserialize, Serialize}; + +/// Objects in JavaScript may be defined as an unordered collection of related data, of +/// primitive or reference types, in the form of “key: value” pairs. +/// +/// Objects can be initialized using `new Object()`, `Object.create()`, or using the literal +/// notation. +/// +/// An object initializer is an expression that describes the initialization of an +/// [`Object`][object]. Objects consist of properties, which are used to describe an object. +/// Values of object properties can either contain [`primitive`][primitive] data types or other +/// objects. +/// +/// More information: +/// - [ECMAScript reference][spec] +/// - [MDN documentation][mdn] +/// +/// [spec]: https://tc39.es/ecma262/#prod-ObjectLiteral +/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Object_initializer +/// [object]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object +/// [primitive]: https://developer.mozilla.org/en-US/docs/Glossary/primitive + +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +#[cfg_attr(feature = "serde", serde(transparent))] +#[derive(Clone, Debug, Trace, Finalize, PartialEq)] +pub struct Object { + properties: Box<[PropertyDefinition]> +} \ No newline at end of file From 57fa83d13a25eba9e17f9c71a4d7537a01a93e1c Mon Sep 17 00:00:00 2001 From: Paul Lancaster Date: Tue, 26 May 2020 18:10:34 +0100 Subject: [PATCH 02/42] Moved Object AST related parts into their own files --- boa/src/exec/object/mod.rs | 10 ++-- boa/src/syntax/ast/node/mod.rs | 30 +---------- boa/src/syntax/ast/node/object.rs | 51 +++++++++++++++++++ .../primary/object_initializer/mod.rs | 4 +- .../primary/object_initializer/tests.rs | 12 ++--- 5 files changed, 67 insertions(+), 40 deletions(-) diff --git a/boa/src/exec/object/mod.rs b/boa/src/exec/object/mod.rs index a8d53f4db54..164aef52cd8 100644 --- a/boa/src/exec/object/mod.rs +++ b/boa/src/exec/object/mod.rs @@ -2,12 +2,16 @@ use super::{Executable, Interpreter}; use crate::{ - builtins::V - builtins::value::ResultValue, + builtins::value::{Value, ResultValue}, environment::lexical_environment::{new_declarative_environment, VariableScope}, syntax::ast::node::{Object, PropertyDefinition}, + syntax::ast::node::MethodDefinitionKind, }; + + +use std::borrow::Borrow; + impl Executable for Object { fn run(&self, interpreter: &mut Interpreter) -> ResultValue { let global_val = &interpreter @@ -18,7 +22,7 @@ impl Executable for Object { let obj = Value::new_object(Some(global_val)); // TODO: Implement the rest of the property types. - for property in properties.iter() { + for property in self.properties().iter() { match property { PropertyDefinition::Property(key, value) => { obj.borrow() diff --git a/boa/src/syntax/ast/node/mod.rs b/boa/src/syntax/ast/node/mod.rs index 2e4c5d63705..7333f597aa5 100644 --- a/boa/src/syntax/ast/node/mod.rs +++ b/boa/src/syntax/ast/node/mod.rs @@ -426,14 +426,6 @@ impl Node { ) } - /// Creates an `Object` AST node. - pub fn object(def: D) -> Self - where - D: Into>, - { - Self::Object(def.into()) - } - /// Creates a `Return` AST node. pub fn return_node(expr: OE) -> Self where @@ -566,27 +558,7 @@ impl Node { def.display(f, indentation + 1)?; write!(f, "{}}}", indent) } - Self::Object(ref properties) => { - f.write_str("{\n")?; - for property in properties.iter() { - match property { - PropertyDefinition::IdentifierReference(key) => { - write!(f, "{} {},", indent, key)?; - } - PropertyDefinition::Property(key, value) => { - write!(f, "{} {}: {},", indent, key, value)?; - } - PropertyDefinition::SpreadObject(key) => { - write!(f, "{} ...{},", indent, key)?; - } - PropertyDefinition::MethodDefinition(_kind, _key, _node) => { - // TODO: Implement display for PropertyDefinition::MethodDefinition. - unimplemented!("Display for PropertyDefinition::MethodDefinition"); - } - } - } - f.write_str("}") - } + Self::Object(ref obj) => obj.display(f, indentation), Self::ArrayDecl(ref arr) => Display::fmt(arr, f), Self::VarDeclList(ref list) => Display::fmt(list, f), Self::FunctionDecl(ref decl) => decl.display(f, indentation), diff --git a/boa/src/syntax/ast/node/object.rs b/boa/src/syntax/ast/node/object.rs index 0c36953b957..089682665ee 100644 --- a/boa/src/syntax/ast/node/object.rs +++ b/boa/src/syntax/ast/node/object.rs @@ -34,4 +34,55 @@ use serde::{Deserialize, Serialize}; #[derive(Clone, Debug, Trace, Finalize, PartialEq)] pub struct Object { properties: Box<[PropertyDefinition]> +} + +impl Object { + /// Creates an `Object` AST node. + pub fn new(props: D) -> Self + where + D: Into>, + { + Self { + properties: props.into() + } + } + + pub fn properties(&self) -> &Box<[PropertyDefinition]> { + &self.properties + } + + /// Implements the display formatting with indentation. + pub(super) fn display(&self, f: &mut fmt::Formatter<'_>, indent: usize) -> fmt::Result { + f.write_str("{\n")?; + for property in self.properties().iter() { + match property { + PropertyDefinition::IdentifierReference(key) => { + write!(f, "{} {},", indent, key)?; + } + PropertyDefinition::Property(key, value) => { + write!(f, "{} {}: {},", indent, key, value)?; + } + PropertyDefinition::SpreadObject(key) => { + write!(f, "{} ...{},", indent, key)?; + } + PropertyDefinition::MethodDefinition(_kind, _key, _node) => { + // TODO: Implement display for PropertyDefinition::MethodDefinition. + unimplemented!("Display for PropertyDefinition::MethodDefinition"); + } + } + } + f.write_str("}") + } +} + +impl fmt::Display for Object { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.display(f, 0) + } +} + +impl From for Node { + fn from(obj: Object) -> Self { + Self::Object(obj) + } } \ No newline at end of file diff --git a/boa/src/syntax/parser/expression/primary/object_initializer/mod.rs b/boa/src/syntax/parser/expression/primary/object_initializer/mod.rs index f1c6785400f..dd41ab11cf1 100644 --- a/boa/src/syntax/parser/expression/primary/object_initializer/mod.rs +++ b/boa/src/syntax/parser/expression/primary/object_initializer/mod.rs @@ -12,7 +12,7 @@ mod tests; use crate::syntax::{ ast::{ - node::{self, FunctionExpr, MethodDefinitionKind, Node}, + node::{self, FunctionExpr, MethodDefinitionKind, Node, Object}, token::{Token, TokenKind}, Punctuator, }, @@ -82,7 +82,7 @@ impl TokenParser for ObjectLiteral { } } - Ok(Node::object(elements)) + Ok(Object::new(elements).into()) } } diff --git a/boa/src/syntax/parser/expression/primary/object_initializer/tests.rs b/boa/src/syntax/parser/expression/primary/object_initializer/tests.rs index f3b6590a0c2..2f4c271c500 100644 --- a/boa/src/syntax/parser/expression/primary/object_initializer/tests.rs +++ b/boa/src/syntax/parser/expression/primary/object_initializer/tests.rs @@ -2,7 +2,7 @@ use crate::syntax::{ ast::{ node::{ ConstDecl, ConstDeclList, FormalParameter, FunctionExpr, MethodDefinitionKind, Node, - PropertyDefinition, + PropertyDefinition, Object }, Const, }, @@ -24,7 +24,7 @@ fn check_object_literal() { }; ", vec![ - ConstDeclList::from(vec![ConstDecl::new("x", Node::object(object_properties))]).into(), + ConstDeclList::from(vec![ConstDecl::new("x", Object::new(object_properties))]).into(), ], ); } @@ -48,7 +48,7 @@ fn check_object_short_function() { }; ", vec![ - ConstDeclList::from(vec![ConstDecl::new("x", Node::object(object_properties))]).into(), + ConstDeclList::from(vec![ConstDecl::new("x", Object::new(object_properties))]).into(), ], ); } @@ -76,7 +76,7 @@ fn check_object_short_function_arguments() { }; ", vec![ - ConstDeclList::from(vec![ConstDecl::new("x", Node::object(object_properties))]).into(), + ConstDeclList::from(vec![ConstDecl::new("x", Object::new(object_properties))]).into(), ], ); } @@ -99,7 +99,7 @@ fn check_object_getter() { }; ", vec![ - ConstDeclList::from(vec![ConstDecl::new("x", Node::object(object_properties))]).into(), + ConstDeclList::from(vec![ConstDecl::new("x", Object::new(object_properties))]).into(), ], ); } @@ -126,7 +126,7 @@ fn check_object_setter() { }; ", vec![ - ConstDeclList::from(vec![ConstDecl::new("x", Node::object(object_properties))]).into(), + ConstDeclList::from(vec![ConstDecl::new("x", Object::new(object_properties))]).into(), ], ); } From 88a5ba3b501407d1ef4a26f21b37959747799b9e Mon Sep 17 00:00:00 2001 From: Paul Lancaster Date: Tue, 26 May 2020 18:13:06 +0100 Subject: [PATCH 03/42] Rustfmt --- boa/src/exec/object/mod.rs | 8 +++---- boa/src/syntax/ast/node/mod.rs | 4 ++-- boa/src/syntax/ast/node/object.rs | 6 ++--- .../primary/object_initializer/tests.rs | 22 +++++-------------- 4 files changed, 14 insertions(+), 26 deletions(-) diff --git a/boa/src/exec/object/mod.rs b/boa/src/exec/object/mod.rs index 164aef52cd8..1f7112e8c55 100644 --- a/boa/src/exec/object/mod.rs +++ b/boa/src/exec/object/mod.rs @@ -2,14 +2,12 @@ use super::{Executable, Interpreter}; use crate::{ - builtins::value::{Value, ResultValue}, + builtins::value::{ResultValue, Value}, environment::lexical_environment::{new_declarative_environment, VariableScope}, - syntax::ast::node::{Object, PropertyDefinition}, syntax::ast::node::MethodDefinitionKind, + syntax::ast::node::{Object, PropertyDefinition}, }; - - use std::borrow::Borrow; impl Executable for Object { @@ -43,4 +41,4 @@ impl Executable for Object { Ok(obj) } -} \ No newline at end of file +} diff --git a/boa/src/syntax/ast/node/mod.rs b/boa/src/syntax/ast/node/mod.rs index 7333f597aa5..54ca6d39617 100644 --- a/boa/src/syntax/ast/node/mod.rs +++ b/boa/src/syntax/ast/node/mod.rs @@ -6,10 +6,10 @@ pub mod declaration; pub mod expression; pub mod identifier; pub mod iteration; +pub mod object; pub mod operator; pub mod statement_list; pub mod try_node; -pub mod object; pub use self::{ array::ArrayDecl, @@ -21,10 +21,10 @@ pub use self::{ expression::{Call, New}, identifier::Identifier, iteration::ForLoop, + object::Object, operator::{Assign, BinOp, UnaryOp}, statement_list::StatementList, try_node::{Catch, Finally, Try}, - object::Object }; use super::Const; use gc::{Finalize, Trace}; diff --git a/boa/src/syntax/ast/node/object.rs b/boa/src/syntax/ast/node/object.rs index 089682665ee..7a0badff374 100644 --- a/boa/src/syntax/ast/node/object.rs +++ b/boa/src/syntax/ast/node/object.rs @@ -33,7 +33,7 @@ use serde::{Deserialize, Serialize}; #[cfg_attr(feature = "serde", serde(transparent))] #[derive(Clone, Debug, Trace, Finalize, PartialEq)] pub struct Object { - properties: Box<[PropertyDefinition]> + properties: Box<[PropertyDefinition]>, } impl Object { @@ -43,7 +43,7 @@ impl Object { D: Into>, { Self { - properties: props.into() + properties: props.into(), } } @@ -85,4 +85,4 @@ impl From for Node { fn from(obj: Object) -> Self { Self::Object(obj) } -} \ No newline at end of file +} diff --git a/boa/src/syntax/parser/expression/primary/object_initializer/tests.rs b/boa/src/syntax/parser/expression/primary/object_initializer/tests.rs index 2f4c271c500..fffa45cf5d7 100644 --- a/boa/src/syntax/parser/expression/primary/object_initializer/tests.rs +++ b/boa/src/syntax/parser/expression/primary/object_initializer/tests.rs @@ -2,7 +2,7 @@ use crate::syntax::{ ast::{ node::{ ConstDecl, ConstDeclList, FormalParameter, FunctionExpr, MethodDefinitionKind, Node, - PropertyDefinition, Object + Object, PropertyDefinition, }, Const, }, @@ -23,9 +23,7 @@ fn check_object_literal() { b: false, }; ", - vec![ - ConstDeclList::from(vec![ConstDecl::new("x", Object::new(object_properties))]).into(), - ], + vec![ConstDeclList::from(vec![ConstDecl::new("x", Object::new(object_properties))]).into()], ); } @@ -47,9 +45,7 @@ fn check_object_short_function() { b() {}, }; ", - vec![ - ConstDeclList::from(vec![ConstDecl::new("x", Object::new(object_properties))]).into(), - ], + vec![ConstDeclList::from(vec![ConstDecl::new("x", Object::new(object_properties))]).into()], ); } @@ -75,9 +71,7 @@ fn check_object_short_function_arguments() { b(test) {} }; ", - vec![ - ConstDeclList::from(vec![ConstDecl::new("x", Object::new(object_properties))]).into(), - ], + vec![ConstDeclList::from(vec![ConstDecl::new("x", Object::new(object_properties))]).into()], ); } @@ -98,9 +92,7 @@ fn check_object_getter() { get b() {} }; ", - vec![ - ConstDeclList::from(vec![ConstDecl::new("x", Object::new(object_properties))]).into(), - ], + vec![ConstDeclList::from(vec![ConstDecl::new("x", Object::new(object_properties))]).into()], ); } @@ -125,8 +117,6 @@ fn check_object_setter() { set b(test) {} }; ", - vec![ - ConstDeclList::from(vec![ConstDecl::new("x", Object::new(object_properties))]).into(), - ], + vec![ConstDeclList::from(vec![ConstDecl::new("x", Object::new(object_properties))]).into()], ); } From e51d8be95ef9e72c18feff27e8daf48185aea6a6 Mon Sep 17 00:00:00 2001 From: Paul Lancaster Date: Tue, 26 May 2020 18:20:01 +0100 Subject: [PATCH 04/42] Make clippy happier --- boa/src/exec/mod.rs | 2 +- boa/src/exec/object/mod.rs | 1 - boa/src/syntax/ast/node/object.rs | 2 +- .../parser/expression/primary/object_initializer/tests.rs | 2 +- 4 files changed, 3 insertions(+), 4 deletions(-) diff --git a/boa/src/exec/mod.rs b/boa/src/exec/mod.rs index 2b296c52055..723accbc240 100644 --- a/boa/src/exec/mod.rs +++ b/boa/src/exec/mod.rs @@ -25,7 +25,7 @@ use crate::{ realm::Realm, syntax::ast::{ constant::Const, - node::{FormalParameter, MethodDefinitionKind, Node, PropertyDefinition, StatementList}, + node::{FormalParameter, Node, StatementList}, }, }; use std::{borrow::Borrow, ops::Deref}; diff --git a/boa/src/exec/object/mod.rs b/boa/src/exec/object/mod.rs index 1f7112e8c55..5b9acd8ec3c 100644 --- a/boa/src/exec/object/mod.rs +++ b/boa/src/exec/object/mod.rs @@ -3,7 +3,6 @@ use super::{Executable, Interpreter}; use crate::{ builtins::value::{ResultValue, Value}, - environment::lexical_environment::{new_declarative_environment, VariableScope}, syntax::ast::node::MethodDefinitionKind, syntax::ast::node::{Object, PropertyDefinition}, }; diff --git a/boa/src/syntax/ast/node/object.rs b/boa/src/syntax/ast/node/object.rs index 7a0badff374..b210938bf37 100644 --- a/boa/src/syntax/ast/node/object.rs +++ b/boa/src/syntax/ast/node/object.rs @@ -47,7 +47,7 @@ impl Object { } } - pub fn properties(&self) -> &Box<[PropertyDefinition]> { + pub fn properties(&self) -> &[PropertyDefinition] { &self.properties } diff --git a/boa/src/syntax/parser/expression/primary/object_initializer/tests.rs b/boa/src/syntax/parser/expression/primary/object_initializer/tests.rs index fffa45cf5d7..524451813d1 100644 --- a/boa/src/syntax/parser/expression/primary/object_initializer/tests.rs +++ b/boa/src/syntax/parser/expression/primary/object_initializer/tests.rs @@ -1,7 +1,7 @@ use crate::syntax::{ ast::{ node::{ - ConstDecl, ConstDeclList, FormalParameter, FunctionExpr, MethodDefinitionKind, Node, + ConstDecl, ConstDeclList, FormalParameter, FunctionExpr, MethodDefinitionKind, Object, PropertyDefinition, }, Const, From 4c058c0470ed8f255a04cec17833c9a85cc3e83a Mon Sep 17 00:00:00 2001 From: Paul Lancaster Date: Tue, 26 May 2020 18:39:45 +0100 Subject: [PATCH 05/42] Starting to reimplement switch --- boa/src/exec/mod.rs | 26 +------------------------- boa/src/syntax/ast/node/mod.rs | 2 +- boa/src/syntax/ast/node/switch.rs | 29 +++++++++++++++++++++++++++++ 3 files changed, 31 insertions(+), 26 deletions(-) create mode 100644 boa/src/syntax/ast/node/switch.rs diff --git a/boa/src/exec/mod.rs b/boa/src/exec/mod.rs index 723accbc240..152508e96fc 100644 --- a/boa/src/exec/mod.rs +++ b/boa/src/exec/mod.rs @@ -423,31 +423,7 @@ impl Executable for Node { else_e.run(interpreter)? }) } - Node::Switch(ref val_e, ref vals, ref default) => { - let val = val_e.run(interpreter)?; - let mut result = Value::null(); - let mut matched = false; - for tup in vals.iter() { - let cond = &tup.0; - let block = &tup.1; - if val.strict_equals(&cond.run(interpreter)?) { - matched = true; - let last_expr = block.last().expect("Block has no expressions"); - for expr in block.iter() { - let e_result = expr.run(interpreter)?; - if expr == last_expr { - result = e_result; - } - } - } - } - if !matched { - if let Some(default) = default { - result = default.run(interpreter)?; - } - } - Ok(result) - } + Node::Switch(ref switch) => switch.run(interpreter), Node::Object(ref obj) => obj.run(interpreter), Node::ArrayDecl(ref arr) => arr.run(interpreter), // diff --git a/boa/src/syntax/ast/node/mod.rs b/boa/src/syntax/ast/node/mod.rs index 54ca6d39617..bea64b88c92 100644 --- a/boa/src/syntax/ast/node/mod.rs +++ b/boa/src/syntax/ast/node/mod.rs @@ -255,7 +255,7 @@ pub enum Node { /// /// [spec]: https://tc39.es/ecma262/#prod-SwitchStatement /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/switch - Switch(Box, Box<[(Node, Box<[Node]>)]>, Option>), + Switch(Switch), /// The `spread` operator allows an iterable such as an array expression or string to be /// expanded. diff --git a/boa/src/syntax/ast/node/switch.rs b/boa/src/syntax/ast/node/switch.rs new file mode 100644 index 00000000000..8d17c12d622 --- /dev/null +++ b/boa/src/syntax/ast/node/switch.rs @@ -0,0 +1,29 @@ +Switch(Box, Box<[(Node, Box<[Node]>)]>, Option>), + + + + Node::Switch(ref val_e, ref vals, ref default) => { + let val = val_e.run(interpreter)?; + let mut result = Value::null(); + let mut matched = false; + for tup in vals.iter() { + let cond = &tup.0; + let block = &tup.1; + if val.strict_equals(&cond.run(interpreter)?) { + matched = true; + let last_expr = block.last().expect("Block has no expressions"); + for expr in block.iter() { + let e_result = expr.run(interpreter)?; + if expr == last_expr { + result = e_result; + } + } + } + } + if !matched { + if let Some(default) = default { + result = default.run(interpreter)?; + } + } + Ok(result) +} \ No newline at end of file From 744dee8b4dd9b02a61b5d8ce63b4418a90c301d4 Mon Sep 17 00:00:00 2001 From: Paul Lancaster Date: Wed, 27 May 2020 08:31:50 +0100 Subject: [PATCH 06/42] Remove extra newline Co-authored-by: Iban Eguia --- boa/src/syntax/ast/node/object.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/boa/src/syntax/ast/node/object.rs b/boa/src/syntax/ast/node/object.rs index b210938bf37..a79bec96750 100644 --- a/boa/src/syntax/ast/node/object.rs +++ b/boa/src/syntax/ast/node/object.rs @@ -28,7 +28,6 @@ use serde::{Deserialize, Serialize}; /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Object_initializer /// [object]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object /// [primitive]: https://developer.mozilla.org/en-US/docs/Glossary/primitive - #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde", serde(transparent))] #[derive(Clone, Debug, Trace, Finalize, PartialEq)] From dc6b371d97675ffbf18550ab7202848e4c550f13 Mon Sep 17 00:00:00 2001 From: Paul Lancaster Date: Wed, 27 May 2020 08:53:53 +0100 Subject: [PATCH 07/42] Replaced AST object new with From --- boa/src/syntax/ast/node/object.rs | 21 ++++++++++--------- .../primary/object_initializer/mod.rs | 2 +- .../primary/object_initializer/tests.rs | 10 ++++----- 3 files changed, 17 insertions(+), 16 deletions(-) diff --git a/boa/src/syntax/ast/node/object.rs b/boa/src/syntax/ast/node/object.rs index b210938bf37..0025d4f3f26 100644 --- a/boa/src/syntax/ast/node/object.rs +++ b/boa/src/syntax/ast/node/object.rs @@ -37,16 +37,6 @@ pub struct Object { } impl Object { - /// Creates an `Object` AST node. - pub fn new(props: D) -> Self - where - D: Into>, - { - Self { - properties: props.into(), - } - } - pub fn properties(&self) -> &[PropertyDefinition] { &self.properties } @@ -81,6 +71,17 @@ impl fmt::Display for Object { } } +impl From for Object +where + T: Into>, +{ + fn from(props: T) -> Self { + Self { + properties: props.into(), + } + } +} + impl From for Node { fn from(obj: Object) -> Self { Self::Object(obj) diff --git a/boa/src/syntax/parser/expression/primary/object_initializer/mod.rs b/boa/src/syntax/parser/expression/primary/object_initializer/mod.rs index dd41ab11cf1..9eb6b51c720 100644 --- a/boa/src/syntax/parser/expression/primary/object_initializer/mod.rs +++ b/boa/src/syntax/parser/expression/primary/object_initializer/mod.rs @@ -82,7 +82,7 @@ impl TokenParser for ObjectLiteral { } } - Ok(Object::new(elements).into()) + Ok(Object::from(elements).into()) } } diff --git a/boa/src/syntax/parser/expression/primary/object_initializer/tests.rs b/boa/src/syntax/parser/expression/primary/object_initializer/tests.rs index 524451813d1..854560e50eb 100644 --- a/boa/src/syntax/parser/expression/primary/object_initializer/tests.rs +++ b/boa/src/syntax/parser/expression/primary/object_initializer/tests.rs @@ -23,7 +23,7 @@ fn check_object_literal() { b: false, }; ", - vec![ConstDeclList::from(vec![ConstDecl::new("x", Object::new(object_properties))]).into()], + vec![ConstDeclList::from(vec![ConstDecl::new("x", Object::from(object_properties))]).into()], ); } @@ -45,7 +45,7 @@ fn check_object_short_function() { b() {}, }; ", - vec![ConstDeclList::from(vec![ConstDecl::new("x", Object::new(object_properties))]).into()], + vec![ConstDeclList::from(vec![ConstDecl::new("x", Object::from(object_properties))]).into()], ); } @@ -71,7 +71,7 @@ fn check_object_short_function_arguments() { b(test) {} }; ", - vec![ConstDeclList::from(vec![ConstDecl::new("x", Object::new(object_properties))]).into()], + vec![ConstDeclList::from(vec![ConstDecl::new("x", Object::from(object_properties))]).into()], ); } @@ -92,7 +92,7 @@ fn check_object_getter() { get b() {} }; ", - vec![ConstDeclList::from(vec![ConstDecl::new("x", Object::new(object_properties))]).into()], + vec![ConstDeclList::from(vec![ConstDecl::new("x", Object::from(object_properties))]).into()], ); } @@ -117,6 +117,6 @@ fn check_object_setter() { set b(test) {} }; ", - vec![ConstDeclList::from(vec![ConstDecl::new("x", Object::new(object_properties))]).into()], + vec![ConstDeclList::from(vec![ConstDecl::new("x", Object::from(object_properties))]).into()], ); } From d91ac61b16821212c61a0fd1a6de50d327c0c240 Mon Sep 17 00:00:00 2001 From: Paul Lancaster Date: Wed, 27 May 2020 08:55:35 +0100 Subject: [PATCH 08/42] Rustfmt --- .../primary/object_initializer/tests.rs | 24 +++++++++++++------ 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/boa/src/syntax/parser/expression/primary/object_initializer/tests.rs b/boa/src/syntax/parser/expression/primary/object_initializer/tests.rs index 854560e50eb..2a58d44cac1 100644 --- a/boa/src/syntax/parser/expression/primary/object_initializer/tests.rs +++ b/boa/src/syntax/parser/expression/primary/object_initializer/tests.rs @@ -1,8 +1,8 @@ use crate::syntax::{ ast::{ node::{ - ConstDecl, ConstDeclList, FormalParameter, FunctionExpr, MethodDefinitionKind, - Object, PropertyDefinition, + ConstDecl, ConstDeclList, FormalParameter, FunctionExpr, MethodDefinitionKind, Object, + PropertyDefinition, }, Const, }, @@ -23,7 +23,9 @@ fn check_object_literal() { b: false, }; ", - vec![ConstDeclList::from(vec![ConstDecl::new("x", Object::from(object_properties))]).into()], + vec![ + ConstDeclList::from(vec![ConstDecl::new("x", Object::from(object_properties))]).into(), + ], ); } @@ -45,7 +47,9 @@ fn check_object_short_function() { b() {}, }; ", - vec![ConstDeclList::from(vec![ConstDecl::new("x", Object::from(object_properties))]).into()], + vec![ + ConstDeclList::from(vec![ConstDecl::new("x", Object::from(object_properties))]).into(), + ], ); } @@ -71,7 +75,9 @@ fn check_object_short_function_arguments() { b(test) {} }; ", - vec![ConstDeclList::from(vec![ConstDecl::new("x", Object::from(object_properties))]).into()], + vec![ + ConstDeclList::from(vec![ConstDecl::new("x", Object::from(object_properties))]).into(), + ], ); } @@ -92,7 +98,9 @@ fn check_object_getter() { get b() {} }; ", - vec![ConstDeclList::from(vec![ConstDecl::new("x", Object::from(object_properties))]).into()], + vec![ + ConstDeclList::from(vec![ConstDecl::new("x", Object::from(object_properties))]).into(), + ], ); } @@ -117,6 +125,8 @@ fn check_object_setter() { set b(test) {} }; ", - vec![ConstDeclList::from(vec![ConstDecl::new("x", Object::from(object_properties))]).into()], + vec![ + ConstDeclList::from(vec![ConstDecl::new("x", Object::from(object_properties))]).into(), + ], ); } From 4b0bed1e0debea77db4127224bfc8a2313cc7a56 Mon Sep 17 00:00:00 2001 From: Paul Lancaster Date: Wed, 27 May 2020 11:13:58 +0100 Subject: [PATCH 09/42] Starting to move switch AST into seperate files --- boa/src/exec/mod.rs | 1 + boa/src/exec/switch/mod.rs | 37 +++++++++++++++ boa/src/syntax/ast/node/mod.rs | 18 +------- boa/src/syntax/ast/node/switch.rs | 76 ++++++++++++++++++++----------- 4 files changed, 89 insertions(+), 43 deletions(-) create mode 100644 boa/src/exec/switch/mod.rs diff --git a/boa/src/exec/mod.rs b/boa/src/exec/mod.rs index 152508e96fc..7ce8342e70b 100644 --- a/boa/src/exec/mod.rs +++ b/boa/src/exec/mod.rs @@ -8,6 +8,7 @@ mod iteration; mod object; mod operator; mod statement_list; +mod switch; #[cfg(test)] mod tests; mod try_node; diff --git a/boa/src/exec/switch/mod.rs b/boa/src/exec/switch/mod.rs new file mode 100644 index 00000000000..737b34f5191 --- /dev/null +++ b/boa/src/exec/switch/mod.rs @@ -0,0 +1,37 @@ +use super::{Executable, Interpreter}; +use crate::{ + builtins::value::ResultValue, + syntax::ast::node::Switch, +}; + +impl Executable for Switch { + fn run(&self, interpreter: &mut Interpreter) -> ResultValue { + + Node::Switch(ref val_e, ref vals, ref default) => { + let val = val_e.run(interpreter)?; + let mut result = Value::null(); + let mut matched = false; + for tup in vals.iter() { + let cond = &tup.0; + let block = &tup.1; + if val.strict_equals(&cond.run(interpreter)?) { + matched = true; + let last_expr = block.last().expect("Block has no expressions"); + for expr in block.iter() { + let e_result = expr.run(interpreter)?; + if expr == last_expr { + result = e_result; + } + } + } + } + if !matched { + if let Some(default) = default { + result = default.run(interpreter)?; + } + } + Ok(result) + } + + } +} \ No newline at end of file diff --git a/boa/src/syntax/ast/node/mod.rs b/boa/src/syntax/ast/node/mod.rs index bea64b88c92..6e002c8224a 100644 --- a/boa/src/syntax/ast/node/mod.rs +++ b/boa/src/syntax/ast/node/mod.rs @@ -9,6 +9,7 @@ pub mod iteration; pub mod object; pub mod operator; pub mod statement_list; +pub mod switch; pub mod try_node; pub use self::{ @@ -24,6 +25,7 @@ pub use self::{ object::Object, operator::{Assign, BinOp, UnaryOp}, statement_list::StatementList, + switch::Switch, try_node::{Catch, Finally, Try}, }; use super::Const; @@ -239,22 +241,6 @@ pub enum Node { /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/return Return(Option>), - /// The `switch` statement evaluates an expression, matching the expression's value to a case - /// clause, and executes statements associated with that case, as well as statements in cases - /// that follow the matching case. - /// - /// A `switch` statement first evaluates its expression. It then looks for the first case - /// clause whose expression evaluates to the same value as the result of the input expression - /// (using the strict comparison, `===`) and transfers control to that clause, executing the - /// associated statements. (If multiple cases match the provided value, the first case that - /// matches is selected, even if the cases are not equal to each other.) - /// - /// More information: - /// - [ECMAScript reference][spec] - /// - [MDN documentation][mdn] - /// - /// [spec]: https://tc39.es/ecma262/#prod-SwitchStatement - /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/switch Switch(Switch), /// The `spread` operator allows an iterable such as an array expression or string to be diff --git a/boa/src/syntax/ast/node/switch.rs b/boa/src/syntax/ast/node/switch.rs index 8d17c12d622..065ea2aabfe 100644 --- a/boa/src/syntax/ast/node/switch.rs +++ b/boa/src/syntax/ast/node/switch.rs @@ -1,29 +1,51 @@ -Switch(Box, Box<[(Node, Box<[Node]>)]>, Option>), - - - - Node::Switch(ref val_e, ref vals, ref default) => { - let val = val_e.run(interpreter)?; - let mut result = Value::null(); - let mut matched = false; - for tup in vals.iter() { - let cond = &tup.0; - let block = &tup.1; - if val.strict_equals(&cond.run(interpreter)?) { - matched = true; - let last_expr = block.last().expect("Block has no expressions"); - for expr in block.iter() { - let e_result = expr.run(interpreter)?; - if expr == last_expr { - result = e_result; - } - } - } +//! Switch node. + +use super::Node; +use gc::{Finalize, Trace}; +use std::fmt; + +#[cfg(feature = "serde")] +use serde::{Deserialize, Serialize}; + + +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +#[cfg_attr(feature = "serde", serde(transparent))] +#[derive(Clone, Debug, Trace, Finalize, PartialEq)] +pub struct Switch { + +} + +/// The `switch` statement evaluates an expression, matching the expression's value to a case +/// clause, and executes statements associated with that case, as well as statements in cases +/// that follow the matching case. +/// +/// A `switch` statement first evaluates its expression. It then looks for the first case +/// clause whose expression evaluates to the same value as the result of the input expression +/// (using the strict comparison, `===`) and transfers control to that clause, executing the +/// associated statements. (If multiple cases match the provided value, the first case that +/// matches is selected, even if the cases are not equal to each other.) +/// +/// More information: +/// - [ECMAScript reference][spec] +/// - [MDN documentation][mdn] +/// +/// [spec]: https://tc39.es/ecma262/#prod-SwitchStatement +/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/switch +impl Switch { + /// Implements the display formatting with indentation. + pub(super) fn display(&self, f: &mut fmt::Formatter<'_>, indent: usize) -> fmt::Result { + + } +} + +impl fmt::Display for Switch { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.display(f, 0) } - if !matched { - if let Some(default) = default { - result = default.run(interpreter)?; - } +} + +impl From for Node { + fn from(switch: Switch) -> Self { + Self::Switch(switch) } - Ok(result) -} \ No newline at end of file +} From 8ff55908de7487db8219bbdf7aae8f71d5fd18bc Mon Sep 17 00:00:00 2001 From: Paul Lancaster Date: Wed, 27 May 2020 16:20:38 +0100 Subject: [PATCH 10/42] Seperated switch AST node into seperate files --- boa/src/exec/switch/mod.rs | 45 +++++++++--------- boa/src/syntax/ast/node/mod.rs | 35 +------------- boa/src/syntax/ast/node/statement_list.rs | 5 +- boa/src/syntax/ast/node/switch.rs | 46 ++++++++++++++++--- boa/src/syntax/parser/statement/switch/mod.rs | 7 ++- 5 files changed, 69 insertions(+), 69 deletions(-) diff --git a/boa/src/exec/switch/mod.rs b/boa/src/exec/switch/mod.rs index 737b34f5191..8dca8f9f805 100644 --- a/boa/src/exec/switch/mod.rs +++ b/boa/src/exec/switch/mod.rs @@ -1,37 +1,34 @@ use super::{Executable, Interpreter}; use crate::{ - builtins::value::ResultValue, + builtins::value::{ResultValue, Value}, syntax::ast::node::Switch, }; impl Executable for Switch { fn run(&self, interpreter: &mut Interpreter) -> ResultValue { - - Node::Switch(ref val_e, ref vals, ref default) => { - let val = val_e.run(interpreter)?; - let mut result = Value::null(); - let mut matched = false; - for tup in vals.iter() { - let cond = &tup.0; - let block = &tup.1; - if val.strict_equals(&cond.run(interpreter)?) { - matched = true; - let last_expr = block.last().expect("Block has no expressions"); - for expr in block.iter() { - let e_result = expr.run(interpreter)?; - if expr == last_expr { - result = e_result; - } + let default = self.default(); + let val = self.val().run(interpreter)?; + let mut result = Value::null(); + let mut matched = false; + for tup in self.cases().iter() { + let cond = &tup.0; + let block = &tup.1; + if val.strict_equals(&cond.run(interpreter)?) { + matched = true; + let last_expr = block.last().expect("Block has no expressions"); + for expr in block.iter() { + let e_result = expr.run(interpreter)?; + if expr == last_expr { + result = e_result; } } } - if !matched { - if let Some(default) = default { - result = default.run(interpreter)?; - } + } + if !matched { + if let Some(default) = default { + result = default.run(interpreter)?; } - Ok(result) } - + Ok(result) } -} \ No newline at end of file +} diff --git a/boa/src/syntax/ast/node/mod.rs b/boa/src/syntax/ast/node/mod.rs index 6e002c8224a..2ae594e6b9e 100644 --- a/boa/src/syntax/ast/node/mod.rs +++ b/boa/src/syntax/ast/node/mod.rs @@ -421,21 +421,6 @@ impl Node { Self::Return(expr.into().map(E::into).map(Box::new)) } - /// Creates a `Switch` AST node. - pub fn switch(val: V, cases: C, default: OD) -> Self - where - V: Into, - C: Into)]>>, - OD: Into>, - D: Into, - { - Self::Switch( - Box::new(val.into()), - cases.into(), - default.into().map(D::into).map(Box::new), - ) - } - /// Creates a `Spread` AST node. pub fn spread(val: V) -> Self where @@ -526,24 +511,8 @@ impl Node { f.write_str(" else ")?; else_e.display(f, indentation) } - Self::Switch(ref val, ref vals, None) => { - writeln!(f, "switch ({}) {{", val)?; - for e in vals.iter() { - writeln!(f, "{}case {}:", indent, e.0)?; - join_nodes(f, &e.1)?; - } - writeln!(f, "{}}}", indent) - } - Self::Switch(ref val, ref vals, Some(ref def)) => { - writeln!(f, "switch ({}) {{", val)?; - for e in vals.iter() { - writeln!(f, "{}case {}:", indent, e.0)?; - join_nodes(f, &e.1)?; - } - writeln!(f, "{}default:", indent)?; - def.display(f, indentation + 1)?; - write!(f, "{}}}", indent) - } + + Self::Switch(ref switch) => switch.display(f, indentation), Self::Object(ref obj) => obj.display(f, indentation), Self::ArrayDecl(ref arr) => Display::fmt(arr, f), Self::VarDeclList(ref list) => Display::fmt(list, f), diff --git a/boa/src/syntax/ast/node/statement_list.rs b/boa/src/syntax/ast/node/statement_list.rs index 49404a01ca0..94815a2c7fd 100644 --- a/boa/src/syntax/ast/node/statement_list.rs +++ b/boa/src/syntax/ast/node/statement_list.rs @@ -37,10 +37,7 @@ impl StatementList { node.display(f, indentation + 1)?; match node { - Node::Block(_) - | Node::If(_, _, _) - | Node::Switch(_, _, _) - | Node::WhileLoop(_, _) => {} + Node::Block(_) | Node::If(_, _, _) | Node::Switch(_) | Node::WhileLoop(_, _) => {} _ => write!(f, ";")?, } writeln!(f)?; diff --git a/boa/src/syntax/ast/node/switch.rs b/boa/src/syntax/ast/node/switch.rs index 065ea2aabfe..c43c776214f 100644 --- a/boa/src/syntax/ast/node/switch.rs +++ b/boa/src/syntax/ast/node/switch.rs @@ -1,18 +1,18 @@ //! Switch node. - -use super::Node; +//! +use super::{join_nodes, Node}; use gc::{Finalize, Trace}; use std::fmt; #[cfg(feature = "serde")] use serde::{Deserialize, Serialize}; - #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] -#[cfg_attr(feature = "serde", serde(transparent))] #[derive(Clone, Debug, Trace, Finalize, PartialEq)] pub struct Switch { - + val: Box, + cases: Box<[(Node, Box<[Node]>)]>, + default: Option>, } /// The `switch` statement evaluates an expression, matching the expression's value to a case @@ -32,9 +32,43 @@ pub struct Switch { /// [spec]: https://tc39.es/ecma262/#prod-SwitchStatement /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/switch impl Switch { + pub fn val(&self) -> &Node { + &self.val + } + + pub fn cases(&self) -> &[(Node, Box<[Node]>)] { + &self.cases + } + + pub fn default(&self) -> &Option> { + &self.default + } + + pub fn new( + val: Box, + cases: Box<[(Node, Box<[Node]>)]>, + default: Option>, + ) -> Switch { + Self { + val, + cases, + default, + } + } + /// Implements the display formatting with indentation. pub(super) fn display(&self, f: &mut fmt::Formatter<'_>, indent: usize) -> fmt::Result { - + writeln!(f, "switch ({}) {{", self.val())?; + for e in self.cases().iter() { + writeln!(f, "{}case {}:", indent, e.0)?; + join_nodes(f, &e.1)?; + } + + if self.default().is_some() { + writeln!(f, "{}default:", indent)?; + self.default().as_ref().unwrap().display(f, indent + 1)?; + } + writeln!(f, "{}}}", indent) } } diff --git a/boa/src/syntax/parser/statement/switch/mod.rs b/boa/src/syntax/parser/statement/switch/mod.rs index c8416149a03..be434c9e376 100644 --- a/boa/src/syntax/parser/statement/switch/mod.rs +++ b/boa/src/syntax/parser/statement/switch/mod.rs @@ -2,7 +2,7 @@ mod tests; use crate::syntax::{ - ast::{Keyword, Node, Punctuator}, + ast::{node::Switch, Keyword, Node, Punctuator}, parser::{ expression::Expression, AllowAwait, AllowReturn, AllowYield, Cursor, ParseError, ParseResult, TokenParser, @@ -54,7 +54,10 @@ impl TokenParser for SwitchStatement { let (cases, default) = CaseBlock::new(self.allow_yield, self.allow_await, self.allow_return).parse(cursor)?; - Ok(Node::switch::<_, _, _, Node>(condition, cases, default)) + match default { + Some(s) => Ok(Switch::new(Box::new(condition), cases, Some(Box::new(s))).into()), + None => Ok(Switch::new(Box::new(condition), cases, None).into()), + } } } From 6851036222abf657b98ea21f23e36a3ed31952dc Mon Sep 17 00:00:00 2001 From: Paul Lancaster Date: Thu, 28 May 2020 00:06:29 +0100 Subject: [PATCH 11/42] Started moving GetConstField related parts into own file --- boa/src/exec/field/mod.rs | 23 +++++++++++ boa/src/syntax/ast/node/field.rs | 68 ++++++++++++++++++++++++++++++++ boa/src/syntax/ast/node/mod.rs | 41 ++++--------------- 3 files changed, 98 insertions(+), 34 deletions(-) create mode 100644 boa/src/exec/field/mod.rs create mode 100644 boa/src/syntax/ast/node/field.rs diff --git a/boa/src/exec/field/mod.rs b/boa/src/exec/field/mod.rs new file mode 100644 index 00000000000..4a1220d13a0 --- /dev/null +++ b/boa/src/exec/field/mod.rs @@ -0,0 +1,23 @@ +use super::{Executable, Interpreter}; +use crate::{ + builtins::{ + object::{INSTANCE_PROTOTYPE, PROTOTYPE}, + value::{ResultValue, Value, ValueData}, + }, + syntax::ast::node::{Call, New, Node}, +}; + +impl Executable for GetConstField { + fn run(&self, interpreter: &mut Interpreter) -> ResultValue { + let mut obj = obj.run(interpreter)?; + if obj.get_type() != "object" || obj.get_type() != "symbol" { + obj = interpreter + .to_object(&obj) + .expect("failed to convert to object"); + } + (obj.clone(), obj.get_field(field)) + } +} + + + diff --git a/boa/src/syntax/ast/node/field.rs b/boa/src/syntax/ast/node/field.rs new file mode 100644 index 00000000000..57ded3746cf --- /dev/null +++ b/boa/src/syntax/ast/node/field.rs @@ -0,0 +1,68 @@ +//! Field AST node. +//! +use super::{join_nodes, Node}; +use gc::{Finalize, Trace}; +use std::fmt; + +#[cfg(feature = "serde")] +use serde::{Deserialize, Serialize}; + +/// This property accessor provides access to an object's properties by using the +/// [dot notation][mdn]. +/// +/// In the object.property syntax, the property must be a valid JavaScript identifier. +/// (In the ECMAScript standard, the names of properties are technically "IdentifierNames", not +/// "Identifiers", so reserved words can be used but are not recommended). +/// +/// One can think of an object as an associative array (a.k.a. map, dictionary, hash, lookup +/// table). The keys in this array are the names of the object's properties. +/// +/// It's typical when speaking of an object's properties to make a distinction between +/// properties and methods. However, the property/method distinction is little more than a +/// convention. A method is simply a property that can be called (for example, if it has a +/// reference to a Function instance as its value). +/// +/// More information: +/// - [ECMAScript reference][spec] +/// - [MDN documentation][mdn] +/// +/// [spec]: https://tc39.es/ecma262/#sec-property-accessors +/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Property_accessors#Dot_notation +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +#[derive(Clone, Debug, Trace, Finalize, PartialEq)] +pub struct GetConstField { + obj: Box, + field: Box +} + +impl GetConstField { + pub fn obj(&self) -> &Node { + &self.obj + } + + pub fn field(&self) -> &str { + &self.field + } + + /// Creates a `GetConstField` AST node. + pub fn new(value: V, label: L) -> Self + where + V: Into, + L: Into>, + { + Self { + obj: Box::new(value.into()), + field: label.into(), + } + } +} + +impl fmt::Display for GetConstField { + write!(f, "{}.{}", obj, field) +} + +impl From for Node { + fn from(get_const_field: GetConstField) -> Self { + Self::GetConstField(get_const_field) + } +} \ No newline at end of file diff --git a/boa/src/syntax/ast/node/mod.rs b/boa/src/syntax/ast/node/mod.rs index 2ae594e6b9e..b34cc763001 100644 --- a/boa/src/syntax/ast/node/mod.rs +++ b/boa/src/syntax/ast/node/mod.rs @@ -4,6 +4,7 @@ pub mod array; pub mod block; pub mod declaration; pub mod expression; +pub mod field; pub mod identifier; pub mod iteration; pub mod object; @@ -17,9 +18,10 @@ pub use self::{ block::Block, declaration::{ ArrowFunctionDecl, ConstDecl, ConstDeclList, FunctionDecl, FunctionExpr, LetDecl, - LetDeclList, VarDecl, VarDeclList, + LetDeclList, VarDecl, VarDeclList }, expression::{Call, New}, + field::GetConstField, identifier::Identifier, iteration::ForLoop, object::Object, @@ -138,31 +140,11 @@ pub enum Node { /// A function declaration node. [More information](./declaration/struct.FunctionDecl.html). FunctionDecl(FunctionDecl), - /// A function expressino node. [More information](./declaration/struct.FunctionExpr.html) + /// A function expressino node. [More information](./declaration/struct.FunctionExpr.html). FunctionExpr(FunctionExpr), - /// This property accessor provides access to an object's properties by using the - /// [dot notation][mdn]. - /// - /// In the object.property syntax, the property must be a valid JavaScript identifier. - /// (In the ECMAScript standard, the names of properties are technically "IdentifierNames", not - /// "Identifiers", so reserved words can be used but are not recommended). - /// - /// One can think of an object as an associative array (a.k.a. map, dictionary, hash, lookup - /// table). The keys in this array are the names of the object's properties. - /// - /// It's typical when speaking of an object's properties to make a distinction between - /// properties and methods. However, the property/method distinction is little more than a - /// convention. A method is simply a property that can be called (for example, if it has a - /// reference to a Function instance as its value). - /// - /// More information: - /// - [ECMAScript reference][spec] - /// - [MDN documentation][mdn] - /// - /// [spec]: https://tc39.es/ecma262/#sec-property-accessors - /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Property_accessors#Dot_notation - GetConstField(Box, Box), + /// Provides access to an object types' constant properties. [More information](./declaration/struct.GetConstField.html). + GetConstField(GetConstField), /// This property accessor provides access to an object's properties by using the /// [bracket notation][mdn]. @@ -379,15 +361,6 @@ impl Node { Self::DoWhileLoop(Box::new(body.into()), Box::new(condition.into())) } - /// Creates a `GetConstField` AST node. - pub fn get_const_field(value: V, label: L) -> Self - where - V: Into, - L: Into>, - { - Self::GetConstField(Box::new(value.into()), label.into()) - } - /// Creates a `GetField` AST node. pub fn get_field(value: V, field: F) -> Self where @@ -488,7 +461,7 @@ impl Node { Self::Spread(ref node) => write!(f, "...{}", node), Self::Block(ref block) => block.display(f, indentation), Self::Identifier(ref s) => Display::fmt(s, f), - Self::GetConstField(ref ex, ref field) => write!(f, "{}.{}", ex, field), + Self::GetConstField(ref get_const_field) => Display::fmt(get_const_field, f), Self::GetField(ref ex, ref field) => write!(f, "{}[{}]", ex, field), Self::Call(ref expr) => Display::fmt(expr, f), Self::New(ref expr) => Display::fmt(expr, f), From 153f0b1ac03da2d71f5fca4f6d7054c09a6fe8d3 Mon Sep 17 00:00:00 2001 From: Paul Lancaster Date: Thu, 28 May 2020 15:47:02 +0100 Subject: [PATCH 12/42] Correcting various references to Node::GetConstField to use new signature --- boa/src/exec/expression/mod.rs | 10 +--------- boa/src/exec/field/mod.rs | 13 ++++++------- boa/src/exec/mod.rs | 8 +++----- boa/src/syntax/ast/node/field.rs | 8 +++++--- 4 files changed, 15 insertions(+), 24 deletions(-) diff --git a/boa/src/exec/expression/mod.rs b/boa/src/exec/expression/mod.rs index 57fc661ca7a..c69e2ad8fc7 100644 --- a/boa/src/exec/expression/mod.rs +++ b/boa/src/exec/expression/mod.rs @@ -12,15 +12,7 @@ use crate::{ impl Executable for Call { fn run(&self, interpreter: &mut Interpreter) -> ResultValue { let (mut this, func) = match self.expr() { - Node::GetConstField(ref obj, ref field) => { - let mut obj = obj.run(interpreter)?; - if obj.get_type() != "object" || obj.get_type() != "symbol" { - obj = interpreter - .to_object(&obj) - .expect("failed to convert to object"); - } - (obj.clone(), obj.get_field(field)) - } + Node::GetConstField(ref get_const_field) => get_const_field.run(interpreter), Node::GetField(ref obj, ref field) => { let obj = obj.run(interpreter)?; let field = field.run(interpreter)?; diff --git a/boa/src/exec/field/mod.rs b/boa/src/exec/field/mod.rs index 4a1220d13a0..8b040095e7d 100644 --- a/boa/src/exec/field/mod.rs +++ b/boa/src/exec/field/mod.rs @@ -1,21 +1,20 @@ use super::{Executable, Interpreter}; use crate::{ - builtins::{ - object::{INSTANCE_PROTOTYPE, PROTOTYPE}, - value::{ResultValue, Value, ValueData}, - }, - syntax::ast::node::{Call, New, Node}, + builtins::value::ResultValue, + syntax::ast::node::GetConstField, }; impl Executable for GetConstField { fn run(&self, interpreter: &mut Interpreter) -> ResultValue { - let mut obj = obj.run(interpreter)?; + let mut obj = self.obj().run(interpreter)?; if obj.get_type() != "object" || obj.get_type() != "symbol" { obj = interpreter .to_object(&obj) .expect("failed to convert to object"); } - (obj.clone(), obj.get_field(field)) + + + Ok(obj.get_field(self.field())) } } diff --git a/boa/src/exec/mod.rs b/boa/src/exec/mod.rs index 7ce8342e70b..9229d8b983f 100644 --- a/boa/src/exec/mod.rs +++ b/boa/src/exec/mod.rs @@ -4,6 +4,7 @@ mod array; mod block; mod declaration; mod expression; +mod field; mod iteration; mod object; mod operator; @@ -355,7 +356,7 @@ impl Interpreter { .set_mutable_binding(name.as_ref(), value.clone(), true); Ok(value) } - Node::GetConstField(ref obj, ref field) => Ok(obj.run(self)?.set_field(field, value)), + Node::GetConstField(ref get_const_field_node) => Ok(get_const_field_node.obj().run(self)?.set_field(get_const_field_node.field(), value)), Node::GetField(ref obj, ref field) => { Ok(obj.run(self)?.set_field(field.run(self)?, value)) } @@ -385,10 +386,7 @@ impl Executable for Node { .get_binding_value(name.as_ref()); Ok(val) } - Node::GetConstField(ref obj, ref field) => { - let val_obj = obj.run(interpreter)?; - Ok(val_obj.borrow().get_field(field)) - } + Node::GetConstField(ref get_const_field_node) => get_const_field_node.run(interpreter), Node::GetField(ref obj, ref field) => { let val_obj = obj.run(interpreter)?; let val_field = field.run(interpreter)?; diff --git a/boa/src/syntax/ast/node/field.rs b/boa/src/syntax/ast/node/field.rs index 57ded3746cf..03d07d4a7ee 100644 --- a/boa/src/syntax/ast/node/field.rs +++ b/boa/src/syntax/ast/node/field.rs @@ -1,6 +1,6 @@ //! Field AST node. //! -use super::{join_nodes, Node}; +use super::Node; use gc::{Finalize, Trace}; use std::fmt; @@ -47,7 +47,7 @@ impl GetConstField { /// Creates a `GetConstField` AST node. pub fn new(value: V, label: L) -> Self where - V: Into, + V: Into, L: Into>, { Self { @@ -58,7 +58,9 @@ impl GetConstField { } impl fmt::Display for GetConstField { - write!(f, "{}.{}", obj, field) + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{}.{}", self.obj(), self.field()) + } } impl From for Node { From c0404f323484be4559de5da62c4ff9086dc5668a Mon Sep 17 00:00:00 2001 From: Paul Lancaster Date: Fri, 29 May 2020 12:20:00 +0100 Subject: [PATCH 13/42] Extracted GetField code --- boa/src/exec/expression/mod.rs | 16 +++-- boa/src/exec/field/mod.rs | 9 ++- boa/src/exec/mod.rs | 10 +-- boa/src/exec/operator/mod.rs | 31 ++++----- boa/src/syntax/ast/node/field.rs | 64 +++++++++++++++++++ boa/src/syntax/ast/node/mod.rs | 38 ++--------- .../parser/expression/left_hand_side/call.rs | 8 +-- .../expression/left_hand_side/member.rs | 8 +-- .../parser/statement/iteration/tests.rs | 6 +- boa/src/syntax/parser/tests.rs | 7 +- 10 files changed, 116 insertions(+), 81 deletions(-) diff --git a/boa/src/exec/expression/mod.rs b/boa/src/exec/expression/mod.rs index c69e2ad8fc7..f063132f383 100644 --- a/boa/src/exec/expression/mod.rs +++ b/boa/src/exec/expression/mod.rs @@ -12,10 +12,18 @@ use crate::{ impl Executable for Call { fn run(&self, interpreter: &mut Interpreter) -> ResultValue { let (mut this, func) = match self.expr() { - Node::GetConstField(ref get_const_field) => get_const_field.run(interpreter), - Node::GetField(ref obj, ref field) => { - let obj = obj.run(interpreter)?; - let field = field.run(interpreter)?; + Node::GetConstField(ref get_const_field) => { + let mut obj = get_const_field.obj().run(interpreter)?; + if obj.get_type() != "object" || obj.get_type() != "symbol" { + obj = interpreter + .to_object(&obj) + .expect("failed to convert to object"); + } + (obj.clone(), obj.get_field(get_const_field.field())) + }, + Node::GetField(ref get_field) => { + let obj = get_field.obj().run(interpreter)?; + let field = get_field.field().run(interpreter)?; (obj.clone(), obj.get_field(field.to_string())) } _ => ( diff --git a/boa/src/exec/field/mod.rs b/boa/src/exec/field/mod.rs index 8b040095e7d..7143ae14a91 100644 --- a/boa/src/exec/field/mod.rs +++ b/boa/src/exec/field/mod.rs @@ -1,7 +1,7 @@ use super::{Executable, Interpreter}; use crate::{ builtins::value::ResultValue, - syntax::ast::node::GetConstField, + syntax::ast::node::{GetConstField, GetField}, }; impl Executable for GetConstField { @@ -18,5 +18,12 @@ impl Executable for GetConstField { } } +impl Executable for GetField { + fn run(&self, interpreter: &mut Interpreter) -> ResultValue { + let obj = self.obj().run(interpreter)?; + let field = self.field().run(interpreter)?; + Ok(obj.get_field(field.to_string())) + } +} diff --git a/boa/src/exec/mod.rs b/boa/src/exec/mod.rs index 9229d8b983f..f68e3b96994 100644 --- a/boa/src/exec/mod.rs +++ b/boa/src/exec/mod.rs @@ -357,9 +357,7 @@ impl Interpreter { Ok(value) } Node::GetConstField(ref get_const_field_node) => Ok(get_const_field_node.obj().run(self)?.set_field(get_const_field_node.field(), value)), - Node::GetField(ref obj, ref field) => { - Ok(obj.run(self)?.set_field(field.run(self)?, value)) - } + Node::GetField(ref get_field) => Ok(get_field.obj().run(self)?.set_field(get_field.field().run(self)?, value)), _ => panic!("TypeError: invalid assignment to {}", node), } } @@ -387,11 +385,7 @@ impl Executable for Node { Ok(val) } Node::GetConstField(ref get_const_field_node) => get_const_field_node.run(interpreter), - Node::GetField(ref obj, ref field) => { - let val_obj = obj.run(interpreter)?; - let val_field = field.run(interpreter)?; - Ok(val_obj.borrow().get_field(val_field.borrow().to_string())) - } + Node::GetField(ref get_field) => get_field.run(interpreter), Node::Call(ref expr) => expr.run(interpreter), Node::WhileLoop(ref cond, ref expr) => { let mut result = Value::undefined(); diff --git a/boa/src/exec/operator/mod.rs b/boa/src/exec/operator/mod.rs index d4cb97495cb..beee5cc910e 100644 --- a/boa/src/exec/operator/mod.rs +++ b/boa/src/exec/operator/mod.rs @@ -5,7 +5,7 @@ use crate::{ builtins::value::{ResultValue, Value}, environment::lexical_environment::VariableScope, syntax::ast::{ - node::{Assign, BinOp, Node, UnaryOp}, + node::{Assign, BinOp, Node, UnaryOp, field::GetConstField}, op::{self, AssignOp, BitOp, CompOp, LogOp, NumOp}, }, }; @@ -30,13 +30,13 @@ impl Executable for Assign { environment.initialize_binding(name.as_ref(), val.clone()); } } - Node::GetConstField(ref obj, ref field) => { - let val_obj = obj.run(interpreter)?; - val_obj.set_field(field, val.clone()); + Node::GetConstField(ref get_const_field) => { + let val_obj = get_const_field.obj().run(interpreter)?; + val_obj.set_field(get_const_field.field(), val.clone()); } - Node::GetField(ref obj, ref field) => { - let val_obj = obj.run(interpreter)?; - let val_field = field.run(interpreter)?; + Node::GetField(ref get_field) => { + let val_obj = get_field.obj().run(interpreter)?; + let val_field = get_field.field().run(interpreter)?; val_obj.set_field(val_field, val.clone()); } _ => (), @@ -123,12 +123,12 @@ impl Executable for BinOp { ); Ok(value) } - Node::GetConstField(ref obj, ref field) => { - let v_r_a = obj.run(interpreter)?; - let v_a = v_r_a.get_field(field); + Node::GetConstField(ref get_const_field) => { + let v_r_a = get_const_field.obj().run(interpreter)?; + let v_a = v_r_a.get_field(get_const_field.field()); let v_b = self.rhs().run(interpreter)?; let value = Self::run_assign(op, v_a, v_b); - v_r_a.set_field(&field.clone(), value.clone()); + v_r_a.set_field(get_const_field.field(), value.clone()); Ok(value) } _ => Ok(Value::undefined()), @@ -191,13 +191,8 @@ impl Executable for UnaryOp { } op::UnaryOp::Void => Value::undefined(), op::UnaryOp::Delete => match *self.target() { - Node::GetConstField(ref obj, ref field) => { - Value::boolean(obj.run(interpreter)?.remove_property(field)) - } - Node::GetField(ref obj, ref field) => Value::boolean( - obj.run(interpreter)? - .remove_property(&field.run(interpreter)?.to_string()), - ), + Node::GetConstField(ref get_const_field) => Value::boolean(get_const_field.obj().run(interpreter)?.remove_property(get_const_field.field())), + Node::GetField(ref get_field) => Value::boolean(get_field.obj().run(interpreter)?.remove_property(&get_field.field().run(interpreter)?.to_string())), Node::Identifier(_) => Value::boolean(false), Node::ArrayDecl(_) | Node::Block(_) diff --git a/boa/src/syntax/ast/node/field.rs b/boa/src/syntax/ast/node/field.rs index 03d07d4a7ee..6b84a9804a1 100644 --- a/boa/src/syntax/ast/node/field.rs +++ b/boa/src/syntax/ast/node/field.rs @@ -67,4 +67,68 @@ impl From for Node { fn from(get_const_field: GetConstField) -> Self { Self::GetConstField(get_const_field) } +} + +/// This property accessor provides access to an object's properties by using the +/// [bracket notation][mdn]. +/// +/// In the object[property_name] syntax, the property_name is just a string or +/// [Symbol][symbol]. So, it can be any string, including '1foo', '!bar!', or even ' ' (a +/// space). +/// +/// One can think of an object as an associative array (a.k.a. map, dictionary, hash, lookup +/// table). The keys in this array are the names of the object's properties. +/// +/// It's typical when speaking of an object's properties to make a distinction between +/// properties and methods. However, the property/method distinction is little more than a +/// convention. A method is simply a property that can be called (for example, if it has a +/// reference to a Function instance as its value). +/// +/// More information: +/// - [ECMAScript reference][spec] +/// - [MDN documentation][mdn] +/// +/// [spec]: https://tc39.es/ecma262/#sec-property-accessors +/// [symbol]: https://developer.mozilla.org/en-US/docs/Glossary/Symbol +/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Property_accessors#Bracket_notation +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +#[derive(Clone, Debug, Trace, Finalize, PartialEq)] +pub struct GetField { + obj: Box, + field: Box, +} + + +impl GetField { + pub fn obj(&self) -> &Node { + &self.obj + } + + pub fn field(&self) -> &Node { + &self.field + } + + /// Creates a `GetField` AST node. + pub fn new(value: V, field: F) -> Self + where + V: Into, + F: Into, + { + Self { + obj: Box::new(value.into()), + field: Box::new(field.into()), + } + } +} + +impl fmt::Display for GetField { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{}[{}]", self.obj(), self.field()) + } +} + +impl From for Node { + fn from(get_field: GetField) -> Self { + Self::GetField(get_field) + } } \ No newline at end of file diff --git a/boa/src/syntax/ast/node/mod.rs b/boa/src/syntax/ast/node/mod.rs index b34cc763001..c720c057cde 100644 --- a/boa/src/syntax/ast/node/mod.rs +++ b/boa/src/syntax/ast/node/mod.rs @@ -21,7 +21,7 @@ pub use self::{ LetDeclList, VarDecl, VarDeclList }, expression::{Call, New}, - field::GetConstField, + field::{GetConstField, GetField}, identifier::Identifier, iteration::ForLoop, object::Object, @@ -146,29 +146,8 @@ pub enum Node { /// Provides access to an object types' constant properties. [More information](./declaration/struct.GetConstField.html). GetConstField(GetConstField), - /// This property accessor provides access to an object's properties by using the - /// [bracket notation][mdn]. - /// - /// In the object[property_name] syntax, the property_name is just a string or - /// [Symbol][symbol]. So, it can be any string, including '1foo', '!bar!', or even ' ' (a - /// space). - /// - /// One can think of an object as an associative array (a.k.a. map, dictionary, hash, lookup - /// table). The keys in this array are the names of the object's properties. - /// - /// It's typical when speaking of an object's properties to make a distinction between - /// properties and methods. However, the property/method distinction is little more than a - /// convention. A method is simply a property that can be called (for example, if it has a - /// reference to a Function instance as its value). - /// - /// More information: - /// - [ECMAScript reference][spec] - /// - [MDN documentation][mdn] - /// - /// [spec]: https://tc39.es/ecma262/#sec-property-accessors - /// [symbol]: https://developer.mozilla.org/en-US/docs/Glossary/Symbol - /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Property_accessors#Bracket_notation - GetField(Box, Box), + /// Provides access to object fields. [More information](./declaration/struct.GetField.html). + GetField(GetField), /// A `for` statement. [More information](./iteration.struct.ForLoop.html). ForLoop(ForLoop), @@ -361,15 +340,6 @@ impl Node { Self::DoWhileLoop(Box::new(body.into()), Box::new(condition.into())) } - /// Creates a `GetField` AST node. - pub fn get_field(value: V, field: F) -> Self - where - V: Into, - F: Into, - { - Self::GetField(Box::new(value.into()), Box::new(field.into())) - } - /// Creates an `If` AST node. pub fn if_node(condition: C, body: B, else_node: OE) -> Self where @@ -462,7 +432,7 @@ impl Node { Self::Block(ref block) => block.display(f, indentation), Self::Identifier(ref s) => Display::fmt(s, f), Self::GetConstField(ref get_const_field) => Display::fmt(get_const_field, f), - Self::GetField(ref ex, ref field) => write!(f, "{}[{}]", ex, field), + Self::GetField(ref get_field) => Display::fmt(get_field, f), Self::Call(ref expr) => Display::fmt(expr, f), Self::New(ref expr) => Display::fmt(expr, f), Self::WhileLoop(ref cond, ref node) => { diff --git a/boa/src/syntax/parser/expression/left_hand_side/call.rs b/boa/src/syntax/parser/expression/left_hand_side/call.rs index 899b1cc5490..61ce294cd18 100644 --- a/boa/src/syntax/parser/expression/left_hand_side/call.rs +++ b/boa/src/syntax/parser/expression/left_hand_side/call.rs @@ -10,7 +10,7 @@ use super::arguments::Arguments; use crate::syntax::{ ast::{ - node::{Call, Node}, + node::{Call, Node, field::{GetConstField, GetField}}, Punctuator, TokenKind, }, parser::{ @@ -76,10 +76,10 @@ impl TokenParser for CallExpression { let _ = cursor.next().ok_or(ParseError::AbruptEnd)?; // We move the cursor. match &cursor.next().ok_or(ParseError::AbruptEnd)?.kind { TokenKind::Identifier(name) => { - lhs = Node::get_const_field(lhs, name.clone()); + lhs = GetConstField::new(lhs, name.clone()).into(); } TokenKind::Keyword(kw) => { - lhs = Node::get_const_field(lhs, kw.to_string()); + lhs = GetConstField::new(lhs, kw.to_string()).into(); } _ => { return Err(ParseError::expected( @@ -95,7 +95,7 @@ impl TokenParser for CallExpression { let idx = Expression::new(true, self.allow_yield, self.allow_await).parse(cursor)?; cursor.expect(Punctuator::CloseBracket, "call expression")?; - lhs = Node::get_field(lhs, idx); + lhs = GetField::new(lhs, idx).into(); } _ => break, } diff --git a/boa/src/syntax/parser/expression/left_hand_side/member.rs b/boa/src/syntax/parser/expression/left_hand_side/member.rs index de13301eaf3..94d3ce64241 100644 --- a/boa/src/syntax/parser/expression/left_hand_side/member.rs +++ b/boa/src/syntax/parser/expression/left_hand_side/member.rs @@ -8,7 +8,7 @@ use super::arguments::Arguments; use crate::syntax::{ ast::{ - node::{Call, New, Node}, + node::{Call, New, Node, field::{GetConstField, GetField}}, Keyword, Punctuator, TokenKind, }, parser::{ @@ -65,9 +65,9 @@ impl TokenParser for MemberExpression { let _ = cursor.next().ok_or(ParseError::AbruptEnd)?; // We move the cursor forward. match &cursor.next().ok_or(ParseError::AbruptEnd)?.kind { TokenKind::Identifier(name) => { - lhs = Node::get_const_field(lhs, name.clone()) + lhs = GetConstField::new(lhs, name.clone()).into() } - TokenKind::Keyword(kw) => lhs = Node::get_const_field(lhs, kw.to_string()), + TokenKind::Keyword(kw) => lhs = GetConstField::new(lhs, kw.to_string()).into(), _ => { return Err(ParseError::expected( vec![TokenKind::identifier("identifier")], @@ -82,7 +82,7 @@ impl TokenParser for MemberExpression { let idx = Expression::new(true, self.allow_yield, self.allow_await).parse(cursor)?; cursor.expect(Punctuator::CloseBracket, "member expression")?; - lhs = Node::get_field(lhs, idx); + lhs = GetField::new(lhs, idx).into(); } _ => break, } diff --git a/boa/src/syntax/parser/statement/iteration/tests.rs b/boa/src/syntax/parser/statement/iteration/tests.rs index 7830318907b..c129a306770 100644 --- a/boa/src/syntax/parser/statement/iteration/tests.rs +++ b/boa/src/syntax/parser/statement/iteration/tests.rs @@ -1,6 +1,6 @@ use crate::syntax::{ ast::{ - node::{BinOp, Block, Call, Identifier, Node, UnaryOp, VarDecl, VarDeclList}, + node::{BinOp, Block, Call, Identifier, Node, UnaryOp, VarDecl, VarDeclList, field::GetConstField}, op::{self, AssignOp, CompOp}, Const, }, @@ -36,7 +36,7 @@ fn check_do_while_semicolon_insertion() { VarDeclList::from(vec![VarDecl::new("i", Some(Const::from(0).into()))]).into(), Node::do_while_loop( Block::from(vec![Call::new( - Node::get_const_field(Identifier::from("console"), "log"), + GetConstField::new(Identifier::from("console"), "log"), vec![Const::from("hello").into()], ) .into()]), @@ -47,7 +47,7 @@ fn check_do_while_semicolon_insertion() { ), ), Call::new( - Node::get_const_field(Identifier::from("console"), "log"), + GetConstField::new(Identifier::from("console"), "log"), vec![Const::from("end").into()], ) .into(), diff --git a/boa/src/syntax/parser/tests.rs b/boa/src/syntax/parser/tests.rs index 071662835e1..2a8358e036d 100644 --- a/boa/src/syntax/parser/tests.rs +++ b/boa/src/syntax/parser/tests.rs @@ -5,7 +5,7 @@ use crate::syntax::{ ast::{ node::{ Assign, BinOp, Call, FunctionDecl, Identifier, New, Node, StatementList, UnaryOp, - VarDecl, VarDeclList, + VarDecl, VarDeclList, field::GetConstField, }, op::{self, NumOp}, Const, @@ -46,10 +46,7 @@ fn check_construct_call_precedence() { check_parser( "new Date().getTime()", vec![Node::from(Call::new( - Node::get_const_field( - New::from(Call::new(Identifier::from("Date"), vec![])), - "getTime", - ), + GetConstField::new(New::from(Call::new(Identifier::from("Date"), vec![])), "getTime",), vec![], ))], ); From e33a1a57a0a3994b7fd47ac10b9b9e7962e4ea02 Mon Sep 17 00:00:00 2001 From: Paul Lancaster Date: Fri, 29 May 2020 12:20:42 +0100 Subject: [PATCH 14/42] Fmt, clippy --- boa/src/exec/expression/mod.rs | 2 +- boa/src/exec/field/mod.rs | 2 -- boa/src/exec/mod.rs | 10 ++++++++-- boa/src/exec/operator/mod.rs | 16 +++++++++++++--- boa/src/syntax/ast/node/field.rs | 9 ++++----- boa/src/syntax/ast/node/mod.rs | 2 +- .../parser/expression/left_hand_side/call.rs | 5 ++++- .../parser/expression/left_hand_side/member.rs | 9 +++++++-- .../syntax/parser/statement/iteration/tests.rs | 5 ++++- boa/src/syntax/parser/tests.rs | 9 ++++++--- 10 files changed, 48 insertions(+), 21 deletions(-) diff --git a/boa/src/exec/expression/mod.rs b/boa/src/exec/expression/mod.rs index f063132f383..79348badf86 100644 --- a/boa/src/exec/expression/mod.rs +++ b/boa/src/exec/expression/mod.rs @@ -20,7 +20,7 @@ impl Executable for Call { .expect("failed to convert to object"); } (obj.clone(), obj.get_field(get_const_field.field())) - }, + } Node::GetField(ref get_field) => { let obj = get_field.obj().run(interpreter)?; let field = get_field.field().run(interpreter)?; diff --git a/boa/src/exec/field/mod.rs b/boa/src/exec/field/mod.rs index 7143ae14a91..259fda7bd7a 100644 --- a/boa/src/exec/field/mod.rs +++ b/boa/src/exec/field/mod.rs @@ -13,7 +13,6 @@ impl Executable for GetConstField { .expect("failed to convert to object"); } - Ok(obj.get_field(self.field())) } } @@ -26,4 +25,3 @@ impl Executable for GetField { Ok(obj.get_field(field.to_string())) } } - diff --git a/boa/src/exec/mod.rs b/boa/src/exec/mod.rs index f68e3b96994..a9ec0719350 100644 --- a/boa/src/exec/mod.rs +++ b/boa/src/exec/mod.rs @@ -356,8 +356,14 @@ impl Interpreter { .set_mutable_binding(name.as_ref(), value.clone(), true); Ok(value) } - Node::GetConstField(ref get_const_field_node) => Ok(get_const_field_node.obj().run(self)?.set_field(get_const_field_node.field(), value)), - Node::GetField(ref get_field) => Ok(get_field.obj().run(self)?.set_field(get_field.field().run(self)?, value)), + Node::GetConstField(ref get_const_field_node) => Ok(get_const_field_node + .obj() + .run(self)? + .set_field(get_const_field_node.field(), value)), + Node::GetField(ref get_field) => Ok(get_field + .obj() + .run(self)? + .set_field(get_field.field().run(self)?, value)), _ => panic!("TypeError: invalid assignment to {}", node), } } diff --git a/boa/src/exec/operator/mod.rs b/boa/src/exec/operator/mod.rs index beee5cc910e..a7b3797ad1a 100644 --- a/boa/src/exec/operator/mod.rs +++ b/boa/src/exec/operator/mod.rs @@ -5,7 +5,7 @@ use crate::{ builtins::value::{ResultValue, Value}, environment::lexical_environment::VariableScope, syntax::ast::{ - node::{Assign, BinOp, Node, UnaryOp, field::GetConstField}, + node::{field::GetConstField, Assign, BinOp, Node, UnaryOp}, op::{self, AssignOp, BitOp, CompOp, LogOp, NumOp}, }, }; @@ -191,8 +191,18 @@ impl Executable for UnaryOp { } op::UnaryOp::Void => Value::undefined(), op::UnaryOp::Delete => match *self.target() { - Node::GetConstField(ref get_const_field) => Value::boolean(get_const_field.obj().run(interpreter)?.remove_property(get_const_field.field())), - Node::GetField(ref get_field) => Value::boolean(get_field.obj().run(interpreter)?.remove_property(&get_field.field().run(interpreter)?.to_string())), + Node::GetConstField(ref get_const_field) => Value::boolean( + get_const_field + .obj() + .run(interpreter)? + .remove_property(get_const_field.field()), + ), + Node::GetField(ref get_field) => Value::boolean( + get_field + .obj() + .run(interpreter)? + .remove_property(&get_field.field().run(interpreter)?.to_string()), + ), Node::Identifier(_) => Value::boolean(false), Node::ArrayDecl(_) | Node::Block(_) diff --git a/boa/src/syntax/ast/node/field.rs b/boa/src/syntax/ast/node/field.rs index 6b84a9804a1..8577e0efef2 100644 --- a/boa/src/syntax/ast/node/field.rs +++ b/boa/src/syntax/ast/node/field.rs @@ -31,8 +31,8 @@ use serde::{Deserialize, Serialize}; #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[derive(Clone, Debug, Trace, Finalize, PartialEq)] pub struct GetConstField { - obj: Box, - field: Box + obj: Box, + field: Box, } impl GetConstField { @@ -94,11 +94,10 @@ impl From for Node { #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[derive(Clone, Debug, Trace, Finalize, PartialEq)] pub struct GetField { - obj: Box, + obj: Box, field: Box, } - impl GetField { pub fn obj(&self) -> &Node { &self.obj @@ -131,4 +130,4 @@ impl From for Node { fn from(get_field: GetField) -> Self { Self::GetField(get_field) } -} \ No newline at end of file +} diff --git a/boa/src/syntax/ast/node/mod.rs b/boa/src/syntax/ast/node/mod.rs index c720c057cde..8e812c62d4e 100644 --- a/boa/src/syntax/ast/node/mod.rs +++ b/boa/src/syntax/ast/node/mod.rs @@ -18,7 +18,7 @@ pub use self::{ block::Block, declaration::{ ArrowFunctionDecl, ConstDecl, ConstDeclList, FunctionDecl, FunctionExpr, LetDecl, - LetDeclList, VarDecl, VarDeclList + LetDeclList, VarDecl, VarDeclList, }, expression::{Call, New}, field::{GetConstField, GetField}, diff --git a/boa/src/syntax/parser/expression/left_hand_side/call.rs b/boa/src/syntax/parser/expression/left_hand_side/call.rs index 61ce294cd18..5d4fc48cce1 100644 --- a/boa/src/syntax/parser/expression/left_hand_side/call.rs +++ b/boa/src/syntax/parser/expression/left_hand_side/call.rs @@ -10,7 +10,10 @@ use super::arguments::Arguments; use crate::syntax::{ ast::{ - node::{Call, Node, field::{GetConstField, GetField}}, + node::{ + field::{GetConstField, GetField}, + Call, Node, + }, Punctuator, TokenKind, }, parser::{ diff --git a/boa/src/syntax/parser/expression/left_hand_side/member.rs b/boa/src/syntax/parser/expression/left_hand_side/member.rs index 94d3ce64241..51d8a5a04f1 100644 --- a/boa/src/syntax/parser/expression/left_hand_side/member.rs +++ b/boa/src/syntax/parser/expression/left_hand_side/member.rs @@ -8,7 +8,10 @@ use super::arguments::Arguments; use crate::syntax::{ ast::{ - node::{Call, New, Node, field::{GetConstField, GetField}}, + node::{ + field::{GetConstField, GetField}, + Call, New, Node, + }, Keyword, Punctuator, TokenKind, }, parser::{ @@ -67,7 +70,9 @@ impl TokenParser for MemberExpression { TokenKind::Identifier(name) => { lhs = GetConstField::new(lhs, name.clone()).into() } - TokenKind::Keyword(kw) => lhs = GetConstField::new(lhs, kw.to_string()).into(), + TokenKind::Keyword(kw) => { + lhs = GetConstField::new(lhs, kw.to_string()).into() + } _ => { return Err(ParseError::expected( vec![TokenKind::identifier("identifier")], diff --git a/boa/src/syntax/parser/statement/iteration/tests.rs b/boa/src/syntax/parser/statement/iteration/tests.rs index c129a306770..0c26d1c695a 100644 --- a/boa/src/syntax/parser/statement/iteration/tests.rs +++ b/boa/src/syntax/parser/statement/iteration/tests.rs @@ -1,6 +1,9 @@ use crate::syntax::{ ast::{ - node::{BinOp, Block, Call, Identifier, Node, UnaryOp, VarDecl, VarDeclList, field::GetConstField}, + node::{ + field::GetConstField, BinOp, Block, Call, Identifier, Node, UnaryOp, VarDecl, + VarDeclList, + }, op::{self, AssignOp, CompOp}, Const, }, diff --git a/boa/src/syntax/parser/tests.rs b/boa/src/syntax/parser/tests.rs index 2a8358e036d..8777baf3f6c 100644 --- a/boa/src/syntax/parser/tests.rs +++ b/boa/src/syntax/parser/tests.rs @@ -4,8 +4,8 @@ use super::Parser; use crate::syntax::{ ast::{ node::{ - Assign, BinOp, Call, FunctionDecl, Identifier, New, Node, StatementList, UnaryOp, - VarDecl, VarDeclList, field::GetConstField, + field::GetConstField, Assign, BinOp, Call, FunctionDecl, Identifier, New, Node, + StatementList, UnaryOp, VarDecl, VarDeclList, }, op::{self, NumOp}, Const, @@ -46,7 +46,10 @@ fn check_construct_call_precedence() { check_parser( "new Date().getTime()", vec![Node::from(Call::new( - GetConstField::new(New::from(Call::new(Identifier::from("Date"), vec![])), "getTime",), + GetConstField::new( + New::from(Call::new(Identifier::from("Date"), vec![])), + "getTime", + ), vec![], ))], ); From 4937dc32f3662ffd59be6a4a00c4e6df0124abd5 Mon Sep 17 00:00:00 2001 From: Paul Lancaster Date: Fri, 29 May 2020 14:54:34 +0100 Subject: [PATCH 15/42] WhileLoop seperated out --- boa/src/exec/iteration/mod.rs | 13 ++++- boa/src/exec/mod.rs | 8 +-- boa/src/syntax/ast/node/iteration.rs | 51 +++++++++++++++++++ boa/src/syntax/ast/node/mod.rs | 29 ++--------- boa/src/syntax/ast/node/statement_list.rs | 2 +- .../parser/statement/break_stm/tests.rs | 46 +++++++---------- .../parser/statement/continue_stm/tests.rs | 46 +++++++---------- .../statement/iteration/while_statement.rs | 4 +- 8 files changed, 108 insertions(+), 91 deletions(-) diff --git a/boa/src/exec/iteration/mod.rs b/boa/src/exec/iteration/mod.rs index ab1f8308d2f..6a3bc54a2de 100644 --- a/boa/src/exec/iteration/mod.rs +++ b/boa/src/exec/iteration/mod.rs @@ -4,8 +4,9 @@ use super::{Executable, Interpreter}; use crate::{ builtins::value::{ResultValue, Value}, environment::lexical_environment::new_declarative_environment, - syntax::ast::node::ForLoop, + syntax::ast::node::{ForLoop, WhileLoop}, }; +use std::borrow::Borrow; impl Executable for ForLoop { fn run(&self, interpreter: &mut Interpreter) -> ResultValue { @@ -40,3 +41,13 @@ impl Executable for ForLoop { Ok(Value::undefined()) } } + +impl Executable for WhileLoop { + fn run(&self, interpreter: &mut Interpreter) -> ResultValue { + let mut result = Value::undefined(); + while self.cond().run(interpreter)?.borrow().is_true() { + result = self.expr().run(interpreter)?; + } + Ok(result) + } +} diff --git a/boa/src/exec/mod.rs b/boa/src/exec/mod.rs index a9ec0719350..525969d6614 100644 --- a/boa/src/exec/mod.rs +++ b/boa/src/exec/mod.rs @@ -393,13 +393,7 @@ impl Executable for Node { Node::GetConstField(ref get_const_field_node) => get_const_field_node.run(interpreter), Node::GetField(ref get_field) => get_field.run(interpreter), Node::Call(ref expr) => expr.run(interpreter), - Node::WhileLoop(ref cond, ref expr) => { - let mut result = Value::undefined(); - while cond.run(interpreter)?.borrow().is_true() { - result = expr.run(interpreter)?; - } - Ok(result) - } + Node::WhileLoop(ref while_loop) => while_loop.run(interpreter), Node::DoWhileLoop(ref body, ref cond) => { let mut result = body.run(interpreter)?; while cond.run(interpreter)?.borrow().is_true() { diff --git a/boa/src/syntax/ast/node/iteration.rs b/boa/src/syntax/ast/node/iteration.rs index c1ec55c60a2..a9171fd3a96 100644 --- a/boa/src/syntax/ast/node/iteration.rs +++ b/boa/src/syntax/ast/node/iteration.rs @@ -137,3 +137,54 @@ impl InnerForLoop { &self.body } } + +/// The `while` statement creates a loop that executes a specified statement as long as the +/// test condition evaluates to `true`. +/// +/// The condition is evaluated before executing the statement. +/// +/// More information: +/// - [ECMAScript reference][spec] +/// - [MDN documentation][mdn] +/// +/// [spec]: https://tc39.es/ecma262/#prod-grammar-notation-WhileStatement +/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/while +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +#[derive(Clone, Debug, Trace, Finalize, PartialEq)] +pub struct WhileLoop { + cond: Box, + expr: Box, +} + +impl WhileLoop { + pub fn cond(&self) -> &Node { + &self.cond + } + + pub fn expr(&self) -> &Node { + &self.expr + } + + /// Creates a `WhileLoop` AST node. + pub fn new(condition: C, body: B) -> Self + where + C: Into, + B: Into, + { + Self { + cond: Box::new(condition.into()), + expr: Box::new(body.into()), + } + } + + pub(super) fn display(&self, f: &mut fmt::Formatter<'_>, indentation: usize) -> fmt::Result { + write!(f, "while ({}) ", self.cond())?; + self.expr().display(f, indentation) + } +} + +impl From for Node { + fn from(while_loop: WhileLoop) -> Self { + Self::WhileLoop(while_loop) + } +} diff --git a/boa/src/syntax/ast/node/mod.rs b/boa/src/syntax/ast/node/mod.rs index 8e812c62d4e..b2c6fa3a3f5 100644 --- a/boa/src/syntax/ast/node/mod.rs +++ b/boa/src/syntax/ast/node/mod.rs @@ -23,7 +23,7 @@ pub use self::{ expression::{Call, New}, field::{GetConstField, GetField}, identifier::Identifier, - iteration::ForLoop, + iteration::{ForLoop, WhileLoop}, object::Object, operator::{Assign, BinOp, UnaryOp}, statement_list::StatementList, @@ -261,18 +261,7 @@ pub enum Node { /// Array declaration node. [More information](./declaration/struct.VarDeclList.html). VarDeclList(VarDeclList), - /// The `while` statement creates a loop that executes a specified statement as long as the - /// test condition evaluates to `true`. - /// - /// The condition is evaluated before executing the statement. - /// - /// More information: - /// - [ECMAScript reference][spec] - /// - [MDN documentation][mdn] - /// - /// [spec]: https://tc39.es/ecma262/#prod-grammar-notation-WhileStatement - /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/while - WhileLoop(Box, Box), + WhileLoop(WhileLoop), } impl Display for Node { @@ -385,15 +374,6 @@ impl Node { Self::This } - /// Creates a `WhileLoop` AST node. - pub fn while_loop(condition: C, body: B) -> Self - where - C: Into, - B: Into, - { - Self::WhileLoop(Box::new(condition.into()), Box::new(body.into())) - } - /// Implements the display formatting with indentation. fn display(&self, f: &mut fmt::Formatter<'_>, indentation: usize) -> fmt::Result { let indent = " ".repeat(indentation); @@ -435,10 +415,7 @@ impl Node { Self::GetField(ref get_field) => Display::fmt(get_field, f), Self::Call(ref expr) => Display::fmt(expr, f), Self::New(ref expr) => Display::fmt(expr, f), - Self::WhileLoop(ref cond, ref node) => { - write!(f, "while ({}) ", cond)?; - node.display(f, indentation) - } + Self::WhileLoop(ref while_loop) => while_loop.display(f, indentation), Self::DoWhileLoop(ref node, ref cond) => { write!(f, "do")?; node.display(f, indentation)?; diff --git a/boa/src/syntax/ast/node/statement_list.rs b/boa/src/syntax/ast/node/statement_list.rs index 94815a2c7fd..b6a4423200e 100644 --- a/boa/src/syntax/ast/node/statement_list.rs +++ b/boa/src/syntax/ast/node/statement_list.rs @@ -37,7 +37,7 @@ impl StatementList { node.display(f, indentation + 1)?; match node { - Node::Block(_) | Node::If(_, _, _) | Node::Switch(_) | Node::WhileLoop(_, _) => {} + Node::Block(_) | Node::If(_, _, _) | Node::Switch(_) | Node::WhileLoop(_) => {} _ => write!(f, ";")?, } writeln!(f)?; diff --git a/boa/src/syntax/parser/statement/break_stm/tests.rs b/boa/src/syntax/parser/statement/break_stm/tests.rs index 47f960c12b4..9ba30104a3e 100644 --- a/boa/src/syntax/parser/statement/break_stm/tests.rs +++ b/boa/src/syntax/parser/statement/break_stm/tests.rs @@ -1,6 +1,6 @@ use crate::syntax::{ ast::{ - node::{Block, Node}, + node::{Block, Node, WhileLoop}, Const, }, parser::tests::check_parser, @@ -10,7 +10,7 @@ use crate::syntax::{ fn inline() { check_parser( "while (true) break;", - vec![Node::while_loop(Const::from(true), Node::Break(None))], + vec![WhileLoop::new(Const::from(true), Node::Break(None)).into()], ); } @@ -19,7 +19,7 @@ fn new_line() { check_parser( "while (true) break;", - vec![Node::while_loop(Const::from(true), Node::Break(None))], + vec![WhileLoop::new(Const::from(true), Node::Break(None)).into()], ); } @@ -27,10 +27,7 @@ fn new_line() { fn inline_block_semicolon_insertion() { check_parser( "while (true) {break}", - vec![Node::while_loop( - Const::from(true), - Block::from(vec![Node::Break(None)]), - )], + vec![WhileLoop::new(Const::from(true), Block::from(vec![Node::Break(None)])).into()], ); } @@ -40,10 +37,11 @@ fn new_line_semicolon_insertion() { "while (true) { break test }", - vec![Node::while_loop( + vec![WhileLoop::new( Const::from(true), Block::from(vec![Node::break_node("test")]), - )], + ) + .into()], ); } @@ -51,10 +49,7 @@ fn new_line_semicolon_insertion() { fn inline_block() { check_parser( "while (true) {break;}", - vec![Node::while_loop( - Const::from(true), - Block::from(vec![Node::Break(None)]), - )], + vec![WhileLoop::new(Const::from(true), Block::from(vec![Node::Break(None)])).into()], ); } @@ -64,10 +59,11 @@ fn new_line_block() { "while (true) { break test; }", - vec![Node::while_loop( + vec![WhileLoop::new( Const::from(true), Block::from(vec![Node::break_node("test")]), - )], + ) + .into()], ); } @@ -77,20 +73,22 @@ fn reserved_label() { "while (true) { break await; }", - vec![Node::while_loop( + vec![WhileLoop::new( Const::from(true), Block::from(vec![Node::break_node("await")]), - )], + ) + .into()], ); check_parser( "while (true) { break yield; }", - vec![Node::while_loop( + vec![WhileLoop::new( Const::from(true), Block::from(vec![Node::break_node("yield")]), - )], + ) + .into()], ); } @@ -100,10 +98,7 @@ fn new_line_block_empty() { "while (true) { break; }", - vec![Node::while_loop( - Const::from(true), - Block::from(vec![Node::Break(None)]), - )], + vec![WhileLoop::new(Const::from(true), Block::from(vec![Node::Break(None)])).into()], ); } @@ -113,9 +108,6 @@ fn new_line_block_empty_semicolon_insertion() { "while (true) { break }", - vec![Node::while_loop( - Const::from(true), - Block::from(vec![Node::Break(None)]), - )], + vec![WhileLoop::new(Const::from(true), Block::from(vec![Node::Break(None)])).into()], ); } diff --git a/boa/src/syntax/parser/statement/continue_stm/tests.rs b/boa/src/syntax/parser/statement/continue_stm/tests.rs index 564bde0a5ba..eca57628016 100644 --- a/boa/src/syntax/parser/statement/continue_stm/tests.rs +++ b/boa/src/syntax/parser/statement/continue_stm/tests.rs @@ -1,6 +1,6 @@ use crate::syntax::{ ast::{ - node::{Block, Node}, + node::{Block, Node, WhileLoop}, Const, }, parser::tests::check_parser, @@ -10,7 +10,7 @@ use crate::syntax::{ fn inline() { check_parser( "while (true) continue;", - vec![Node::while_loop(Const::from(true), Node::Continue(None))], + vec![WhileLoop::new(Const::from(true), Node::Continue(None)).into()], ); } @@ -19,7 +19,7 @@ fn new_line() { check_parser( "while (true) continue;", - vec![Node::while_loop(Const::from(true), Node::Continue(None))], + vec![WhileLoop::new(Const::from(true), Node::Continue(None)).into()], ); } @@ -27,10 +27,7 @@ fn new_line() { fn inline_block_semicolon_insertion() { check_parser( "while (true) {continue}", - vec![Node::while_loop( - Const::from(true), - Block::from(vec![Node::Continue(None)]), - )], + vec![WhileLoop::new(Const::from(true), Block::from(vec![Node::Continue(None)])).into()], ); } @@ -40,10 +37,11 @@ fn new_line_semicolon_insertion() { "while (true) { continue test }", - vec![Node::while_loop( + vec![WhileLoop::new( Const::from(true), Block::from(vec![Node::continue_node("test")]), - )], + ) + .into()], ); } @@ -51,10 +49,7 @@ fn new_line_semicolon_insertion() { fn inline_block() { check_parser( "while (true) {continue;}", - vec![Node::while_loop( - Const::from(true), - Block::from(vec![Node::Continue(None)]), - )], + vec![WhileLoop::new(Const::from(true), Block::from(vec![Node::Continue(None)])).into()], ); } @@ -64,10 +59,11 @@ fn new_line_block() { "while (true) { continue test; }", - vec![Node::while_loop( + vec![WhileLoop::new( Const::from(true), Block::from(vec![Node::continue_node("test")]), - )], + ) + .into()], ); } @@ -77,20 +73,22 @@ fn reserved_label() { "while (true) { continue await; }", - vec![Node::while_loop( + vec![WhileLoop::new( Const::from(true), Block::from(vec![Node::continue_node("await")]), - )], + ) + .into()], ); check_parser( "while (true) { continue yield; }", - vec![Node::while_loop( + vec![WhileLoop::new( Const::from(true), Block::from(vec![Node::continue_node("yield")]), - )], + ) + .into()], ); } @@ -100,10 +98,7 @@ fn new_line_block_empty() { "while (true) { continue; }", - vec![Node::while_loop( - Const::from(true), - Block::from(vec![Node::Continue(None)]), - )], + vec![WhileLoop::new(Const::from(true), Block::from(vec![Node::Continue(None)])).into()], ); } @@ -113,9 +108,6 @@ fn new_line_block_empty_semicolon_insertion() { "while (true) { continue }", - vec![Node::while_loop( - Const::from(true), - Block::from(vec![Node::Continue(None)]), - )], + vec![WhileLoop::new(Const::from(true), Block::from(vec![Node::Continue(None)])).into()], ); } diff --git a/boa/src/syntax/parser/statement/iteration/while_statement.rs b/boa/src/syntax/parser/statement/iteration/while_statement.rs index dd8040ae248..f8b97c64d77 100644 --- a/boa/src/syntax/parser/statement/iteration/while_statement.rs +++ b/boa/src/syntax/parser/statement/iteration/while_statement.rs @@ -1,5 +1,5 @@ use crate::syntax::{ - ast::{Keyword, Node, Punctuator}, + ast::{node::WhileLoop, Keyword, Node, Punctuator}, parser::{ expression::Expression, statement::Statement, AllowAwait, AllowReturn, AllowYield, Cursor, ParseResult, TokenParser, @@ -55,6 +55,6 @@ impl TokenParser for WhileStatement { let body = Statement::new(self.allow_yield, self.allow_await, self.allow_return).parse(cursor)?; - Ok(Node::while_loop(cond, body)) + Ok(WhileLoop::new(cond, body).into()) } } From ad075275d2cebc09fc80573a38fde145a17de20c Mon Sep 17 00:00:00 2001 From: Paul Lancaster Date: Fri, 29 May 2020 14:56:55 +0100 Subject: [PATCH 16/42] Impl fmt::display for WhileLoop --- boa/src/syntax/ast/node/iteration.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/boa/src/syntax/ast/node/iteration.rs b/boa/src/syntax/ast/node/iteration.rs index a9171fd3a96..9d8620050fa 100644 --- a/boa/src/syntax/ast/node/iteration.rs +++ b/boa/src/syntax/ast/node/iteration.rs @@ -183,6 +183,12 @@ impl WhileLoop { } } +impl fmt::Display for WhileLoop { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.display(f, 0) + } +} + impl From for Node { fn from(while_loop: WhileLoop) -> Self { Self::WhileLoop(while_loop) From be040706b5eb5ebb77f64815f92cd7d2ac87df7e Mon Sep 17 00:00:00 2001 From: Paul Lancaster Date: Fri, 29 May 2020 15:40:31 +0100 Subject: [PATCH 17/42] DoWhileLoop struct created --- boa/src/exec/iteration/mod.rs | 4 ++ boa/src/syntax/ast/node/iteration.rs | 60 ++++++++++++++++++++++++++++ boa/src/syntax/ast/node/mod.rs | 31 ++------------ 3 files changed, 67 insertions(+), 28 deletions(-) diff --git a/boa/src/exec/iteration/mod.rs b/boa/src/exec/iteration/mod.rs index 6a3bc54a2de..e468ed4d4d5 100644 --- a/boa/src/exec/iteration/mod.rs +++ b/boa/src/exec/iteration/mod.rs @@ -51,3 +51,7 @@ impl Executable for WhileLoop { Ok(result) } } + +impl Executable for DoWhileLoop { + +} \ No newline at end of file diff --git a/boa/src/syntax/ast/node/iteration.rs b/boa/src/syntax/ast/node/iteration.rs index 9d8620050fa..5fbfb8e52e7 100644 --- a/boa/src/syntax/ast/node/iteration.rs +++ b/boa/src/syntax/ast/node/iteration.rs @@ -194,3 +194,63 @@ impl From for Node { Self::WhileLoop(while_loop) } } + +/// The `do...while` statement creates a loop that executes a specified statement until the +/// test condition evaluates to false. +/// +/// The condition is evaluated after executing the statement, resulting in the specified +/// statement executing at least once. +/// +/// More information: +/// - [ECMAScript reference][spec] +/// - [MDN documentation][mdn] +/// +/// [spec]: https://tc39.es/ecma262/#sec-do-while-statement +/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/do...while +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +#[derive(Clone, Debug, Trace, Finalize, PartialEq)] +pub struct DoWhileLoop { + body: Box, + cond: Box, +} + +impl DoWhileLoop { + pub fn body(&self) -> &Node { + &self.body + } + + pub fn cond(&self) -> &Node { + &self.cond + } + + /// Creates a `DoWhileLoop` AST node. + pub fn new(body: B, condition: C) -> Self + where + B: Into, + C: Into, + { + Self { + body: Box::new(body.into()), + cond: Box::new(condition.into()), + } + } + + pub(super) fn display(&self, f: &mut fmt::Formatter<'_>, indentation: usize) -> fmt::Result { + write!(f, "do")?; + self.body().display(f, indentation)?; + write!(f, "while ({})", self.cond()) + } + +} + +impl fmt::Display for DoWhileLoop { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.display(f, 0) + } +} + +impl From for Node { + fn from(do_while: DoWhileLoop) -> Self { + Self::DoWhileLoop(do_while) + } +} \ No newline at end of file diff --git a/boa/src/syntax/ast/node/mod.rs b/boa/src/syntax/ast/node/mod.rs index b2c6fa3a3f5..6aa5d3faa3f 100644 --- a/boa/src/syntax/ast/node/mod.rs +++ b/boa/src/syntax/ast/node/mod.rs @@ -23,7 +23,7 @@ pub use self::{ expression::{Call, New}, field::{GetConstField, GetField}, identifier::Identifier, - iteration::{ForLoop, WhileLoop}, + iteration::{ForLoop, WhileLoop, DoWhileLoop}, object::Object, operator::{Assign, BinOp, UnaryOp}, statement_list::StatementList, @@ -123,19 +123,7 @@ pub enum Node { /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/continue Continue(Option>), - /// The `do...while` statement creates a loop that executes a specified statement until the - /// test condition evaluates to false. - /// - /// The condition is evaluated after executing the statement, resulting in the specified - /// statement executing at least once. - /// - /// More information: - /// - [ECMAScript reference][spec] - /// - [MDN documentation][mdn] - /// - /// [spec]: https://tc39.es/ecma262/#sec-do-while-statement - /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/do...while - DoWhileLoop(Box, Box), + DoWhileLoop(DoWhileLoop), /// A function declaration node. [More information](./declaration/struct.FunctionDecl.html). FunctionDecl(FunctionDecl), @@ -320,15 +308,6 @@ impl Node { Self::Continue(label.into().map(L::into)) } - /// Creates a `DoWhileLoop` AST node. - pub fn do_while_loop(body: B, condition: C) -> Self - where - B: Into, - C: Into, - { - Self::DoWhileLoop(Box::new(body.into()), Box::new(condition.into())) - } - /// Creates an `If` AST node. pub fn if_node(condition: C, body: B, else_node: OE) -> Self where @@ -416,11 +395,7 @@ impl Node { Self::Call(ref expr) => Display::fmt(expr, f), Self::New(ref expr) => Display::fmt(expr, f), Self::WhileLoop(ref while_loop) => while_loop.display(f, indentation), - Self::DoWhileLoop(ref node, ref cond) => { - write!(f, "do")?; - node.display(f, indentation)?; - write!(f, "while ({})", cond) - } + Self::DoWhileLoop(ref do_while) => do_while.display(f, indentation), Self::If(ref cond, ref node, None) => { write!(f, "if ({}) ", cond)?; node.display(f, indentation) From 58f83f73be32778ea4a8436797285af1934390a3 Mon Sep 17 00:00:00 2001 From: Paul Lancaster Date: Fri, 29 May 2020 23:19:21 +0100 Subject: [PATCH 18/42] Seperated out do while loop --- boa/src/exec/iteration/mod.rs | 12 +++++++++--- boa/src/exec/mod.rs | 8 +------- boa/src/syntax/ast/node/iteration.rs | 9 ++++----- boa/src/syntax/ast/node/mod.rs | 2 +- .../statement/iteration/do_while_statement.rs | 4 ++-- boa/src/syntax/parser/statement/iteration/tests.rs | 14 ++++++++------ 6 files changed, 25 insertions(+), 24 deletions(-) diff --git a/boa/src/exec/iteration/mod.rs b/boa/src/exec/iteration/mod.rs index e468ed4d4d5..fdfd48ad397 100644 --- a/boa/src/exec/iteration/mod.rs +++ b/boa/src/exec/iteration/mod.rs @@ -4,7 +4,7 @@ use super::{Executable, Interpreter}; use crate::{ builtins::value::{ResultValue, Value}, environment::lexical_environment::new_declarative_environment, - syntax::ast::node::{ForLoop, WhileLoop}, + syntax::ast::node::{DoWhileLoop, ForLoop, WhileLoop}, }; use std::borrow::Borrow; @@ -53,5 +53,11 @@ impl Executable for WhileLoop { } impl Executable for DoWhileLoop { - -} \ No newline at end of file + fn run(&self, interpreter: &mut Interpreter) -> ResultValue { + let mut result = self.body().run(interpreter)?; + while self.cond().run(interpreter)?.borrow().is_true() { + result = self.body().run(interpreter)?; + } + Ok(result) + } +} diff --git a/boa/src/exec/mod.rs b/boa/src/exec/mod.rs index 525969d6614..996a6823d45 100644 --- a/boa/src/exec/mod.rs +++ b/boa/src/exec/mod.rs @@ -394,13 +394,7 @@ impl Executable for Node { Node::GetField(ref get_field) => get_field.run(interpreter), Node::Call(ref expr) => expr.run(interpreter), Node::WhileLoop(ref while_loop) => while_loop.run(interpreter), - Node::DoWhileLoop(ref body, ref cond) => { - let mut result = body.run(interpreter)?; - while cond.run(interpreter)?.borrow().is_true() { - result = body.run(interpreter)?; - } - Ok(result) - } + Node::DoWhileLoop(ref do_while) => do_while.run(interpreter), Node::ForLoop(ref for_loop) => for_loop.run(interpreter), Node::If(ref cond, ref expr, None) => { Ok(if cond.run(interpreter)?.borrow().is_true() { diff --git a/boa/src/syntax/ast/node/iteration.rs b/boa/src/syntax/ast/node/iteration.rs index 5fbfb8e52e7..b4b71d6b346 100644 --- a/boa/src/syntax/ast/node/iteration.rs +++ b/boa/src/syntax/ast/node/iteration.rs @@ -210,7 +210,7 @@ impl From for Node { #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[derive(Clone, Debug, Trace, Finalize, PartialEq)] pub struct DoWhileLoop { - body: Box, + body: Box, cond: Box, } @@ -230,7 +230,7 @@ impl DoWhileLoop { C: Into, { Self { - body: Box::new(body.into()), + body: Box::new(body.into()), cond: Box::new(condition.into()), } } @@ -240,17 +240,16 @@ impl DoWhileLoop { self.body().display(f, indentation)?; write!(f, "while ({})", self.cond()) } - } impl fmt::Display for DoWhileLoop { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { self.display(f, 0) - } + } } impl From for Node { fn from(do_while: DoWhileLoop) -> Self { Self::DoWhileLoop(do_while) } -} \ No newline at end of file +} diff --git a/boa/src/syntax/ast/node/mod.rs b/boa/src/syntax/ast/node/mod.rs index 6aa5d3faa3f..2f02ada1042 100644 --- a/boa/src/syntax/ast/node/mod.rs +++ b/boa/src/syntax/ast/node/mod.rs @@ -23,7 +23,7 @@ pub use self::{ expression::{Call, New}, field::{GetConstField, GetField}, identifier::Identifier, - iteration::{ForLoop, WhileLoop, DoWhileLoop}, + iteration::{DoWhileLoop, ForLoop, WhileLoop}, object::Object, operator::{Assign, BinOp, UnaryOp}, statement_list::StatementList, diff --git a/boa/src/syntax/parser/statement/iteration/do_while_statement.rs b/boa/src/syntax/parser/statement/iteration/do_while_statement.rs index 5b71869af4e..331f29de947 100644 --- a/boa/src/syntax/parser/statement/iteration/do_while_statement.rs +++ b/boa/src/syntax/parser/statement/iteration/do_while_statement.rs @@ -8,7 +8,7 @@ //! [spec]: https://tc39.es/ecma262/#sec-do-while-statement use crate::syntax::{ - ast::{Keyword, Node, Punctuator, TokenKind}, + ast::{node::DoWhileLoop, Keyword, Node, Punctuator, TokenKind}, parser::{ expression::Expression, statement::Statement, AllowAwait, AllowReturn, AllowYield, Cursor, ParseError, ParseResult, TokenParser, @@ -77,6 +77,6 @@ impl TokenParser for DoWhileStatement { cursor.expect(Punctuator::CloseParen, "do while statement")?; cursor.expect_semicolon(true, "do while statement")?; - Ok(Node::do_while_loop(body, cond)) + Ok(DoWhileLoop::new(body, cond).into()) } } diff --git a/boa/src/syntax/parser/statement/iteration/tests.rs b/boa/src/syntax/parser/statement/iteration/tests.rs index 0c26d1c695a..744d954d0d2 100644 --- a/boa/src/syntax/parser/statement/iteration/tests.rs +++ b/boa/src/syntax/parser/statement/iteration/tests.rs @@ -1,8 +1,8 @@ use crate::syntax::{ ast::{ node::{ - field::GetConstField, BinOp, Block, Call, Identifier, Node, UnaryOp, VarDecl, - VarDeclList, + field::GetConstField, BinOp, Block, Call, DoWhileLoop, Identifier, Node, UnaryOp, + VarDecl, VarDeclList, }, op::{self, AssignOp, CompOp}, Const, @@ -17,7 +17,7 @@ fn check_do_while() { r#"do { a += 1; } while (true)"#, - vec![Node::do_while_loop( + vec![DoWhileLoop::new( Block::from(vec![BinOp::new( AssignOp::Add, Identifier::from("a"), @@ -25,7 +25,8 @@ fn check_do_while() { ) .into()]), Const::from(true), - )], + ) + .into()], ); } @@ -37,7 +38,7 @@ fn check_do_while_semicolon_insertion() { do {console.log("hello");} while(i++ < 10) console.log("end");"#, vec![ VarDeclList::from(vec![VarDecl::new("i", Some(Const::from(0).into()))]).into(), - Node::do_while_loop( + DoWhileLoop::new( Block::from(vec![Call::new( GetConstField::new(Identifier::from("console"), "log"), vec![Const::from("hello").into()], @@ -48,7 +49,8 @@ fn check_do_while_semicolon_insertion() { UnaryOp::new(op::UnaryOp::IncrementPost, Identifier::from("i")), Const::from(10), ), - ), + ) + .into(), Call::new( GetConstField::new(Identifier::from("console"), "log"), vec![Const::from("end").into()], From 13daec18a564fd118e5ee89ba8340312e0e5cfbf Mon Sep 17 00:00:00 2001 From: Paul Lancaster Date: Sat, 30 May 2020 12:51:46 +0100 Subject: [PATCH 19/42] Created Return struct --- boa/src/exec/mod.rs | 10 +---- boa/src/exec/return/mod.rs | 21 +++++++++++ boa/src/syntax/ast/node/mod.rs | 32 ++-------------- boa/src/syntax/ast/node/return_smt.rs | 54 +++++++++++++++++++++++++++ 4 files changed, 80 insertions(+), 37 deletions(-) create mode 100644 boa/src/exec/return/mod.rs create mode 100644 boa/src/syntax/ast/node/return_smt.rs diff --git a/boa/src/exec/mod.rs b/boa/src/exec/mod.rs index 996a6823d45..39d7694b556 100644 --- a/boa/src/exec/mod.rs +++ b/boa/src/exec/mod.rs @@ -421,15 +421,7 @@ impl Executable for Node { Node::BinOp(ref op) => op.run(interpreter), Node::UnaryOp(ref op) => op.run(interpreter), Node::New(ref call) => call.run(interpreter), - Node::Return(ref ret) => { - let result = match *ret { - Some(ref v) => v.run(interpreter), - None => Ok(Value::undefined()), - }; - // Set flag for return - interpreter.is_return = true; - result - } + Node::Return(ref ret) => ret.run(interpreter), Node::Throw(ref ex) => Err(ex.run(interpreter)?), Node::Assign(ref op) => op.run(interpreter), Node::VarDeclList(ref decl) => decl.run(interpreter), diff --git a/boa/src/exec/return/mod.rs b/boa/src/exec/return/mod.rs new file mode 100644 index 00000000000..be91f5394e2 --- /dev/null +++ b/boa/src/exec/return/mod.rs @@ -0,0 +1,21 @@ + +use super::{Executable, Interpreter}; +use crate::{ + builtins::{ + object::{INSTANCE_PROTOTYPE, PROTOTYPE}, + value::{ResultValue, Value, ValueData}, + }, + syntax::ast::node::{Call, New, Node}, +}; + +impl Executable for Return { + fn run(&self, interpreter: &mut Interpreter) -> ResultValue { + let result = match *self.ret() { + Some(ref v) => v.run(interpreter), + None => Ok(Value::undefined()), + }; + // Set flag for return + interpreter.is_return = true; + result + } +} \ No newline at end of file diff --git a/boa/src/syntax/ast/node/mod.rs b/boa/src/syntax/ast/node/mod.rs index 2f02ada1042..793b4dca51c 100644 --- a/boa/src/syntax/ast/node/mod.rs +++ b/boa/src/syntax/ast/node/mod.rs @@ -11,6 +11,7 @@ pub mod object; pub mod operator; pub mod statement_list; pub mod switch; +pub mod return_smt; pub mod try_node; pub use self::{ @@ -28,6 +29,7 @@ pub use self::{ operator::{Assign, BinOp, UnaryOp}, statement_list::StatementList, switch::Switch, + return_smt::Return, try_node::{Catch, Finally, Try}, }; use super::Const; @@ -170,25 +172,8 @@ pub enum Node { /// An object. [More information](./object/struct.Object.html). Object(Object), - /// The `return` statement ends function execution and specifies a value to be returned to the - /// function caller. - /// - /// Syntax: `return [expression];` - /// - /// `expression`: - /// > The expression whose value is to be returned. If omitted, `undefined` is returned - /// > nstead. - /// - /// When a `return` statement is used in a function body, the execution of the function is - /// stopped. If specified, a given value is returned to the function caller. - /// - /// More information: - /// - [ECMAScript reference][spec] - /// - [MDN documentation][mdn] - /// - /// [spec]: https://tc39.es/ecma262/#prod-ReturnStatement - /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/return - Return(Option>), + /// A return statement. [More information](./object/struct.Return.html). + Return(Return), Switch(Switch), @@ -323,15 +308,6 @@ impl Node { ) } - /// Creates a `Return` AST node. - pub fn return_node(expr: OE) -> Self - where - E: Into, - OE: Into>, - { - Self::Return(expr.into().map(E::into).map(Box::new)) - } - /// Creates a `Spread` AST node. pub fn spread(val: V) -> Self where diff --git a/boa/src/syntax/ast/node/return_smt.rs b/boa/src/syntax/ast/node/return_smt.rs new file mode 100644 index 00000000000..e385fb754ea --- /dev/null +++ b/boa/src/syntax/ast/node/return_smt.rs @@ -0,0 +1,54 @@ +use super::Node; +use gc::{Finalize, Trace}; +use std::fmt; + +#[cfg(feature = "serde")] +use serde::{Deserialize, Serialize}; + +/// The `return` statement ends function execution and specifies a value to be returned to the +/// function caller. +/// +/// Syntax: `return [expression];` +/// +/// `expression`: +/// > The expression whose value is to be returned. If omitted, `undefined` is returned +/// > instead. +/// +/// When a `return` statement is used in a function body, the execution of the function is +/// stopped. If specified, a given value is returned to the function caller. +/// +/// More information: +/// - [ECMAScript reference][spec] +/// - [MDN documentation][mdn] +/// +/// [spec]: https://tc39.es/ecma262/#prod-ReturnStatement + /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/return +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +#[cfg_attr(feature = "serde", serde(transparent))] +#[derive(Clone, Debug, Trace, Finalize, PartialEq)] +pub struct Return { + value: Option>, +} + +impl Return { + pub fn value(&self) -> &Option> { + &self.value + } + + /// Creates a `Return` AST node. + pub fn new(expr: OE) -> Self + where + E: Into, + OE: Into>, + { + Self { + value: expr.into().map(E::into).map(Box::new) + } + } +} + +impl From for Node { + fn from(return_smt: Return) -> Node { + Node::Return(return_smt) + } +} \ No newline at end of file From 211615284204fd432e0f73388ddb442ee513b18a Mon Sep 17 00:00:00 2001 From: Paul Lancaster Date: Sat, 30 May 2020 15:56:49 +0100 Subject: [PATCH 20/42] Seperated Return statement out --- boa/src/exec/mod.rs | 1 + boa/src/exec/{return => return_smt}/mod.rs | 12 +++------ boa/src/syntax/ast/node/mod.rs | 7 +++-- boa/src/syntax/ast/node/return_smt.rs | 21 ++++++++++----- .../expression/assignment/arrow_function.rs | 7 ++--- boa/src/syntax/parser/function/tests.rs | 26 +++++++++++-------- .../syntax/parser/statement/block/tests.rs | 7 ++--- .../syntax/parser/statement/return_stm/mod.rs | 6 ++--- boa/src/syntax/parser/tests.rs | 4 +-- 9 files changed, 51 insertions(+), 40 deletions(-) rename boa/src/exec/{return => return_smt}/mod.rs (62%) diff --git a/boa/src/exec/mod.rs b/boa/src/exec/mod.rs index 39d7694b556..6e6c0eb120a 100644 --- a/boa/src/exec/mod.rs +++ b/boa/src/exec/mod.rs @@ -8,6 +8,7 @@ mod field; mod iteration; mod object; mod operator; +mod return_smt; mod statement_list; mod switch; #[cfg(test)] diff --git a/boa/src/exec/return/mod.rs b/boa/src/exec/return_smt/mod.rs similarity index 62% rename from boa/src/exec/return/mod.rs rename to boa/src/exec/return_smt/mod.rs index be91f5394e2..a0ecc05bfbc 100644 --- a/boa/src/exec/return/mod.rs +++ b/boa/src/exec/return_smt/mod.rs @@ -1,16 +1,12 @@ - use super::{Executable, Interpreter}; use crate::{ - builtins::{ - object::{INSTANCE_PROTOTYPE, PROTOTYPE}, - value::{ResultValue, Value, ValueData}, - }, - syntax::ast::node::{Call, New, Node}, + builtins::value::{ResultValue, Value}, + syntax::ast::node::Return, }; impl Executable for Return { fn run(&self, interpreter: &mut Interpreter) -> ResultValue { - let result = match *self.ret() { + let result = match *self.expr() { Some(ref v) => v.run(interpreter), None => Ok(Value::undefined()), }; @@ -18,4 +14,4 @@ impl Executable for Return { interpreter.is_return = true; result } -} \ No newline at end of file +} diff --git a/boa/src/syntax/ast/node/mod.rs b/boa/src/syntax/ast/node/mod.rs index 793b4dca51c..887a0995e03 100644 --- a/boa/src/syntax/ast/node/mod.rs +++ b/boa/src/syntax/ast/node/mod.rs @@ -9,9 +9,9 @@ pub mod identifier; pub mod iteration; pub mod object; pub mod operator; +pub mod return_smt; pub mod statement_list; pub mod switch; -pub mod return_smt; pub mod try_node; pub use self::{ @@ -27,9 +27,9 @@ pub use self::{ iteration::{DoWhileLoop, ForLoop, WhileLoop}, object::Object, operator::{Assign, BinOp, UnaryOp}, + return_smt::Return, statement_list::StatementList, switch::Switch, - return_smt::Return, try_node::{Catch, Finally, Try}, }; use super::Const; @@ -392,8 +392,7 @@ impl Node { Self::ArrowFunctionDecl(ref decl) => decl.display(f, indentation), Self::BinOp(ref op) => Display::fmt(op, f), Self::UnaryOp(ref op) => Display::fmt(op, f), - Self::Return(Some(ref ex)) => write!(f, "return {}", ex), - Self::Return(None) => write!(f, "return"), + Self::Return(ref ret) => Display::fmt(ret, f), Self::Throw(ref ex) => write!(f, "throw {}", ex), Self::Assign(ref op) => Display::fmt(op, f), Self::LetDeclList(ref decl) => Display::fmt(decl, f), diff --git a/boa/src/syntax/ast/node/return_smt.rs b/boa/src/syntax/ast/node/return_smt.rs index e385fb754ea..23b80f16acb 100644 --- a/boa/src/syntax/ast/node/return_smt.rs +++ b/boa/src/syntax/ast/node/return_smt.rs @@ -22,17 +22,17 @@ use serde::{Deserialize, Serialize}; /// - [MDN documentation][mdn] /// /// [spec]: https://tc39.es/ecma262/#prod-ReturnStatement - /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/return +/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/return #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde", serde(transparent))] #[derive(Clone, Debug, Trace, Finalize, PartialEq)] pub struct Return { - value: Option>, + expr: Option>, } impl Return { - pub fn value(&self) -> &Option> { - &self.value + pub fn expr(&self) -> &Option> { + &self.expr } /// Creates a `Return` AST node. @@ -42,7 +42,7 @@ impl Return { OE: Into>, { Self { - value: expr.into().map(E::into).map(Box::new) + expr: expr.into().map(E::into).map(Box::new), } } } @@ -51,4 +51,13 @@ impl From for Node { fn from(return_smt: Return) -> Node { Node::Return(return_smt) } -} \ No newline at end of file +} + +impl fmt::Display for Return { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self.expr() { + Some(ex) => write!(f, "return {}", ex), + None => write!(f, "return"), + } + } +} diff --git a/boa/src/syntax/parser/expression/assignment/arrow_function.rs b/boa/src/syntax/parser/expression/assignment/arrow_function.rs index ccab9a104bc..cfc4e5b6c7e 100644 --- a/boa/src/syntax/parser/expression/assignment/arrow_function.rs +++ b/boa/src/syntax/parser/expression/assignment/arrow_function.rs @@ -10,7 +10,7 @@ use super::AssignmentExpression; use crate::syntax::{ ast::{ - node::{ArrowFunctionDecl, FormalParameter, Node, StatementList}, + node::{ArrowFunctionDecl, FormalParameter, Node, Return, StatementList}, Punctuator, TokenKind, }, parser::{ @@ -113,9 +113,10 @@ impl TokenParser for ConciseBody { cursor.expect(Punctuator::CloseBlock, "arrow function")?; Ok(body) } - _ => Ok(StatementList::from(vec![Node::return_node( + _ => Ok(StatementList::from(vec![Return::new( ExpressionBody::new(self.allow_in, false).parse(cursor)?, - )])), + ) + .into()])), } } } diff --git a/boa/src/syntax/parser/function/tests.rs b/boa/src/syntax/parser/function/tests.rs index 7e0b6c20868..7ca527a1210 100644 --- a/boa/src/syntax/parser/function/tests.rs +++ b/boa/src/syntax/parser/function/tests.rs @@ -1,5 +1,7 @@ use crate::syntax::{ - ast::node::{ArrowFunctionDecl, BinOp, FormalParameter, FunctionDecl, Identifier, Node}, + ast::node::{ + ArrowFunctionDecl, BinOp, FormalParameter, FunctionDecl, Identifier, Node, Return, + }, ast::op::NumOp, parser::tests::check_parser, }; @@ -12,7 +14,7 @@ fn check_basic() { vec![FunctionDecl::new( Box::from("foo"), vec![FormalParameter::new("a", None, false)], - vec![Node::return_node(Identifier::from("a"))], + vec![Return::new(Identifier::from("a")).into()], ) .into()], ); @@ -26,7 +28,7 @@ fn check_basic_semicolon_insertion() { vec![FunctionDecl::new( Box::from("foo"), vec![FormalParameter::new("a", None, false)], - vec![Node::return_node(Identifier::from("a"))], + vec![Return::new(Identifier::from("a")).into()], ) .into()], ); @@ -40,7 +42,7 @@ fn check_empty_return() { vec![FunctionDecl::new( Box::from("foo"), vec![FormalParameter::new("a", None, false)], - vec![Node::Return(None)], + vec![Return::new::>(None).into()], ) .into()], ); @@ -54,7 +56,7 @@ fn check_empty_return_semicolon_insertion() { vec![FunctionDecl::new( Box::from("foo"), vec![FormalParameter::new("a", None, false)], - vec![Node::Return(None)], + vec![Return::new::>(None).into()], ) .into()], ); @@ -113,11 +115,12 @@ fn check_arrow() { FormalParameter::new("a", None, false), FormalParameter::new("b", None, false), ], - vec![Node::return_node(BinOp::new( + vec![Return::new(BinOp::new( NumOp::Add, Identifier::from("a"), Identifier::from("b"), - ))], + )) + .into()], ) .into()], ); @@ -133,11 +136,12 @@ fn check_arrow_semicolon_insertion() { FormalParameter::new("a", None, false), FormalParameter::new("b", None, false), ], - vec![Node::return_node(BinOp::new( + vec![Return::new(BinOp::new( NumOp::Add, Identifier::from("a"), Identifier::from("b"), - ))], + )) + .into()], ) .into()], ); @@ -153,7 +157,7 @@ fn check_arrow_epty_return() { FormalParameter::new("a", None, false), FormalParameter::new("b", None, false), ], - vec![Node::Return(None)], + vec![Return::new::>(None).into()], ) .into()], ); @@ -169,7 +173,7 @@ fn check_arrow_empty_return_semicolon_insertion() { FormalParameter::new("a", None, false), FormalParameter::new("b", None, false), ], - vec![Node::Return(None)], + vec![Return::new::>(None).into()], ) .into()], ); diff --git a/boa/src/syntax/parser/statement/block/tests.rs b/boa/src/syntax/parser/statement/block/tests.rs index 34a748d1c5b..e0c1797c75c 100644 --- a/boa/src/syntax/parser/statement/block/tests.rs +++ b/boa/src/syntax/parser/statement/block/tests.rs @@ -3,7 +3,8 @@ use crate::syntax::{ ast::{ node::{ - Assign, Block, Call, FunctionDecl, Identifier, Node, UnaryOp, VarDecl, VarDeclList, + Assign, Block, Call, FunctionDecl, Identifier, Node, Return, UnaryOp, VarDecl, + VarDeclList, }, op, Const, }, @@ -50,7 +51,7 @@ fn non_empty() { FunctionDecl::new( "hello".to_owned().into_boxed_str(), vec![], - vec![Node::return_node(Const::from(10))], + vec![Return::new(Const::from(10)).into()], ) .into(), VarDeclList::from(vec![VarDecl::new( @@ -76,7 +77,7 @@ fn hoisting() { FunctionDecl::new( "hello".to_owned().into_boxed_str(), vec![], - vec![Node::return_node(Const::from(10))], + vec![Return::new(Const::from(10)).into()], ) .into(), VarDeclList::from(vec![VarDecl::new( diff --git a/boa/src/syntax/parser/statement/return_stm/mod.rs b/boa/src/syntax/parser/statement/return_stm/mod.rs index 096b3be17ae..58f3f543ce3 100644 --- a/boa/src/syntax/parser/statement/return_stm/mod.rs +++ b/boa/src/syntax/parser/statement/return_stm/mod.rs @@ -2,7 +2,7 @@ mod tests; use crate::syntax::{ - ast::{Keyword, Node, Punctuator, TokenKind}, + ast::{node::Return, Keyword, Node, Punctuator, TokenKind}, parser::{expression::Expression, AllowAwait, AllowYield, Cursor, ParseResult, TokenParser}, }; @@ -51,13 +51,13 @@ impl TokenParser for ReturnStatement { _ => {} } - return Ok(Node::Return(None)); + return Ok(Return::new::>(None).into()); } let expr = Expression::new(true, self.allow_yield, self.allow_await).parse(cursor)?; cursor.expect_semicolon(false, "return statement")?; - Ok(Node::return_node(expr)) + Ok(Return::new(expr).into()) } } diff --git a/boa/src/syntax/parser/tests.rs b/boa/src/syntax/parser/tests.rs index 8777baf3f6c..c5e83d03d26 100644 --- a/boa/src/syntax/parser/tests.rs +++ b/boa/src/syntax/parser/tests.rs @@ -4,7 +4,7 @@ use super::Parser; use crate::syntax::{ ast::{ node::{ - field::GetConstField, Assign, BinOp, Call, FunctionDecl, Identifier, New, Node, + field::GetConstField, Assign, BinOp, Call, FunctionDecl, Identifier, New, Node, Return, StatementList, UnaryOp, VarDecl, VarDeclList, }, op::{self, NumOp}, @@ -79,7 +79,7 @@ fn hoisting() { FunctionDecl::new( Box::from("hello"), vec![], - vec![Node::return_node(Const::from(10))], + vec![Return::new(Const::from(10)).into()], ) .into(), VarDeclList::from(vec![VarDecl::new( From cc7261a095fe3e334b91864216f352c77736e1ad Mon Sep 17 00:00:00 2001 From: Paul Lancaster Date: Sat, 30 May 2020 22:13:07 +0100 Subject: [PATCH 21/42] Seperated IF statement out --- boa/src/exec/conditional/mod.rs | 19 +++++ boa/src/exec/mod.rs | 16 +--- boa/src/syntax/ast/node/conditional.rs | 83 +++++++++++++++++++ boa/src/syntax/ast/node/mod.rs | 48 ++--------- boa/src/syntax/ast/node/statement_list.rs | 2 +- boa/src/syntax/parser/statement/if_stm/mod.rs | 4 +- .../syntax/parser/statement/if_stm/tests.rs | 14 +--- .../parser/statement/iteration/tests.rs | 4 +- 8 files changed, 117 insertions(+), 73 deletions(-) create mode 100644 boa/src/exec/conditional/mod.rs create mode 100644 boa/src/syntax/ast/node/conditional.rs diff --git a/boa/src/exec/conditional/mod.rs b/boa/src/exec/conditional/mod.rs new file mode 100644 index 00000000000..582f9bdc212 --- /dev/null +++ b/boa/src/exec/conditional/mod.rs @@ -0,0 +1,19 @@ +use super::{Executable, Interpreter}; +use crate::{ + builtins::{ResultValue, Value}, + syntax::ast::node::If, +}; +use std::borrow::Borrow; + +impl Executable for If { + fn run(&self, interpreter: &mut Interpreter) -> ResultValue { + Ok(if self.cond().run(interpreter)?.borrow().is_true() { + self.body().run(interpreter)? + } else { + match self.else_node() { + Some(ref else_e) => else_e.run(interpreter)?, + None => Value::undefined(), + } + }) + } +} diff --git a/boa/src/exec/mod.rs b/boa/src/exec/mod.rs index 6e6c0eb120a..c48fd00a995 100644 --- a/boa/src/exec/mod.rs +++ b/boa/src/exec/mod.rs @@ -2,6 +2,7 @@ mod array; mod block; +mod conditional; mod declaration; mod expression; mod field; @@ -397,20 +398,7 @@ impl Executable for Node { Node::WhileLoop(ref while_loop) => while_loop.run(interpreter), Node::DoWhileLoop(ref do_while) => do_while.run(interpreter), Node::ForLoop(ref for_loop) => for_loop.run(interpreter), - Node::If(ref cond, ref expr, None) => { - Ok(if cond.run(interpreter)?.borrow().is_true() { - expr.run(interpreter)? - } else { - Value::undefined() - }) - } - Node::If(ref cond, ref expr, Some(ref else_e)) => { - Ok(if cond.run(interpreter)?.borrow().is_true() { - expr.run(interpreter)? - } else { - else_e.run(interpreter)? - }) - } + Node::If(ref if_smt) => if_smt.run(interpreter), Node::Switch(ref switch) => switch.run(interpreter), Node::Object(ref obj) => obj.run(interpreter), Node::ArrayDecl(ref arr) => arr.run(interpreter), diff --git a/boa/src/syntax/ast/node/conditional.rs b/boa/src/syntax/ast/node/conditional.rs new file mode 100644 index 00000000000..b3fbb9a46d0 --- /dev/null +++ b/boa/src/syntax/ast/node/conditional.rs @@ -0,0 +1,83 @@ +use super::{join_nodes, FormalParameter, Identifier, Node, StatementList}; +use gc::{Finalize, Trace}; +use std::fmt; + +#[cfg(feature = "serde")] +use serde::{Deserialize, Serialize}; + +/// The `if` statement executes a statement if a specified condition is [`truthy`][truthy]. If +/// the condition is [`falsy`][falsy], another statement can be executed. +/// +/// Multiple `if...else` statements can be nested to create an else if clause. +/// +/// Note that there is no elseif (in one word) keyword in JavaScript. +/// +/// More information: +/// - [ECMAScript reference][spec] +/// - [MDN documentation][mdn] +/// +/// [spec]: https://tc39.es/ecma262/#prod-IfStatement +/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/if...else +/// [truthy]: https://developer.mozilla.org/en-US/docs/Glossary/truthy +/// [falsy]: https://developer.mozilla.org/en-US/docs/Glossary/falsy +/// [expression]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Expressions_and_Operators#Expressions +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +#[derive(Clone, Debug, Trace, Finalize, PartialEq)] +pub struct If { + cond: Box, + body: Box, + else_node: Option>, +} + +impl If { + pub fn cond(&self) -> &Node { + &self.cond + } + + pub fn body(&self) -> &Node { + &self.body + } + + pub fn else_node(&self) -> &Option> { + &self.else_node + } + + /// Creates an `If` AST node. + pub fn new(condition: C, body: B, else_node: OE) -> Self + where + C: Into, + B: Into, + E: Into, + OE: Into>, + { + Self { + cond: Box::new(condition.into()), + body: Box::new(body.into()), + else_node: else_node.into().map(E::into).map(Box::new), + } + } + + pub(super) fn display(&self, f: &mut fmt::Formatter<'_>, indent: usize) -> fmt::Result { + write!(f, "if ({}) ", self.cond())?; + match self.else_node() { + Some(else_e) => { + self.body().display(f, indent); + f.write_str(" else ")?; + else_e.display(f, indent) + } + None => self.body().display(f, indent), + } + } +} + +impl fmt::Display for If { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.display(f, 0) + } +} + +impl From for Node { + fn from(if_stm: If) -> Node { + Self::If(if_stm) + } +} diff --git a/boa/src/syntax/ast/node/mod.rs b/boa/src/syntax/ast/node/mod.rs index 887a0995e03..3cdc780ca3d 100644 --- a/boa/src/syntax/ast/node/mod.rs +++ b/boa/src/syntax/ast/node/mod.rs @@ -2,6 +2,7 @@ pub mod array; pub mod block; +pub mod conditional; pub mod declaration; pub mod expression; pub mod field; @@ -17,6 +18,7 @@ pub mod try_node; pub use self::{ array::ArrayDecl, block::Block, + conditional::If, declaration::{ ArrowFunctionDecl, ConstDecl, ConstDeclList, FunctionDecl, FunctionExpr, LetDecl, LetDeclList, VarDecl, VarDeclList, @@ -142,23 +144,8 @@ pub enum Node { /// A `for` statement. [More information](./iteration.struct.ForLoop.html). ForLoop(ForLoop), - /// The `if` statement executes a statement if a specified condition is [`truthy`][truthy]. If - /// the condition is [`falsy`][falsy], another statement can be executed. - /// - /// Multiple `if...else` statements can be nested to create an else if clause. - /// - /// Note that there is no elseif (in one word) keyword in JavaScript. - /// - /// More information: - /// - [ECMAScript reference][spec] - /// - [MDN documentation][mdn] - /// - /// [spec]: https://tc39.es/ecma262/#prod-IfStatement - /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/if...else - /// [truthy]: https://developer.mozilla.org/en-US/docs/Glossary/truthy - /// [falsy]: https://developer.mozilla.org/en-US/docs/Glossary/falsy - /// [expression]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Expressions_and_Operators#Expressions - If(Box, Box, Option>), + /// An 'if' statement. [More information](./conditional.struct.If.html). + If(If), /// A `let` declaration list. [More information](./declaration/struct.LetDeclList.html). LetDeclList(LetDeclList), @@ -293,21 +280,6 @@ impl Node { Self::Continue(label.into().map(L::into)) } - /// Creates an `If` AST node. - pub fn if_node(condition: C, body: B, else_node: OE) -> Self - where - C: Into, - B: Into, - E: Into, - OE: Into>, - { - Self::If( - Box::new(condition.into()), - Box::new(body.into()), - else_node.into().map(E::into).map(Box::new), - ) - } - /// Creates a `Spread` AST node. pub fn spread(val: V) -> Self where @@ -372,17 +344,7 @@ impl Node { Self::New(ref expr) => Display::fmt(expr, f), Self::WhileLoop(ref while_loop) => while_loop.display(f, indentation), Self::DoWhileLoop(ref do_while) => do_while.display(f, indentation), - Self::If(ref cond, ref node, None) => { - write!(f, "if ({}) ", cond)?; - node.display(f, indentation) - } - Self::If(ref cond, ref node, Some(ref else_e)) => { - write!(f, "if ({}) ", cond)?; - node.display(f, indentation)?; - f.write_str(" else ")?; - else_e.display(f, indentation) - } - + Self::If(ref if_smt) => if_smt.display(f, indentation), Self::Switch(ref switch) => switch.display(f, indentation), Self::Object(ref obj) => obj.display(f, indentation), Self::ArrayDecl(ref arr) => Display::fmt(arr, f), diff --git a/boa/src/syntax/ast/node/statement_list.rs b/boa/src/syntax/ast/node/statement_list.rs index b6a4423200e..b6b388f03c9 100644 --- a/boa/src/syntax/ast/node/statement_list.rs +++ b/boa/src/syntax/ast/node/statement_list.rs @@ -37,7 +37,7 @@ impl StatementList { node.display(f, indentation + 1)?; match node { - Node::Block(_) | Node::If(_, _, _) | Node::Switch(_) | Node::WhileLoop(_) => {} + Node::Block(_) | Node::If(_) | Node::Switch(_) | Node::WhileLoop(_) => {} _ => write!(f, ";")?, } writeln!(f)?; diff --git a/boa/src/syntax/parser/statement/if_stm/mod.rs b/boa/src/syntax/parser/statement/if_stm/mod.rs index 7d7f95785bb..41a54ea3392 100644 --- a/boa/src/syntax/parser/statement/if_stm/mod.rs +++ b/boa/src/syntax/parser/statement/if_stm/mod.rs @@ -3,7 +3,7 @@ mod tests; use super::Statement; use crate::syntax::{ - ast::{Keyword, Node, Punctuator, TokenKind}, + ast::{node::If, Keyword, Node, Punctuator, TokenKind}, parser::{ expression::Expression, AllowAwait, AllowReturn, AllowYield, Cursor, ParseResult, TokenParser, @@ -68,6 +68,6 @@ impl TokenParser for IfStatement { _ => None, }; - Ok(Node::if_node::<_, _, Node, _>(cond, then_stm, else_stm)) + Ok(If::new::<_, _, Node, _>(cond, then_stm, else_stm).into()) } } diff --git a/boa/src/syntax/parser/statement/if_stm/tests.rs b/boa/src/syntax/parser/statement/if_stm/tests.rs index eb6fdd7951d..852ce4a8396 100644 --- a/boa/src/syntax/parser/statement/if_stm/tests.rs +++ b/boa/src/syntax/parser/statement/if_stm/tests.rs @@ -1,6 +1,6 @@ use crate::syntax::{ ast::{ - node::{Block, Node}, + node::{Block, If, Node}, Const, }, parser::tests::check_parser, @@ -10,11 +10,7 @@ use crate::syntax::{ fn if_without_else_block() { check_parser( "if (true) {}", - vec![Node::if_node::<_, _, Node, _>( - Const::from(true), - Block::from(Vec::new()), - None, - )], + vec![If::new::<_, _, Node, _>(Const::from(true), Block::from(Vec::new()), None).into()], ); } @@ -22,10 +18,6 @@ fn if_without_else_block() { fn if_without_else_block_with_trailing_newline() { check_parser( "if (true) {}\n", - vec![Node::if_node::<_, _, Node, _>( - Const::from(true), - Block::from(Vec::new()), - None, - )], + vec![If::new::<_, _, Node, _>(Const::from(true), Block::from(Vec::new()), None).into()], ); } diff --git a/boa/src/syntax/parser/statement/iteration/tests.rs b/boa/src/syntax/parser/statement/iteration/tests.rs index 744d954d0d2..06c00772aab 100644 --- a/boa/src/syntax/parser/statement/iteration/tests.rs +++ b/boa/src/syntax/parser/statement/iteration/tests.rs @@ -1,8 +1,8 @@ use crate::syntax::{ ast::{ node::{ - field::GetConstField, BinOp, Block, Call, DoWhileLoop, Identifier, Node, UnaryOp, - VarDecl, VarDeclList, + field::GetConstField, BinOp, Block, Call, DoWhileLoop, Identifier, UnaryOp, VarDecl, + VarDeclList, }, op::{self, AssignOp, CompOp}, Const, From c858a79bcc44c5ab000fe5931420521d73182f92 Mon Sep 17 00:00:00 2001 From: Paul Lancaster Date: Sat, 30 May 2020 22:15:07 +0100 Subject: [PATCH 22/42] Removed unused imports, fmt --- boa/src/exec/operator/mod.rs | 2 +- boa/src/syntax/ast/node/conditional.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/boa/src/exec/operator/mod.rs b/boa/src/exec/operator/mod.rs index a7b3797ad1a..86abf2c147c 100644 --- a/boa/src/exec/operator/mod.rs +++ b/boa/src/exec/operator/mod.rs @@ -5,7 +5,7 @@ use crate::{ builtins::value::{ResultValue, Value}, environment::lexical_environment::VariableScope, syntax::ast::{ - node::{field::GetConstField, Assign, BinOp, Node, UnaryOp}, + node::{Assign, BinOp, Node, UnaryOp}, op::{self, AssignOp, BitOp, CompOp, LogOp, NumOp}, }, }; diff --git a/boa/src/syntax/ast/node/conditional.rs b/boa/src/syntax/ast/node/conditional.rs index b3fbb9a46d0..9b0776c5f31 100644 --- a/boa/src/syntax/ast/node/conditional.rs +++ b/boa/src/syntax/ast/node/conditional.rs @@ -1,4 +1,4 @@ -use super::{join_nodes, FormalParameter, Identifier, Node, StatementList}; +use super::Node; use gc::{Finalize, Trace}; use std::fmt; @@ -61,7 +61,7 @@ impl If { write!(f, "if ({}) ", self.cond())?; match self.else_node() { Some(else_e) => { - self.body().display(f, indent); + self.body().display(f, indent)?; f.write_str(" else ")?; else_e.display(f, indent) } From b5ca4b88eb5591ba75d260fb71f9b49e0f486766 Mon Sep 17 00:00:00 2001 From: Paul Lancaster Date: Sat, 30 May 2020 23:02:54 +0100 Subject: [PATCH 23/42] Created Break struct --- boa/src/syntax/ast/node/break_node.rs | 61 +++++++++++++++++++ boa/src/syntax/ast/node/mod.rs | 38 ++---------- .../syntax/parser/statement/break_stm/mod.rs | 4 +- .../parser/statement/break_stm/tests.rs | 16 ++--- 4 files changed, 76 insertions(+), 43 deletions(-) create mode 100644 boa/src/syntax/ast/node/break_node.rs diff --git a/boa/src/syntax/ast/node/break_node.rs b/boa/src/syntax/ast/node/break_node.rs new file mode 100644 index 00000000000..e7b3a79f522 --- /dev/null +++ b/boa/src/syntax/ast/node/break_node.rs @@ -0,0 +1,61 @@ +use super::Node; +use gc::{Finalize, Trace}; +use std::fmt; + +#[cfg(feature = "serde")] +use serde::{Deserialize, Serialize}; + +/// The `break` statement terminates the current loop, switch, or label statement and transfers +/// program control to the statement following the terminated statement. +/// +/// The break statement includes an optional label that allows the program to break out of a +/// labeled statement. The break statement needs to be nested within the referenced label. The +/// labeled statement can be any block statement; it does not have to be preceded by a loop +/// statement. +/// +/// More information: +/// - [ECMAScript reference][spec] +/// - [MDN documentation][mdn] +/// +/// [spec]: https://tc39.es/ecma262/#prod-BreakStatement +/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/break +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +#[derive(Clone, Debug, Trace, Finalize, PartialEq)] +pub struct Break { + label: Option> +} + +impl Break { + pub fn label(&self) -> &Option> { + &self.label + } + + /// Creates a `Break` AST node. + pub fn new(label: OL) -> Self + where + L: Into>, + OL: Into>, + { + Self { + label: label.into().map(L::into) + } + } +} + +impl fmt::Display for Break { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "break{}", + if self.label().is_some() { + format!(" {}", self.label().unwrap()) + } else { + String::new() + } + ) + } +} + +impl From for Node { + fn from(break_smt: Break) -> Node { + Self::Break(break_smt) + } +} \ No newline at end of file diff --git a/boa/src/syntax/ast/node/mod.rs b/boa/src/syntax/ast/node/mod.rs index 3cdc780ca3d..d8bf2ea363c 100644 --- a/boa/src/syntax/ast/node/mod.rs +++ b/boa/src/syntax/ast/node/mod.rs @@ -2,6 +2,7 @@ pub mod array; pub mod block; +pub mod break_node; pub mod conditional; pub mod declaration; pub mod expression; @@ -18,6 +19,7 @@ pub mod try_node; pub use self::{ array::ArrayDecl, block::Block, + break_node::Break, conditional::If, declaration::{ ArrowFunctionDecl, ConstDecl, ConstDeclList, FunctionDecl, FunctionExpr, LetDecl, @@ -62,21 +64,8 @@ pub enum Node { /// A Block node. [More information](./block/struct.Block.html). Block(Block), - /// The `break` statement terminates the current loop, switch, or label statement and transfers - /// program control to the statement following the terminated statement. - /// - /// The break statement includes an optional label that allows the program to break out of a - /// labeled statement. The break statement needs to be nested within the referenced label. The - /// labeled statement can be any block statement; it does not have to be preceded by a loop - /// statement. - /// - /// More information: - /// - [ECMAScript reference][spec] - /// - [MDN documentation][mdn] - /// - /// [spec]: https://tc39.es/ecma262/#prod-BreakStatement - /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/break - Break(Option>), + /// A break node. [More information](./break/struct.Break.html). + Break(Break), /// A function call. [More information](./expression/struct.Call.html). Call(Call), @@ -248,15 +237,6 @@ impl Node { } } - /// Creates a `Break` AST node. - pub fn break_node(label: OL) -> Self - where - L: Into>, - OL: Into>, - { - Self::Break(label.into().map(L::into)) - } - /// Creates a `ConditionalOp` AST node. pub fn conditional_op(condition: C, if_true: T, if_false: F) -> Self where @@ -317,15 +297,7 @@ impl Node { Self::ForLoop(ref for_loop) => for_loop.display(f, indentation), Self::This => write!(f, "this"), Self::Try(ref try_catch) => try_catch.display(f, indentation), - Self::Break(ref l) => write!( - f, - "break{}", - if let Some(label) = l { - format!(" {}", label) - } else { - String::new() - } - ), + Self::Break(ref break_smt) => Display::fmt(break_smt, f), Self::Continue(ref l) => write!( f, "continue{}", diff --git a/boa/src/syntax/parser/statement/break_stm/mod.rs b/boa/src/syntax/parser/statement/break_stm/mod.rs index d203097b059..12642c9f97e 100644 --- a/boa/src/syntax/parser/statement/break_stm/mod.rs +++ b/boa/src/syntax/parser/statement/break_stm/mod.rs @@ -12,7 +12,7 @@ mod tests; use super::LabelIdentifier; use crate::syntax::{ - ast::{Keyword, Node, Punctuator, TokenKind}, + ast::{Keyword, Node, Punctuator, TokenKind, node::Break}, parser::{AllowAwait, AllowYield, Cursor, ParseResult, TokenParser}, }; @@ -66,6 +66,6 @@ impl TokenParser for BreakStatement { Some(label) }; - Ok(Node::Break(label)) + Ok(Break::new(label).into()) } } diff --git a/boa/src/syntax/parser/statement/break_stm/tests.rs b/boa/src/syntax/parser/statement/break_stm/tests.rs index 9ba30104a3e..de5a320635f 100644 --- a/boa/src/syntax/parser/statement/break_stm/tests.rs +++ b/boa/src/syntax/parser/statement/break_stm/tests.rs @@ -1,6 +1,6 @@ use crate::syntax::{ ast::{ - node::{Block, Node, WhileLoop}, + node::{Block, Node, WhileLoop, Break}, Const, }, parser::tests::check_parser, @@ -39,7 +39,7 @@ fn new_line_semicolon_insertion() { }", vec![WhileLoop::new( Const::from(true), - Block::from(vec![Node::break_node("test")]), + Block::from(vec![Break::new("test").into()]), ) .into()], ); @@ -49,7 +49,7 @@ fn new_line_semicolon_insertion() { fn inline_block() { check_parser( "while (true) {break;}", - vec![WhileLoop::new(Const::from(true), Block::from(vec![Node::Break(None)])).into()], + vec![WhileLoop::new(Const::from(true), Block::from(vec![Break::new(None).into()])).into()], ); } @@ -61,7 +61,7 @@ fn new_line_block() { }", vec![WhileLoop::new( Const::from(true), - Block::from(vec![Node::break_node("test")]), + Block::from(vec![Break::new("test").into()]), ) .into()], ); @@ -75,7 +75,7 @@ fn reserved_label() { }", vec![WhileLoop::new( Const::from(true), - Block::from(vec![Node::break_node("await")]), + Block::from(vec![Break::new("await").into()]), ) .into()], ); @@ -86,7 +86,7 @@ fn reserved_label() { }", vec![WhileLoop::new( Const::from(true), - Block::from(vec![Node::break_node("yield")]), + Block::from(vec![Break::new("yield").into()]), ) .into()], ); @@ -98,7 +98,7 @@ fn new_line_block_empty() { "while (true) { break; }", - vec![WhileLoop::new(Const::from(true), Block::from(vec![Node::Break(None)])).into()], + vec![WhileLoop::new(Const::from(true), Block::from(vec![Break::new(None).into()])).into()], ); } @@ -108,6 +108,6 @@ fn new_line_block_empty_semicolon_insertion() { "while (true) { break }", - vec![WhileLoop::new(Const::from(true), Block::from(vec![Node::Break(None)])).into()], + vec![WhileLoop::new(Const::from(true), Block::from(vec![Break::new(None).into()])).into()], ); } From 94dcacc9b79c5b201bdd1c23f3347eb68ba447e4 Mon Sep 17 00:00:00 2001 From: Paul Lancaster Date: Sun, 31 May 2020 14:58:01 +0100 Subject: [PATCH 24/42] Break impl --- boa/src/syntax/ast/node/break_node.rs | 12 ++++--- .../syntax/parser/statement/break_stm/mod.rs | 4 +-- .../parser/statement/break_stm/tests.rs | 34 +++++++++++++++---- 3 files changed, 36 insertions(+), 14 deletions(-) diff --git a/boa/src/syntax/ast/node/break_node.rs b/boa/src/syntax/ast/node/break_node.rs index e7b3a79f522..92e2b8068f4 100644 --- a/boa/src/syntax/ast/node/break_node.rs +++ b/boa/src/syntax/ast/node/break_node.rs @@ -22,7 +22,7 @@ use serde::{Deserialize, Serialize}; #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[derive(Clone, Debug, Trace, Finalize, PartialEq)] pub struct Break { - label: Option> + label: Option>, } impl Break { @@ -37,16 +37,18 @@ impl Break { OL: Into>, { Self { - label: label.into().map(L::into) + label: label.into().map(L::into), } } } impl fmt::Display for Break { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "break{}", + write!( + f, + "break{}", if self.label().is_some() { - format!(" {}", self.label().unwrap()) + format!(" {}", self.label().as_ref().unwrap()) } else { String::new() } @@ -58,4 +60,4 @@ impl From for Node { fn from(break_smt: Break) -> Node { Self::Break(break_smt) } -} \ No newline at end of file +} diff --git a/boa/src/syntax/parser/statement/break_stm/mod.rs b/boa/src/syntax/parser/statement/break_stm/mod.rs index 12642c9f97e..162d5420305 100644 --- a/boa/src/syntax/parser/statement/break_stm/mod.rs +++ b/boa/src/syntax/parser/statement/break_stm/mod.rs @@ -12,7 +12,7 @@ mod tests; use super::LabelIdentifier; use crate::syntax::{ - ast::{Keyword, Node, Punctuator, TokenKind, node::Break}, + ast::{node::Break, Keyword, Node, Punctuator, TokenKind}, parser::{AllowAwait, AllowYield, Cursor, ParseResult, TokenParser}, }; @@ -66,6 +66,6 @@ impl TokenParser for BreakStatement { Some(label) }; - Ok(Break::new(label).into()) + Ok(Break::new::<_, Box>(label).into()) } } diff --git a/boa/src/syntax/parser/statement/break_stm/tests.rs b/boa/src/syntax/parser/statement/break_stm/tests.rs index de5a320635f..1507b0917bb 100644 --- a/boa/src/syntax/parser/statement/break_stm/tests.rs +++ b/boa/src/syntax/parser/statement/break_stm/tests.rs @@ -1,6 +1,6 @@ use crate::syntax::{ ast::{ - node::{Block, Node, WhileLoop, Break}, + node::{Block, Break, Node, WhileLoop}, Const, }, parser::tests::check_parser, @@ -10,7 +10,11 @@ use crate::syntax::{ fn inline() { check_parser( "while (true) break;", - vec![WhileLoop::new(Const::from(true), Node::Break(None)).into()], + vec![WhileLoop::new( + Const::from(true), + Node::Break(Break::new::<_, Box>(None)), + ) + .into()], ); } @@ -19,7 +23,7 @@ fn new_line() { check_parser( "while (true) break;", - vec![WhileLoop::new(Const::from(true), Node::Break(None)).into()], + vec![WhileLoop::new(Const::from(true), Break::new::<_, Box>(None)).into()], ); } @@ -27,7 +31,11 @@ fn new_line() { fn inline_block_semicolon_insertion() { check_parser( "while (true) {break}", - vec![WhileLoop::new(Const::from(true), Block::from(vec![Node::Break(None)])).into()], + vec![WhileLoop::new( + Const::from(true), + Block::from(vec![Break::new::<_, Box>(None).into()]), + ) + .into()], ); } @@ -49,7 +57,11 @@ fn new_line_semicolon_insertion() { fn inline_block() { check_parser( "while (true) {break;}", - vec![WhileLoop::new(Const::from(true), Block::from(vec![Break::new(None).into()])).into()], + vec![WhileLoop::new( + Const::from(true), + Block::from(vec![Break::new::<_, Box>(None).into()]), + ) + .into()], ); } @@ -98,7 +110,11 @@ fn new_line_block_empty() { "while (true) { break; }", - vec![WhileLoop::new(Const::from(true), Block::from(vec![Break::new(None).into()])).into()], + vec![WhileLoop::new( + Const::from(true), + Block::from(vec![Break::new::<_, Box>(None).into()]), + ) + .into()], ); } @@ -108,6 +124,10 @@ fn new_line_block_empty_semicolon_insertion() { "while (true) { break }", - vec![WhileLoop::new(Const::from(true), Block::from(vec![Break::new(None).into()])).into()], + vec![WhileLoop::new( + Const::from(true), + Block::from(vec![Break::new::<_, Box>(None).into()]), + ) + .into()], ); } From 5c90059172a0be4ff6acc289989a026485f891f9 Mon Sep 17 00:00:00 2001 From: Paul Lancaster Date: Sun, 31 May 2020 15:26:53 +0100 Subject: [PATCH 25/42] Conditional Op impl --- boa/src/syntax/ast/node/conditional.rs | 68 +++++++++++++++++++ boa/src/syntax/ast/node/mod.rs | 37 ++-------- .../expression/assignment/conditional.rs | 4 +- 3 files changed, 74 insertions(+), 35 deletions(-) diff --git a/boa/src/syntax/ast/node/conditional.rs b/boa/src/syntax/ast/node/conditional.rs index 9b0776c5f31..717490a15d7 100644 --- a/boa/src/syntax/ast/node/conditional.rs +++ b/boa/src/syntax/ast/node/conditional.rs @@ -81,3 +81,71 @@ impl From for Node { Self::If(if_stm) } } + +/// The `conditional` (ternary) operator is the only JavaScript operator that takes three +/// operands. +/// +/// This operator is the only JavaScript operator that takes three operands: a condition +/// followed by a question mark (`?`), then an expression to execute `if` the condition is +/// truthy followed by a colon (`:`), and finally the expression to execute if the condition +/// is `false`. This operator is frequently used as a shortcut for the `if` statement. +/// +/// More information: +/// - [ECMAScript reference][spec] +/// - [MDN documentation][mdn] +/// +/// [spec]: https://tc39.es/ecma262/#prod-ConditionalExpression +/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Grammar_and_types#Literals +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +#[derive(Clone, Debug, Trace, Finalize, PartialEq)] +pub struct ConditionalOp { + condition: Box, + if_true: Box, + if_false: Box, +} + +impl ConditionalOp { + pub fn cond(&self) -> &Node { + &self.condition + } + + pub fn if_true(&self) -> &Node { + &self.if_true + } + + pub fn if_false(&self) -> &Node { + &self.if_false + } + + /// Creates a `ConditionalOp` AST node. + pub fn new(condition: C, if_true: T, if_false: F) -> Self + where + C: Into, + T: Into, + F: Into, + { + Self { + condition: Box::new(condition.into()), + if_true: Box::new(if_true.into()), + if_false: Box::new(if_false.into()), + } + } +} + +impl fmt::Display for ConditionalOp { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!( + f, + "{} ? {} : {}", + self.cond(), + self.if_true(), + self.if_false() + ) + } +} + +impl From for Node { + fn from(cond_op: ConditionalOp) -> Node { + Self::ConditionalOp(cond_op) + } +} diff --git a/boa/src/syntax/ast/node/mod.rs b/boa/src/syntax/ast/node/mod.rs index d8bf2ea363c..d9c57f7878b 100644 --- a/boa/src/syntax/ast/node/mod.rs +++ b/boa/src/syntax/ast/node/mod.rs @@ -20,7 +20,7 @@ pub use self::{ array::ArrayDecl, block::Block, break_node::Break, - conditional::If, + conditional::{ConditionalOp, If}, declaration::{ ArrowFunctionDecl, ConstDecl, ConstDeclList, FunctionDecl, FunctionExpr, LetDecl, LetDeclList, VarDecl, VarDeclList, @@ -70,21 +70,8 @@ pub enum Node { /// A function call. [More information](./expression/struct.Call.html). Call(Call), - /// The `conditional` (ternary) operator is the only JavaScript operator that takes three - /// operands. - /// - /// This operator is the only JavaScript operator that takes three operands: a condition - /// followed by a question mark (`?`), then an expression to execute `if` the condition is - /// truthy followed by a colon (`:`), and finally the expression to execute if the condition - /// is `false`. This operator is frequently used as a shortcut for the `if` statement. - /// - /// More information: - /// - [ECMAScript reference][spec] - /// - [MDN documentation][mdn] - /// - /// [spec]: https://tc39.es/ecma262/#prod-ConditionalExpression - /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Grammar_and_types#Literals - ConditionalOp(Box, Box, Box), + /// A javascript conditional operand ( x ? y : z ). [More information](./conditional/struct.ConditionalOp.html). + ConditionalOp(ConditionalOp), /// Literals represent values in JavaScript. /// @@ -237,20 +224,6 @@ impl Node { } } - /// Creates a `ConditionalOp` AST node. - pub fn conditional_op(condition: C, if_true: T, if_false: F) -> Self - where - C: Into, - T: Into, - F: Into, - { - Self::ConditionalOp( - Box::new(condition.into()), - Box::new(if_true.into()), - Box::new(if_false.into()), - ) - } - /// Creates a `Continue` AST node. pub fn continue_node(label: OL) -> Self where @@ -291,9 +264,7 @@ impl Node { match *self { Self::Const(ref c) => write!(f, "{}", c), - Self::ConditionalOp(ref cond, ref if_true, ref if_false) => { - write!(f, "{} ? {} : {}", cond, if_true, if_false) - } + Self::ConditionalOp(ref cond_op) => Display::fmt(cond_op, f), Self::ForLoop(ref for_loop) => for_loop.display(f, indentation), Self::This => write!(f, "this"), Self::Try(ref try_catch) => try_catch.display(f, indentation), diff --git a/boa/src/syntax/parser/expression/assignment/conditional.rs b/boa/src/syntax/parser/expression/assignment/conditional.rs index 2bea95cc9bb..39b3d33744d 100644 --- a/boa/src/syntax/parser/expression/assignment/conditional.rs +++ b/boa/src/syntax/parser/expression/assignment/conditional.rs @@ -8,7 +8,7 @@ //! [spec]: https://tc39.es/ecma262/#sec-conditional-operator use crate::syntax::{ - ast::{Node, Punctuator, TokenKind}, + ast::{node::ConditionalOp, Node, Punctuator, TokenKind}, parser::{ expression::{AssignmentExpression, LogicalORExpression}, AllowAwait, AllowIn, AllowYield, Cursor, ParseResult, TokenParser, @@ -68,7 +68,7 @@ impl TokenParser for ConditionalExpression { let else_clause = AssignmentExpression::new(self.allow_in, self.allow_yield, self.allow_await) .parse(cursor)?; - return Ok(Node::conditional_op(lhs, then_clause, else_clause)); + return Ok(ConditionalOp::new(lhs, then_clause, else_clause).into()); } else { cursor.back(); } From 4e267c3f9914dff71f35959796300195c25dbe83 Mon Sep 17 00:00:00 2001 From: Paul Lancaster Date: Sun, 31 May 2020 16:02:04 +0100 Subject: [PATCH 26/42] Continue impl --- boa/src/syntax/ast/node/iteration.rs | 56 +++++++++++++++++++ boa/src/syntax/ast/node/mod.rs | 43 +++----------- .../parser/statement/continue_stm/mod.rs | 4 +- .../parser/statement/continue_stm/tests.rs | 38 +++++++++---- 4 files changed, 93 insertions(+), 48 deletions(-) diff --git a/boa/src/syntax/ast/node/iteration.rs b/boa/src/syntax/ast/node/iteration.rs index b4b71d6b346..cdeccb9f7bd 100644 --- a/boa/src/syntax/ast/node/iteration.rs +++ b/boa/src/syntax/ast/node/iteration.rs @@ -253,3 +253,59 @@ impl From for Node { Self::DoWhileLoop(do_while) } } + +/// The `continue` statement terminates execution of the statements in the current iteration of +/// the current or labeled loop, and continues execution of the loop with the next iteration. +/// +/// The continue statement can include an optional label that allows the program to jump to the +/// next iteration of a labeled loop statement instead of the current loop. In this case, the +/// continue statement needs to be nested within this labeled statement. +/// +/// More information: +/// - [ECMAScript reference][spec] +/// - [MDN documentation][mdn] +/// +/// [spec]: https://tc39.es/ecma262/#prod-ContinueStatement +/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/continue +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +#[derive(Clone, Debug, Trace, Finalize, PartialEq)] +pub struct Continue { + label: Option>, +} + +impl Continue { + pub fn label(&self) -> &Option> { + &self.label + } + + /// Creates a `Continue` AST node. + pub fn new(label: OL) -> Self + where + L: Into>, + OL: Into>, + { + Self { + label: label.into().map(L::into), + } + } +} + +impl fmt::Display for Continue { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!( + f, + "continue{}", + if let Some(label) = self.label() { + format!(" {}", label) + } else { + String::new() + } + ) + } +} + +impl From for Node { + fn from(cont: Continue) -> Node { + Self::Continue(cont) + } +} diff --git a/boa/src/syntax/ast/node/mod.rs b/boa/src/syntax/ast/node/mod.rs index d9c57f7878b..2745c9107a9 100644 --- a/boa/src/syntax/ast/node/mod.rs +++ b/boa/src/syntax/ast/node/mod.rs @@ -28,7 +28,7 @@ pub use self::{ expression::{Call, New}, field::{GetConstField, GetField}, identifier::Identifier, - iteration::{DoWhileLoop, ForLoop, WhileLoop}, + iteration::{Continue, DoWhileLoop, ForLoop, WhileLoop}, object::Object, operator::{Assign, BinOp, UnaryOp}, return_smt::Return, @@ -88,21 +88,10 @@ pub enum Node { /// A constant declaration list. [More information](./declaration/struct.ConstDeclList.html). ConstDeclList(ConstDeclList), - /// The `continue` statement terminates execution of the statements in the current iteration of - /// the current or labeled loop, and continues execution of the loop with the next iteration. - /// - /// The continue statement can include an optional label that allows the program to jump to the - /// next iteration of a labeled loop statement instead of the current loop. In this case, the - /// continue statement needs to be nested within this labeled statement. - /// - /// More information: - /// - [ECMAScript reference][spec] - /// - [MDN documentation][mdn] - /// - /// [spec]: https://tc39.es/ecma262/#prod-ContinueStatement - /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/continue - Continue(Option>), + /// A continue statement. [More information](./iteration/struct.Continue.html). + Continue(Continue), + /// A do ... while statement. [More information](./iteration/struct.DoWhileLoop.html). DoWhileLoop(DoWhileLoop), /// A function declaration node. [More information](./declaration/struct.FunctionDecl.html). @@ -117,10 +106,10 @@ pub enum Node { /// Provides access to object fields. [More information](./declaration/struct.GetField.html). GetField(GetField), - /// A `for` statement. [More information](./iteration.struct.ForLoop.html). + /// A `for` statement. [More information](./iteration/struct.ForLoop.html). ForLoop(ForLoop), - /// An 'if' statement. [More information](./conditional.struct.If.html). + /// An 'if' statement. [More information](./conditional/struct.If.html). If(If), /// A `let` declaration list. [More information](./declaration/struct.LetDeclList.html). @@ -138,6 +127,7 @@ pub enum Node { /// A return statement. [More information](./object/struct.Return.html). Return(Return), + /// A switch {case...} statement. [More information](./switch/struct.Switch.html). Switch(Switch), /// The `spread` operator allows an iterable such as an array expression or string to be @@ -224,15 +214,6 @@ impl Node { } } - /// Creates a `Continue` AST node. - pub fn continue_node(label: OL) -> Self - where - L: Into>, - OL: Into>, - { - Self::Continue(label.into().map(L::into)) - } - /// Creates a `Spread` AST node. pub fn spread(val: V) -> Self where @@ -269,15 +250,7 @@ impl Node { Self::This => write!(f, "this"), Self::Try(ref try_catch) => try_catch.display(f, indentation), Self::Break(ref break_smt) => Display::fmt(break_smt, f), - Self::Continue(ref l) => write!( - f, - "continue{}", - if let Some(label) = l { - format!(" {}", label) - } else { - String::new() - } - ), + Self::Continue(ref cont) => Display::fmt(cont, f), Self::Spread(ref node) => write!(f, "...{}", node), Self::Block(ref block) => block.display(f, indentation), Self::Identifier(ref s) => Display::fmt(s, f), diff --git a/boa/src/syntax/parser/statement/continue_stm/mod.rs b/boa/src/syntax/parser/statement/continue_stm/mod.rs index 7da0b5414cb..bb757f7ffec 100644 --- a/boa/src/syntax/parser/statement/continue_stm/mod.rs +++ b/boa/src/syntax/parser/statement/continue_stm/mod.rs @@ -12,7 +12,7 @@ mod tests; use super::LabelIdentifier; use crate::syntax::{ - ast::{Keyword, Node, Punctuator, TokenKind}, + ast::{node::Continue, Keyword, Node, Punctuator, TokenKind}, parser::{AllowAwait, AllowYield, Cursor, ParseResult, TokenParser}, }; @@ -66,6 +66,6 @@ impl TokenParser for ContinueStatement { Some(label) }; - Ok(Node::Continue(label)) + Ok(Continue::new::<_, Box>(label).into()) } } diff --git a/boa/src/syntax/parser/statement/continue_stm/tests.rs b/boa/src/syntax/parser/statement/continue_stm/tests.rs index eca57628016..b8aba8bb089 100644 --- a/boa/src/syntax/parser/statement/continue_stm/tests.rs +++ b/boa/src/syntax/parser/statement/continue_stm/tests.rs @@ -1,6 +1,6 @@ use crate::syntax::{ ast::{ - node::{Block, Node, WhileLoop}, + node::{Block, Continue, WhileLoop}, Const, }, parser::tests::check_parser, @@ -10,7 +10,7 @@ use crate::syntax::{ fn inline() { check_parser( "while (true) continue;", - vec![WhileLoop::new(Const::from(true), Node::Continue(None)).into()], + vec![WhileLoop::new(Const::from(true), Continue::new::<_, Box>(None)).into()], ); } @@ -19,7 +19,7 @@ fn new_line() { check_parser( "while (true) continue;", - vec![WhileLoop::new(Const::from(true), Node::Continue(None)).into()], + vec![WhileLoop::new(Const::from(true), Continue::new::<_, Box>(None)).into()], ); } @@ -27,7 +27,11 @@ fn new_line() { fn inline_block_semicolon_insertion() { check_parser( "while (true) {continue}", - vec![WhileLoop::new(Const::from(true), Block::from(vec![Node::Continue(None)])).into()], + vec![WhileLoop::new( + Const::from(true), + Block::from(vec![Continue::new::<_, Box>(None).into()]), + ) + .into()], ); } @@ -39,7 +43,7 @@ fn new_line_semicolon_insertion() { }", vec![WhileLoop::new( Const::from(true), - Block::from(vec![Node::continue_node("test")]), + Block::from(vec![Continue::new("test").into()]), ) .into()], ); @@ -49,7 +53,11 @@ fn new_line_semicolon_insertion() { fn inline_block() { check_parser( "while (true) {continue;}", - vec![WhileLoop::new(Const::from(true), Block::from(vec![Node::Continue(None)])).into()], + vec![WhileLoop::new( + Const::from(true), + Block::from(vec![Continue::new::<_, Box>(None).into()]), + ) + .into()], ); } @@ -61,7 +69,7 @@ fn new_line_block() { }", vec![WhileLoop::new( Const::from(true), - Block::from(vec![Node::continue_node("test")]), + Block::from(vec![Continue::new("test").into()]), ) .into()], ); @@ -75,7 +83,7 @@ fn reserved_label() { }", vec![WhileLoop::new( Const::from(true), - Block::from(vec![Node::continue_node("await")]), + Block::from(vec![Continue::new("await").into()]), ) .into()], ); @@ -86,7 +94,7 @@ fn reserved_label() { }", vec![WhileLoop::new( Const::from(true), - Block::from(vec![Node::continue_node("yield")]), + Block::from(vec![Continue::new("yield").into()]), ) .into()], ); @@ -98,7 +106,11 @@ fn new_line_block_empty() { "while (true) { continue; }", - vec![WhileLoop::new(Const::from(true), Block::from(vec![Node::Continue(None)])).into()], + vec![WhileLoop::new( + Const::from(true), + Block::from(vec![Continue::new::<_, Box>(None).into()]), + ) + .into()], ); } @@ -108,6 +120,10 @@ fn new_line_block_empty_semicolon_insertion() { "while (true) { continue }", - vec![WhileLoop::new(Const::from(true), Block::from(vec![Node::Continue(None)])).into()], + vec![WhileLoop::new( + Const::from(true), + Block::from(vec![Continue::new::<_, Box>(None).into()]), + ) + .into()], ); } From e3882d7c4d20410f02e045901346befb2ee0caf1 Mon Sep 17 00:00:00 2001 From: Paul Lancaster Date: Sun, 31 May 2020 16:54:24 +0100 Subject: [PATCH 27/42] Throw impl --- boa/src/exec/mod.rs | 3 +- boa/src/exec/throw/mod.rs | 8 +++ boa/src/syntax/ast/node/mod.rs | 29 ++-------- boa/src/syntax/ast/node/throw.rs | 54 +++++++++++++++++++ boa/src/syntax/parser/statement/throw/mod.rs | 4 +- .../syntax/parser/statement/throw/tests.rs | 7 ++- 6 files changed, 76 insertions(+), 29 deletions(-) create mode 100644 boa/src/exec/throw/mod.rs create mode 100644 boa/src/syntax/ast/node/throw.rs diff --git a/boa/src/exec/mod.rs b/boa/src/exec/mod.rs index c48fd00a995..fd6bdeab68b 100644 --- a/boa/src/exec/mod.rs +++ b/boa/src/exec/mod.rs @@ -14,6 +14,7 @@ mod statement_list; mod switch; #[cfg(test)] mod tests; +mod throw; mod try_node; use crate::{ @@ -411,7 +412,7 @@ impl Executable for Node { Node::UnaryOp(ref op) => op.run(interpreter), Node::New(ref call) => call.run(interpreter), Node::Return(ref ret) => ret.run(interpreter), - Node::Throw(ref ex) => Err(ex.run(interpreter)?), + Node::Throw(ref throw) => throw.run(interpreter), Node::Assign(ref op) => op.run(interpreter), Node::VarDeclList(ref decl) => decl.run(interpreter), Node::LetDeclList(ref decl) => decl.run(interpreter), diff --git a/boa/src/exec/throw/mod.rs b/boa/src/exec/throw/mod.rs new file mode 100644 index 00000000000..b6a6f9a7007 --- /dev/null +++ b/boa/src/exec/throw/mod.rs @@ -0,0 +1,8 @@ +use super::{Executable, Interpreter}; +use crate::{builtins::value::ResultValue, syntax::ast::node::Throw}; + +impl Executable for Throw { + fn run(&self, interpreter: &mut Interpreter) -> ResultValue { + Err(self.expr().run(interpreter)?) + } +} diff --git a/boa/src/syntax/ast/node/mod.rs b/boa/src/syntax/ast/node/mod.rs index 2745c9107a9..6e127f547c0 100644 --- a/boa/src/syntax/ast/node/mod.rs +++ b/boa/src/syntax/ast/node/mod.rs @@ -14,6 +14,7 @@ pub mod operator; pub mod return_smt; pub mod statement_list; pub mod switch; +pub mod throw; pub mod try_node; pub use self::{ @@ -34,6 +35,7 @@ pub use self::{ return_smt::Return, statement_list::StatementList, switch::Switch, + throw::Throw, try_node::{Catch, Finally, Try}, }; use super::Const; @@ -148,21 +150,8 @@ pub enum Node { /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_syntax Spread(Box), - /// The `throw` statement throws a user-defined exception. - /// - /// Syntax: `throw expression;` - /// - /// Execution of the current function will stop (the statements after throw won't be executed), - /// and control will be passed to the first catch block in the call stack. If no catch block - /// exists among caller functions, the program will terminate. - /// - /// More information: - /// - [ECMAScript reference][spec] - /// - [MDN documentation][mdn] - /// - /// [spec]: https://tc39.es/ecma262/#prod-ThrowStatement - /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/throw - Throw(Box), + /// A throw statement. [More information](./throw/struct.Throw.html). + Throw(Throw), /// A `try...catch` node. [More information](./try_node/struct.Try.htl). Try(Try), @@ -222,14 +211,6 @@ impl Node { Self::Spread(Box::new(val.into())) } - /// Creates a `Throw` AST node. - pub fn throw(val: V) -> Self - where - V: Into, - { - Self::Throw(Box::new(val.into())) - } - /// Creates a `This` AST node. pub fn this() -> Self { Self::This @@ -271,7 +252,7 @@ impl Node { Self::BinOp(ref op) => Display::fmt(op, f), Self::UnaryOp(ref op) => Display::fmt(op, f), Self::Return(ref ret) => Display::fmt(ret, f), - Self::Throw(ref ex) => write!(f, "throw {}", ex), + Self::Throw(ref throw) => Display::fmt(throw, f), Self::Assign(ref op) => Display::fmt(op, f), Self::LetDeclList(ref decl) => Display::fmt(decl, f), Self::ConstDeclList(ref decl) => Display::fmt(decl, f), diff --git a/boa/src/syntax/ast/node/throw.rs b/boa/src/syntax/ast/node/throw.rs new file mode 100644 index 00000000000..432616e2d3a --- /dev/null +++ b/boa/src/syntax/ast/node/throw.rs @@ -0,0 +1,54 @@ +use super::Node; +use gc::{Finalize, Trace}; +use std::fmt; + +#[cfg(feature = "serde")] +use serde::{Deserialize, Serialize}; + +/// The `throw` statement throws a user-defined exception. +/// +/// Syntax: `throw expression;` +/// +/// Execution of the current function will stop (the statements after throw won't be executed), +/// and control will be passed to the first catch block in the call stack. If no catch block +/// exists among caller functions, the program will terminate. +/// +/// More information: +/// - [ECMAScript reference][spec] +/// - [MDN documentation][mdn] +/// +/// [spec]: https://tc39.es/ecma262/#prod-ThrowStatement +/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/throw +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +#[derive(Clone, Debug, Trace, Finalize, PartialEq)] +pub struct Throw { + expr: Box, +} + +impl Throw { + pub fn expr(&self) -> &Node { + &self.expr + } + + /// Creates a `Throw` AST node. + pub fn new(val: V) -> Self + where + V: Into, + { + Self { + expr: Box::new(val.into()), + } + } +} + +impl fmt::Display for Throw { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "throw {}", self.expr) + } +} + +impl From for Node { + fn from(trw: Throw) -> Node { + Self::Throw(trw) + } +} diff --git a/boa/src/syntax/parser/statement/throw/mod.rs b/boa/src/syntax/parser/statement/throw/mod.rs index 4d788424e7e..161ba8dd670 100644 --- a/boa/src/syntax/parser/statement/throw/mod.rs +++ b/boa/src/syntax/parser/statement/throw/mod.rs @@ -2,7 +2,7 @@ mod tests; use crate::syntax::{ - ast::{Keyword, Node, Punctuator, TokenKind}, + ast::{node::Throw, Keyword, Node, Punctuator, TokenKind}, parser::{expression::Expression, AllowAwait, AllowYield, Cursor, ParseResult, TokenParser}, }; @@ -49,6 +49,6 @@ impl TokenParser for ThrowStatement { } } - Ok(Node::throw(expr)) + Ok(Throw::new(expr).into()) } } diff --git a/boa/src/syntax/parser/statement/throw/tests.rs b/boa/src/syntax/parser/statement/throw/tests.rs index f8a9357ac41..fad2603a72f 100644 --- a/boa/src/syntax/parser/statement/throw/tests.rs +++ b/boa/src/syntax/parser/statement/throw/tests.rs @@ -1,9 +1,12 @@ use crate::syntax::{ - ast::{Const, Node}, + ast::{node::Throw, Const}, parser::tests::check_parser, }; #[test] fn check_throw_parsing() { - check_parser("throw 'error';", vec![Node::throw(Const::from("error"))]); + check_parser( + "throw 'error';", + vec![Throw::new(Const::from("error")).into()], + ); } From bb3353266471da64552a2d53efda9a430fabf654 Mon Sep 17 00:00:00 2001 From: Paul Lancaster Date: Sun, 31 May 2020 17:21:35 +0100 Subject: [PATCH 28/42] Spread impl --- boa/src/exec/mod.rs | 6 +- boa/src/exec/spread/mod.rs | 9 +++ boa/src/syntax/ast/node/mod.rs | 33 ++--------- boa/src/syntax/ast/node/spread.rs | 57 +++++++++++++++++++ .../expression/left_hand_side/arguments.rs | 13 +++-- .../primary/array_initializer/mod.rs | 4 +- 6 files changed, 84 insertions(+), 38 deletions(-) create mode 100644 boa/src/exec/spread/mod.rs create mode 100644 boa/src/syntax/ast/node/spread.rs diff --git a/boa/src/exec/mod.rs b/boa/src/exec/mod.rs index fd6bdeab68b..a26c928ae19 100644 --- a/boa/src/exec/mod.rs +++ b/boa/src/exec/mod.rs @@ -10,6 +10,7 @@ mod iteration; mod object; mod operator; mod return_smt; +mod spread; mod statement_list; mod switch; #[cfg(test)] @@ -417,10 +418,7 @@ impl Executable for Node { Node::VarDeclList(ref decl) => decl.run(interpreter), Node::LetDeclList(ref decl) => decl.run(interpreter), Node::ConstDeclList(ref decl) => decl.run(interpreter), - Node::Spread(ref node) => { - // TODO: for now we can do nothing but return the value as-is - node.run(interpreter) - } + Node::Spread(ref spread) => spread.run(interpreter), Node::This => { // Will either return `this` binding or undefined Ok(interpreter.realm().environment.get_this_binding()) diff --git a/boa/src/exec/spread/mod.rs b/boa/src/exec/spread/mod.rs new file mode 100644 index 00000000000..189b0d7a67c --- /dev/null +++ b/boa/src/exec/spread/mod.rs @@ -0,0 +1,9 @@ +use super::{Executable, Interpreter}; +use crate::{builtins::value::ResultValue, syntax::ast::node::Spread}; + +impl Executable for Spread { + fn run(&self, interpreter: &mut Interpreter) -> ResultValue { + // TODO: for now we can do nothing but return the value as-is + self.val().run(interpreter) + } +} diff --git a/boa/src/syntax/ast/node/mod.rs b/boa/src/syntax/ast/node/mod.rs index 6e127f547c0..658bb2fae71 100644 --- a/boa/src/syntax/ast/node/mod.rs +++ b/boa/src/syntax/ast/node/mod.rs @@ -12,6 +12,7 @@ pub mod iteration; pub mod object; pub mod operator; pub mod return_smt; +pub mod spread; pub mod statement_list; pub mod switch; pub mod throw; @@ -33,6 +34,7 @@ pub use self::{ object::Object, operator::{Assign, BinOp, UnaryOp}, return_smt::Return, + spread::Spread, statement_list::StatementList, switch::Switch, throw::Throw, @@ -129,26 +131,11 @@ pub enum Node { /// A return statement. [More information](./object/struct.Return.html). Return(Return), - /// A switch {case...} statement. [More information](./switch/struct.Switch.html). + /// A switch {case} statement. [More information](./switch/struct.Switch.html). Switch(Switch), - /// The `spread` operator allows an iterable such as an array expression or string to be - /// expanded. - /// - /// Syntax: `...x` - /// - /// It expands array expressions or strings in places where zero or more arguments (for - /// function calls) or elements (for array literals) - /// are expected, or an object expression to be expanded in places where zero or more key-value - /// pairs (for object literals) are expected. - /// - /// More information: - /// - [ECMAScript reference][spec] - /// - [MDN documentation][mdn] - /// - /// [spec]: https://tc39.es/ecma262/#prod-SpreadElement - /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_syntax - Spread(Box), + /// A spread (...x) statement. [More information](./spread/struct.Spread.html). + Spread(Spread), /// A throw statement. [More information](./throw/struct.Throw.html). Throw(Throw), @@ -203,14 +190,6 @@ impl Node { } } - /// Creates a `Spread` AST node. - pub fn spread(val: V) -> Self - where - V: Into, - { - Self::Spread(Box::new(val.into())) - } - /// Creates a `This` AST node. pub fn this() -> Self { Self::This @@ -232,7 +211,7 @@ impl Node { Self::Try(ref try_catch) => try_catch.display(f, indentation), Self::Break(ref break_smt) => Display::fmt(break_smt, f), Self::Continue(ref cont) => Display::fmt(cont, f), - Self::Spread(ref node) => write!(f, "...{}", node), + Self::Spread(ref spread) => Display::fmt(spread, f), Self::Block(ref block) => block.display(f, indentation), Self::Identifier(ref s) => Display::fmt(s, f), Self::GetConstField(ref get_const_field) => Display::fmt(get_const_field, f), diff --git a/boa/src/syntax/ast/node/spread.rs b/boa/src/syntax/ast/node/spread.rs new file mode 100644 index 00000000000..3afe90775fb --- /dev/null +++ b/boa/src/syntax/ast/node/spread.rs @@ -0,0 +1,57 @@ +use super::Node; +use gc::{Finalize, Trace}; +use std::fmt; + +#[cfg(feature = "serde")] +use serde::{Deserialize, Serialize}; + +/// The `spread` operator allows an iterable such as an array expression or string to be +/// expanded. +/// +/// Syntax: `...x` +/// +/// It expands array expressions or strings in places where zero or more arguments (for +/// function calls) or elements (for array literals) +/// are expected, or an object expression to be expanded in places where zero or more key-value +/// pairs (for object literals) are expected. +/// +/// More information: +/// - [ECMAScript reference][spec] +/// - [MDN documentation][mdn] +/// +/// [spec]: https://tc39.es/ecma262/#prod-SpreadElement +/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_syntax +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +#[cfg_attr(feature = "serde", serde(transparent))] +#[derive(Clone, Debug, Trace, Finalize, PartialEq)] +pub struct Spread { + val: Box, +} + +impl Spread { + pub fn val(&self) -> &Node { + &self.val + } + + /// Creates a `Spread` AST node. + pub fn new(val: V) -> Self + where + V: Into, + { + Self { + val: Box::new(val.into()), + } + } +} + +impl fmt::Display for Spread { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "...{}", self.val()) + } +} + +impl From for Node { + fn from(spread: Spread) -> Node { + Self::Spread(spread) + } +} diff --git a/boa/src/syntax/parser/expression/left_hand_side/arguments.rs b/boa/src/syntax/parser/expression/left_hand_side/arguments.rs index a5caf3a9383..7be7de7a0eb 100644 --- a/boa/src/syntax/parser/expression/left_hand_side/arguments.rs +++ b/boa/src/syntax/parser/expression/left_hand_side/arguments.rs @@ -8,7 +8,7 @@ //! [spec]: https://tc39.es/ecma262/#prod-Arguments use crate::syntax::{ - ast::{Node, Punctuator, TokenKind}, + ast::{node::Spread, Node, Punctuator, TokenKind}, parser::{ expression::AssignmentExpression, AllowAwait, AllowYield, Cursor, ParseError, TokenParser, }, @@ -78,10 +78,13 @@ impl TokenParser for Arguments { } if cursor.next_if(Punctuator::Spread).is_some() { - args.push(Node::spread( - AssignmentExpression::new(true, self.allow_yield, self.allow_await) - .parse(cursor)?, - )); + args.push( + Spread::new( + AssignmentExpression::new(true, self.allow_yield, self.allow_await) + .parse(cursor)?, + ) + .into(), + ); } else { args.push( AssignmentExpression::new(true, self.allow_yield, self.allow_await) diff --git a/boa/src/syntax/parser/expression/primary/array_initializer/mod.rs b/boa/src/syntax/parser/expression/primary/array_initializer/mod.rs index 999af9a8c17..9d9f14d492c 100644 --- a/boa/src/syntax/parser/expression/primary/array_initializer/mod.rs +++ b/boa/src/syntax/parser/expression/primary/array_initializer/mod.rs @@ -12,7 +12,7 @@ mod tests; use crate::syntax::{ ast::{ - node::{ArrayDecl, Node}, + node::{ArrayDecl, Node, Spread}, Const, Punctuator, }, parser::{ @@ -69,7 +69,7 @@ impl TokenParser for ArrayLiteral { if cursor.next_if(Punctuator::Spread).is_some() { let node = AssignmentExpression::new(true, self.allow_yield, self.allow_await) .parse(cursor)?; - elements.push(Node::spread(node)); + elements.push(Spread::new(node).into()); } else { elements.push( AssignmentExpression::new(true, self.allow_yield, self.allow_await) From 022b48e3aada1021beeedc8949689688bf23c063 Mon Sep 17 00:00:00 2001 From: Paul Lancaster Date: Sun, 31 May 2020 17:40:02 +0100 Subject: [PATCH 29/42] Object initalizer now returns Object in result rather than Node --- boa/src/syntax/parser/expression/primary/mod.rs | 4 +++- .../parser/expression/primary/object_initializer/mod.rs | 6 +++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/boa/src/syntax/parser/expression/primary/mod.rs b/boa/src/syntax/parser/expression/primary/mod.rs index 62cdfb525b0..0e31e581cc5 100644 --- a/boa/src/syntax/parser/expression/primary/mod.rs +++ b/boa/src/syntax/parser/expression/primary/mod.rs @@ -80,7 +80,9 @@ impl TokenParser for PrimaryExpression { .map(Node::ArrayDecl) } TokenKind::Punctuator(Punctuator::OpenBlock) => { - ObjectLiteral::new(self.allow_yield, self.allow_await).parse(cursor) + Ok(ObjectLiteral::new(self.allow_yield, self.allow_await) + .parse(cursor)? + .into()) } TokenKind::BooleanLiteral(boolean) => Ok(Const::from(*boolean).into()), // TODO: ADD TokenKind::UndefinedLiteral diff --git a/boa/src/syntax/parser/expression/primary/object_initializer/mod.rs b/boa/src/syntax/parser/expression/primary/object_initializer/mod.rs index 9eb6b51c720..66548cc6184 100644 --- a/boa/src/syntax/parser/expression/primary/object_initializer/mod.rs +++ b/boa/src/syntax/parser/expression/primary/object_initializer/mod.rs @@ -52,9 +52,9 @@ impl ObjectLiteral { } impl TokenParser for ObjectLiteral { - type Output = Node; + type Output = Object; - fn parse(self, cursor: &mut Cursor<'_>) -> ParseResult { + fn parse(self, cursor: &mut Cursor<'_>) -> Result { let mut elements = Vec::new(); loop { @@ -82,7 +82,7 @@ impl TokenParser for ObjectLiteral { } } - Ok(Object::from(elements).into()) + Ok(Object::from(elements)) } } From 57cace0142f18b109f17d222d31e5e7cdf98960d Mon Sep 17 00:00:00 2001 From: Paul Lancaster Date: Mon, 1 Jun 2020 12:26:11 +0100 Subject: [PATCH 30/42] Update boa/src/exec/throw/mod.rs Co-authored-by: Iban Eguia --- boa/src/exec/throw/mod.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/boa/src/exec/throw/mod.rs b/boa/src/exec/throw/mod.rs index b6a6f9a7007..3c8cf527fe8 100644 --- a/boa/src/exec/throw/mod.rs +++ b/boa/src/exec/throw/mod.rs @@ -2,6 +2,7 @@ use super::{Executable, Interpreter}; use crate::{builtins::value::ResultValue, syntax::ast::node::Throw}; impl Executable for Throw { + #[inline] fn run(&self, interpreter: &mut Interpreter) -> ResultValue { Err(self.expr().run(interpreter)?) } From e96f79c59b08665d1490b28e42e3933b2b379b8b Mon Sep 17 00:00:00 2001 From: Paul Lancaster Date: Mon, 1 Jun 2020 12:26:28 +0100 Subject: [PATCH 31/42] Update boa/src/syntax/ast/node/break_node.rs Co-authored-by: Iban Eguia --- boa/src/syntax/ast/node/break_node.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/boa/src/syntax/ast/node/break_node.rs b/boa/src/syntax/ast/node/break_node.rs index 92e2b8068f4..39c8258317b 100644 --- a/boa/src/syntax/ast/node/break_node.rs +++ b/boa/src/syntax/ast/node/break_node.rs @@ -26,8 +26,8 @@ pub struct Break { } impl Break { - pub fn label(&self) -> &Option> { - &self.label + pub fn label(&self) -> Option<&str> { + self.label.as_ref().map(Box::as_ref) } /// Creates a `Break` AST node. From 44da6aa74da93e48ab2c643c1bf9ce45eff6bcb6 Mon Sep 17 00:00:00 2001 From: Paul Lancaster Date: Mon, 1 Jun 2020 12:26:51 +0100 Subject: [PATCH 32/42] Update boa/src/syntax/ast/node/conditional.rs Co-authored-by: Iban Eguia --- boa/src/syntax/ast/node/conditional.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/boa/src/syntax/ast/node/conditional.rs b/boa/src/syntax/ast/node/conditional.rs index 717490a15d7..973a3bef001 100644 --- a/boa/src/syntax/ast/node/conditional.rs +++ b/boa/src/syntax/ast/node/conditional.rs @@ -38,8 +38,8 @@ impl If { &self.body } - pub fn else_node(&self) -> &Option> { - &self.else_node + pub fn else_node(&self) -> Option<&Node> { + self.else_node.as_ref().map(Box::as_ref) } /// Creates an `If` AST node. From 43a046faf999a9846c2a0bf7491367ee784638b1 Mon Sep 17 00:00:00 2001 From: Paul Lancaster Date: Mon, 1 Jun 2020 12:27:07 +0100 Subject: [PATCH 33/42] Update boa/src/syntax/ast/node/iteration.rs Co-authored-by: Iban Eguia --- boa/src/syntax/ast/node/iteration.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/boa/src/syntax/ast/node/iteration.rs b/boa/src/syntax/ast/node/iteration.rs index cdeccb9f7bd..d84a12499f3 100644 --- a/boa/src/syntax/ast/node/iteration.rs +++ b/boa/src/syntax/ast/node/iteration.rs @@ -274,8 +274,8 @@ pub struct Continue { } impl Continue { - pub fn label(&self) -> &Option> { - &self.label + pub fn label(&self) -> Option<&str> { + self.label.as_ref().map(Box::as_ref) } /// Creates a `Continue` AST node. From 7604c0feb4f4fa1b5ad975357c3efa28f7d7e419 Mon Sep 17 00:00:00 2001 From: Paul Lancaster Date: Mon, 1 Jun 2020 15:11:41 +0100 Subject: [PATCH 34/42] Made Switch::new() more generic, added TODO for break in Switch::run() --- boa/src/exec/switch/mod.rs | 2 ++ boa/src/syntax/ast/node/switch.rs | 18 ++++++++++-------- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/boa/src/exec/switch/mod.rs b/boa/src/exec/switch/mod.rs index 8dca8f9f805..df30936fc10 100644 --- a/boa/src/exec/switch/mod.rs +++ b/boa/src/exec/switch/mod.rs @@ -23,6 +23,8 @@ impl Executable for Switch { } } } + + // TODO: break out of switch on a break statement. } if !matched { if let Some(default) = default { diff --git a/boa/src/syntax/ast/node/switch.rs b/boa/src/syntax/ast/node/switch.rs index c43c776214f..2fd5892c2c7 100644 --- a/boa/src/syntax/ast/node/switch.rs +++ b/boa/src/syntax/ast/node/switch.rs @@ -44,15 +44,17 @@ impl Switch { &self.default } - pub fn new( - val: Box, - cases: Box<[(Node, Box<[Node]>)]>, - default: Option>, - ) -> Switch { + /// Creates a `Switch` AST node. + pub fn new(val: V, cases: C, default: D) -> Self + where + V: Into, + C: Into)]>>, + D: Into>>, + { Self { - val, - cases, - default, + val: Box::new(val.into()), + cases: cases.into(), + default: default.into(), } } From b7a641b40b704303c792e330af027a5ddc353706 Mon Sep 17 00:00:00 2001 From: Paul Lancaster Date: Mon, 1 Jun 2020 17:49:39 +0100 Subject: [PATCH 35/42] Making parse functions return the actual result of the parse rather than a Node where possible --- boa/src/syntax/ast/node/switch.rs | 2 +- boa/src/syntax/parser/statement/break_stm/mod.rs | 10 +++++----- boa/src/syntax/parser/statement/continue_stm/mod.rs | 8 ++++---- boa/src/syntax/parser/statement/declaration/mod.rs | 2 +- boa/src/syntax/parser/statement/if_stm/mod.rs | 12 ++++++------ .../parser/statement/iteration/do_while_statement.rs | 6 +++--- .../parser/statement/iteration/for_statement.rs | 2 +- .../parser/statement/iteration/while_statement.rs | 8 ++++---- boa/src/syntax/parser/statement/mod.rs | 4 ++-- boa/src/syntax/parser/statement/return_stm/mod.rs | 8 ++++---- boa/src/syntax/parser/statement/switch/mod.rs | 11 ++++------- boa/src/syntax/parser/statement/throw/mod.rs | 10 +++++----- 12 files changed, 40 insertions(+), 43 deletions(-) diff --git a/boa/src/syntax/ast/node/switch.rs b/boa/src/syntax/ast/node/switch.rs index 2fd5892c2c7..6f3702aa486 100644 --- a/boa/src/syntax/ast/node/switch.rs +++ b/boa/src/syntax/ast/node/switch.rs @@ -54,7 +54,7 @@ impl Switch { Self { val: Box::new(val.into()), cases: cases.into(), - default: default.into(), + default: default.into().map(V::into).map(Box::new), } } diff --git a/boa/src/syntax/parser/statement/break_stm/mod.rs b/boa/src/syntax/parser/statement/break_stm/mod.rs index 162d5420305..f25ab47d525 100644 --- a/boa/src/syntax/parser/statement/break_stm/mod.rs +++ b/boa/src/syntax/parser/statement/break_stm/mod.rs @@ -12,8 +12,8 @@ mod tests; use super::LabelIdentifier; use crate::syntax::{ - ast::{node::Break, Keyword, Node, Punctuator, TokenKind}, - parser::{AllowAwait, AllowYield, Cursor, ParseResult, TokenParser}, + ast::{node::Break, Keyword, Punctuator, TokenKind}, + parser::{AllowAwait, AllowYield, Cursor, ParseError, TokenParser}, }; /// Break statement parsing @@ -45,9 +45,9 @@ impl BreakStatement { } impl TokenParser for BreakStatement { - type Output = Node; + type Output = Break; - fn parse(self, cursor: &mut Cursor<'_>) -> ParseResult { + fn parse(self, cursor: &mut Cursor<'_>) -> Result { cursor.expect(Keyword::Break, "break statement")?; let label = if let (true, tok) = cursor.peek_semicolon(false) { @@ -66,6 +66,6 @@ impl TokenParser for BreakStatement { Some(label) }; - Ok(Break::new::<_, Box>(label).into()) + Ok(Break::new::<_, Box>(label)) } } diff --git a/boa/src/syntax/parser/statement/continue_stm/mod.rs b/boa/src/syntax/parser/statement/continue_stm/mod.rs index bb757f7ffec..bfb91768a3f 100644 --- a/boa/src/syntax/parser/statement/continue_stm/mod.rs +++ b/boa/src/syntax/parser/statement/continue_stm/mod.rs @@ -13,7 +13,7 @@ mod tests; use super::LabelIdentifier; use crate::syntax::{ ast::{node::Continue, Keyword, Node, Punctuator, TokenKind}, - parser::{AllowAwait, AllowYield, Cursor, ParseResult, TokenParser}, + parser::{AllowAwait, AllowYield, Cursor, ParseError, TokenParser}, }; /// For statement parsing @@ -45,9 +45,9 @@ impl ContinueStatement { } impl TokenParser for ContinueStatement { - type Output = Node; + type Output = Continue; - fn parse(self, cursor: &mut Cursor<'_>) -> ParseResult { + fn parse(self, cursor: &mut Cursor<'_>) -> Result { cursor.expect(Keyword::Continue, "continue statement")?; let label = if let (true, tok) = cursor.peek_semicolon(false) { @@ -66,6 +66,6 @@ impl TokenParser for ContinueStatement { Some(label) }; - Ok(Continue::new::<_, Box>(label).into()) + Ok(Continue::new::<_, Box>(label)) } } diff --git a/boa/src/syntax/parser/statement/declaration/mod.rs b/boa/src/syntax/parser/statement/declaration/mod.rs index c8f44aee9f7..7ff701c9182 100644 --- a/boa/src/syntax/parser/statement/declaration/mod.rs +++ b/boa/src/syntax/parser/statement/declaration/mod.rs @@ -46,7 +46,7 @@ impl Declaration { impl TokenParser for Declaration { type Output = Node; - fn parse(self, cursor: &mut Cursor<'_>) -> ParseResult { + fn parse(self, cursor: &mut Cursor<'_>) -> Result { let tok = cursor.peek(0).ok_or(ParseError::AbruptEnd)?; match tok.kind { diff --git a/boa/src/syntax/parser/statement/if_stm/mod.rs b/boa/src/syntax/parser/statement/if_stm/mod.rs index 41a54ea3392..06604984646 100644 --- a/boa/src/syntax/parser/statement/if_stm/mod.rs +++ b/boa/src/syntax/parser/statement/if_stm/mod.rs @@ -3,9 +3,9 @@ mod tests; use super::Statement; use crate::syntax::{ - ast::{node::If, Keyword, Node, Punctuator, TokenKind}, + ast::{node::If, Keyword, Punctuator, TokenKind, Node}, parser::{ - expression::Expression, AllowAwait, AllowReturn, AllowYield, Cursor, ParseResult, + expression::Expression, AllowAwait, AllowReturn, AllowYield, Cursor, ParseError, TokenParser, }, }; @@ -44,9 +44,9 @@ impl IfStatement { } impl TokenParser for IfStatement { - type Output = Node; + type Output = If; - fn parse(self, cursor: &mut Cursor<'_>) -> ParseResult { + fn parse(self, cursor: &mut Cursor<'_>) -> Result { cursor.expect(Keyword::If, "if statement")?; cursor.expect(Punctuator::OpenParen, "if statement")?; @@ -62,12 +62,12 @@ impl TokenParser for IfStatement { cursor.next(); Some( Statement::new(self.allow_yield, self.allow_await, self.allow_return) - .parse(cursor)?, + .parse(cursor), ) } _ => None, }; - Ok(If::new::<_, _, Node, _>(cond, then_stm, else_stm).into()) + Ok(If::new(cond, then_stm, else_stm)) } } diff --git a/boa/src/syntax/parser/statement/iteration/do_while_statement.rs b/boa/src/syntax/parser/statement/iteration/do_while_statement.rs index 331f29de947..f87ae5936ea 100644 --- a/boa/src/syntax/parser/statement/iteration/do_while_statement.rs +++ b/boa/src/syntax/parser/statement/iteration/do_while_statement.rs @@ -51,9 +51,9 @@ impl DoWhileStatement { } impl TokenParser for DoWhileStatement { - type Output = Node; + type Output = DoWhileLoop; - fn parse(self, cursor: &mut Cursor<'_>) -> ParseResult { + fn parse(self, cursor: &mut Cursor<'_>) -> Result { cursor.expect(Keyword::Do, "do while statement")?; let body = @@ -77,6 +77,6 @@ impl TokenParser for DoWhileStatement { cursor.expect(Punctuator::CloseParen, "do while statement")?; cursor.expect_semicolon(true, "do while statement")?; - Ok(DoWhileLoop::new(body, cond).into()) + Ok(DoWhileLoop::new(body, cond)) } } diff --git a/boa/src/syntax/parser/statement/iteration/for_statement.rs b/boa/src/syntax/parser/statement/iteration/for_statement.rs index c5d2b340a06..995c7017293 100644 --- a/boa/src/syntax/parser/statement/iteration/for_statement.rs +++ b/boa/src/syntax/parser/statement/iteration/for_statement.rs @@ -58,7 +58,7 @@ impl ForStatement { impl TokenParser for ForStatement { type Output = ForLoop; - fn parse(self, cursor: &mut Cursor<'_>) -> Result { + fn parse(self, cursor: &mut Cursor<'_>) -> Result { cursor.expect(Keyword::For, "for statement")?; cursor.expect(Punctuator::OpenParen, "for statement")?; diff --git a/boa/src/syntax/parser/statement/iteration/while_statement.rs b/boa/src/syntax/parser/statement/iteration/while_statement.rs index f8b97c64d77..7614135c4c9 100644 --- a/boa/src/syntax/parser/statement/iteration/while_statement.rs +++ b/boa/src/syntax/parser/statement/iteration/while_statement.rs @@ -2,7 +2,7 @@ use crate::syntax::{ ast::{node::WhileLoop, Keyword, Node, Punctuator}, parser::{ expression::Expression, statement::Statement, AllowAwait, AllowReturn, AllowYield, Cursor, - ParseResult, TokenParser, + ParseError, TokenParser, }, }; @@ -42,9 +42,9 @@ impl WhileStatement { } impl TokenParser for WhileStatement { - type Output = Node; + type Output = WhileLoop; - fn parse(self, cursor: &mut Cursor<'_>) -> ParseResult { + fn parse(self, cursor: &mut Cursor<'_>) -> Result { cursor.expect(Keyword::While, "while statement")?; cursor.expect(Punctuator::OpenParen, "while statement")?; @@ -55,6 +55,6 @@ impl TokenParser for WhileStatement { let body = Statement::new(self.allow_yield, self.allow_await, self.allow_return).parse(cursor)?; - Ok(WhileLoop::new(cond, body).into()) + Ok(WhileLoop::new(cond, body)) } } diff --git a/boa/src/syntax/parser/statement/mod.rs b/boa/src/syntax/parser/statement/mod.rs index cf845e8a410..40e638e6227 100644 --- a/boa/src/syntax/parser/statement/mod.rs +++ b/boa/src/syntax/parser/statement/mod.rs @@ -89,7 +89,7 @@ impl Statement { impl TokenParser for Statement { type Output = Node; - fn parse(self, cursor: &mut Cursor<'_>) -> ParseResult { + fn parse(self, cursor: &mut Cursor<'_>) -> Result { // TODO: add BreakableStatement and divide Whiles, fors and so on to another place. let tok = cursor.peek(0).ok_or(ParseError::AbruptEnd)?; @@ -269,7 +269,7 @@ impl StatementListItem { impl TokenParser for StatementListItem { type Output = Node; - fn parse(self, cursor: &mut Cursor<'_>) -> ParseResult { + fn parse(self, cursor: &mut Cursor<'_>) -> Result { let tok = cursor.peek(0).ok_or(ParseError::AbruptEnd)?; match tok.kind { diff --git a/boa/src/syntax/parser/statement/return_stm/mod.rs b/boa/src/syntax/parser/statement/return_stm/mod.rs index 58f3f543ce3..af44bb8d429 100644 --- a/boa/src/syntax/parser/statement/return_stm/mod.rs +++ b/boa/src/syntax/parser/statement/return_stm/mod.rs @@ -3,7 +3,7 @@ mod tests; use crate::syntax::{ ast::{node::Return, Keyword, Node, Punctuator, TokenKind}, - parser::{expression::Expression, AllowAwait, AllowYield, Cursor, ParseResult, TokenParser}, + parser::{expression::Expression, AllowAwait, AllowYield, Cursor, ParseError, TokenParser}, }; /// Return statement parsing @@ -35,9 +35,9 @@ impl ReturnStatement { } impl TokenParser for ReturnStatement { - type Output = Node; + type Output = Return; - fn parse(self, cursor: &mut Cursor<'_>) -> ParseResult { + fn parse(self, cursor: &mut Cursor<'_>) -> Result { cursor.expect(Keyword::Return, "return statement")?; if let (true, tok) = cursor.peek_semicolon(false) { @@ -58,6 +58,6 @@ impl TokenParser for ReturnStatement { cursor.expect_semicolon(false, "return statement")?; - Ok(Return::new(expr).into()) + Ok(Return::new(expr)) } } diff --git a/boa/src/syntax/parser/statement/switch/mod.rs b/boa/src/syntax/parser/statement/switch/mod.rs index be434c9e376..2ecec0cda0b 100644 --- a/boa/src/syntax/parser/statement/switch/mod.rs +++ b/boa/src/syntax/parser/statement/switch/mod.rs @@ -41,9 +41,9 @@ impl SwitchStatement { } impl TokenParser for SwitchStatement { - type Output = Node; + type Output = Switch; - fn parse(self, cursor: &mut Cursor<'_>) -> ParseResult { + fn parse(self, cursor: &mut Cursor<'_>) -> Result { cursor.expect(Keyword::Switch, "switch statement")?; cursor.expect(Punctuator::OpenParen, "switch statement")?; @@ -53,11 +53,8 @@ impl TokenParser for SwitchStatement { let (cases, default) = CaseBlock::new(self.allow_yield, self.allow_await, self.allow_return).parse(cursor)?; - - match default { - Some(s) => Ok(Switch::new(Box::new(condition), cases, Some(Box::new(s))).into()), - None => Ok(Switch::new(Box::new(condition), cases, None).into()), - } + + Ok(Switch::new(condition, cases, default)) } } diff --git a/boa/src/syntax/parser/statement/throw/mod.rs b/boa/src/syntax/parser/statement/throw/mod.rs index 161ba8dd670..7851ad8d5ce 100644 --- a/boa/src/syntax/parser/statement/throw/mod.rs +++ b/boa/src/syntax/parser/statement/throw/mod.rs @@ -2,8 +2,8 @@ mod tests; use crate::syntax::{ - ast::{node::Throw, Keyword, Node, Punctuator, TokenKind}, - parser::{expression::Expression, AllowAwait, AllowYield, Cursor, ParseResult, TokenParser}, + ast::{node::Throw, Keyword, Punctuator, TokenKind}, + parser::{expression::Expression, AllowAwait, AllowYield, Cursor, ParseError, TokenParser}, }; /// For statement parsing @@ -35,9 +35,9 @@ impl ThrowStatement { } impl TokenParser for ThrowStatement { - type Output = Node; + type Output = Throw; - fn parse(self, cursor: &mut Cursor<'_>) -> ParseResult { + fn parse(self, cursor: &mut Cursor<'_>) -> Result { cursor.expect(Keyword::Throw, "throw statement")?; cursor.peek_expect_no_lineterminator(0)?; @@ -49,6 +49,6 @@ impl TokenParser for ThrowStatement { } } - Ok(Throw::new(expr).into()) + Ok(Throw::new(expr)) } } From ea45b26156e29c1c8595b848ef22a30cdd8345bf Mon Sep 17 00:00:00 2001 From: Paul Lancaster Date: Mon, 1 Jun 2020 18:46:28 +0100 Subject: [PATCH 36/42] Reworked switch::new, added Case struct --- boa/src/syntax/ast/node/mod.rs | 3 +- boa/src/syntax/ast/node/switch.rs | 42 +++++++++++++------ boa/src/syntax/parser/statement/if_stm/mod.rs | 4 +- boa/src/syntax/parser/statement/switch/mod.rs | 9 ++-- 4 files changed, 37 insertions(+), 21 deletions(-) diff --git a/boa/src/syntax/ast/node/mod.rs b/boa/src/syntax/ast/node/mod.rs index 658bb2fae71..6308bcb86f8 100644 --- a/boa/src/syntax/ast/node/mod.rs +++ b/boa/src/syntax/ast/node/mod.rs @@ -36,7 +36,7 @@ pub use self::{ return_smt::Return, spread::Spread, statement_list::StatementList, - switch::Switch, + switch::{Switch, Case}, throw::Throw, try_node::{Catch, Finally, Try}, }; @@ -163,6 +163,7 @@ pub enum Node { /// Array declaration node. [More information](./declaration/struct.VarDeclList.html). VarDeclList(VarDeclList), + /// A 'while {...}' node. [More information](./iteration/struct.WhileLoop.html). WhileLoop(WhileLoop), } diff --git a/boa/src/syntax/ast/node/switch.rs b/boa/src/syntax/ast/node/switch.rs index 6f3702aa486..023d776a91c 100644 --- a/boa/src/syntax/ast/node/switch.rs +++ b/boa/src/syntax/ast/node/switch.rs @@ -1,18 +1,29 @@ //! Switch node. //! -use super::{join_nodes, Node}; +use super::Node; use gc::{Finalize, Trace}; use std::fmt; +use crate::syntax::ast::node::StatementList; + #[cfg(feature = "serde")] use serde::{Deserialize, Serialize}; #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[derive(Clone, Debug, Trace, Finalize, PartialEq)] -pub struct Switch { - val: Box, - cases: Box<[(Node, Box<[Node]>)]>, - default: Option>, +pub struct Case { + cond: Node, + statements: StatementList +} + +impl Case { + pub fn cond(&self) -> &Node { + &self.cond + } + + pub fn statements(&self) -> &StatementList { + &self.statements + } } /// The `switch` statement evaluates an expression, matching the expression's value to a case @@ -31,12 +42,20 @@ pub struct Switch { /// /// [spec]: https://tc39.es/ecma262/#prod-SwitchStatement /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/switch +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +#[derive(Clone, Debug, Trace, Finalize, PartialEq)] +pub struct Switch { + val: Box, + cases: Box<[Case]>, + default: Option>, +} + impl Switch { pub fn val(&self) -> &Node { &self.val } - pub fn cases(&self) -> &[(Node, Box<[Node]>)] { + pub fn cases(&self) -> &[Case] { &self.cases } @@ -45,16 +64,15 @@ impl Switch { } /// Creates a `Switch` AST node. - pub fn new(val: V, cases: C, default: D) -> Self + pub fn new(val: V, cases: C, default: Option) -> Self where V: Into, - C: Into)]>>, - D: Into>>, + C: Into>, { Self { val: Box::new(val.into()), cases: cases.into(), - default: default.into().map(V::into).map(Box::new), + default: default.map(V::into).map(Box::new), } } @@ -62,8 +80,8 @@ impl Switch { pub(super) fn display(&self, f: &mut fmt::Formatter<'_>, indent: usize) -> fmt::Result { writeln!(f, "switch ({}) {{", self.val())?; for e in self.cases().iter() { - writeln!(f, "{}case {}:", indent, e.0)?; - join_nodes(f, &e.1)?; + writeln!(f, "{}case {}:", indent, e.cond())?; + e.statements().display(f, indent); } if self.default().is_some() { diff --git a/boa/src/syntax/parser/statement/if_stm/mod.rs b/boa/src/syntax/parser/statement/if_stm/mod.rs index 06604984646..545627b2048 100644 --- a/boa/src/syntax/parser/statement/if_stm/mod.rs +++ b/boa/src/syntax/parser/statement/if_stm/mod.rs @@ -62,12 +62,12 @@ impl TokenParser for IfStatement { cursor.next(); Some( Statement::new(self.allow_yield, self.allow_await, self.allow_return) - .parse(cursor), + .parse(cursor)?, ) } _ => None, }; - Ok(If::new(cond, then_stm, else_stm)) + Ok(If::new::<_, _, Node, _>(cond, then_stm, else_stm)) } } diff --git a/boa/src/syntax/parser/statement/switch/mod.rs b/boa/src/syntax/parser/statement/switch/mod.rs index 2ecec0cda0b..f4ee31ab939 100644 --- a/boa/src/syntax/parser/statement/switch/mod.rs +++ b/boa/src/syntax/parser/statement/switch/mod.rs @@ -2,10 +2,10 @@ mod tests; use crate::syntax::{ - ast::{node::Switch, Keyword, Node, Punctuator}, + ast::{node::{Switch, Case}, Keyword, Node, Punctuator}, parser::{ - expression::Expression, AllowAwait, AllowReturn, AllowYield, Cursor, ParseError, - ParseResult, TokenParser, + expression::Expression, AllowAwait, AllowReturn, AllowYield, Cursor, ParseError, + TokenParser, }, }; @@ -87,9 +87,6 @@ impl CaseBlock { } } -/// Type used for case definition in a switch. -type Case = (Node, Box<[Node]>); - impl TokenParser for CaseBlock { type Output = (Box<[Case]>, Option); From 7733da27c7b4c2b766b67cd2eab41afbb2f8f08e Mon Sep 17 00:00:00 2001 From: Paul Lancaster Date: Mon, 1 Jun 2020 19:02:39 +0100 Subject: [PATCH 37/42] Switch::run() refractored, rustfmt --- boa/src/exec/switch/mod.rs | 14 ++++--------- boa/src/syntax/ast/node/mod.rs | 2 +- boa/src/syntax/ast/node/switch.rs | 16 +++++++-------- .../parser/statement/continue_stm/mod.rs | 2 +- .../parser/statement/declaration/mod.rs | 2 +- boa/src/syntax/parser/statement/if_stm/mod.rs | 2 +- .../statement/iteration/do_while_statement.rs | 4 ++-- .../statement/iteration/while_statement.rs | 2 +- boa/src/syntax/parser/statement/mod.rs | 20 +++++++++++++++---- .../syntax/parser/statement/return_stm/mod.rs | 2 +- boa/src/syntax/parser/statement/switch/mod.rs | 9 ++++++--- 11 files changed, 42 insertions(+), 33 deletions(-) diff --git a/boa/src/exec/switch/mod.rs b/boa/src/exec/switch/mod.rs index df30936fc10..d5e5e93e48e 100644 --- a/boa/src/exec/switch/mod.rs +++ b/boa/src/exec/switch/mod.rs @@ -10,18 +10,12 @@ impl Executable for Switch { let val = self.val().run(interpreter)?; let mut result = Value::null(); let mut matched = false; - for tup in self.cases().iter() { - let cond = &tup.0; - let block = &tup.1; + for case in self.cases().iter() { + let cond = case.condition(); + let block = case.body(); if val.strict_equals(&cond.run(interpreter)?) { matched = true; - let last_expr = block.last().expect("Block has no expressions"); - for expr in block.iter() { - let e_result = expr.run(interpreter)?; - if expr == last_expr { - result = e_result; - } - } + block.run(interpreter)?; } // TODO: break out of switch on a break statement. diff --git a/boa/src/syntax/ast/node/mod.rs b/boa/src/syntax/ast/node/mod.rs index 6308bcb86f8..ab177d6259c 100644 --- a/boa/src/syntax/ast/node/mod.rs +++ b/boa/src/syntax/ast/node/mod.rs @@ -36,7 +36,7 @@ pub use self::{ return_smt::Return, spread::Spread, statement_list::StatementList, - switch::{Switch, Case}, + switch::{Case, Switch}, throw::Throw, try_node::{Catch, Finally, Try}, }; diff --git a/boa/src/syntax/ast/node/switch.rs b/boa/src/syntax/ast/node/switch.rs index 023d776a91c..94ca8b53bec 100644 --- a/boa/src/syntax/ast/node/switch.rs +++ b/boa/src/syntax/ast/node/switch.rs @@ -12,17 +12,17 @@ use serde::{Deserialize, Serialize}; #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[derive(Clone, Debug, Trace, Finalize, PartialEq)] pub struct Case { - cond: Node, - statements: StatementList + condition: Node, + body: StatementList, } impl Case { - pub fn cond(&self) -> &Node { - &self.cond + pub fn condition(&self) -> &Node { + &self.condition } - pub fn statements(&self) -> &StatementList { - &self.statements + pub fn body(&self) -> &StatementList { + &self.body } } @@ -80,8 +80,8 @@ impl Switch { pub(super) fn display(&self, f: &mut fmt::Formatter<'_>, indent: usize) -> fmt::Result { writeln!(f, "switch ({}) {{", self.val())?; for e in self.cases().iter() { - writeln!(f, "{}case {}:", indent, e.cond())?; - e.statements().display(f, indent); + writeln!(f, "{}case {}:", indent, e.condition())?; + e.body().display(f, indent)?; } if self.default().is_some() { diff --git a/boa/src/syntax/parser/statement/continue_stm/mod.rs b/boa/src/syntax/parser/statement/continue_stm/mod.rs index bfb91768a3f..2bee5bca263 100644 --- a/boa/src/syntax/parser/statement/continue_stm/mod.rs +++ b/boa/src/syntax/parser/statement/continue_stm/mod.rs @@ -12,7 +12,7 @@ mod tests; use super::LabelIdentifier; use crate::syntax::{ - ast::{node::Continue, Keyword, Node, Punctuator, TokenKind}, + ast::{node::Continue, Keyword, Punctuator, TokenKind}, parser::{AllowAwait, AllowYield, Cursor, ParseError, TokenParser}, }; diff --git a/boa/src/syntax/parser/statement/declaration/mod.rs b/boa/src/syntax/parser/statement/declaration/mod.rs index 7ff701c9182..b6e79196b8e 100644 --- a/boa/src/syntax/parser/statement/declaration/mod.rs +++ b/boa/src/syntax/parser/statement/declaration/mod.rs @@ -15,7 +15,7 @@ mod tests; use self::{hoistable::HoistableDeclaration, lexical::LexicalDeclaration}; use crate::syntax::{ ast::{Keyword, Node, TokenKind}, - parser::{AllowAwait, AllowYield, Cursor, ParseError, ParseResult, TokenParser}, + parser::{AllowAwait, AllowYield, Cursor, ParseError, TokenParser}, }; /// Parses a declaration. diff --git a/boa/src/syntax/parser/statement/if_stm/mod.rs b/boa/src/syntax/parser/statement/if_stm/mod.rs index 545627b2048..f6c90f3bea1 100644 --- a/boa/src/syntax/parser/statement/if_stm/mod.rs +++ b/boa/src/syntax/parser/statement/if_stm/mod.rs @@ -3,7 +3,7 @@ mod tests; use super::Statement; use crate::syntax::{ - ast::{node::If, Keyword, Punctuator, TokenKind, Node}, + ast::{node::If, Keyword, Node, Punctuator, TokenKind}, parser::{ expression::Expression, AllowAwait, AllowReturn, AllowYield, Cursor, ParseError, TokenParser, diff --git a/boa/src/syntax/parser/statement/iteration/do_while_statement.rs b/boa/src/syntax/parser/statement/iteration/do_while_statement.rs index f87ae5936ea..b0320026a39 100644 --- a/boa/src/syntax/parser/statement/iteration/do_while_statement.rs +++ b/boa/src/syntax/parser/statement/iteration/do_while_statement.rs @@ -8,10 +8,10 @@ //! [spec]: https://tc39.es/ecma262/#sec-do-while-statement use crate::syntax::{ - ast::{node::DoWhileLoop, Keyword, Node, Punctuator, TokenKind}, + ast::{node::DoWhileLoop, Keyword, Punctuator, TokenKind}, parser::{ expression::Expression, statement::Statement, AllowAwait, AllowReturn, AllowYield, Cursor, - ParseError, ParseResult, TokenParser, + ParseError, TokenParser, }, }; diff --git a/boa/src/syntax/parser/statement/iteration/while_statement.rs b/boa/src/syntax/parser/statement/iteration/while_statement.rs index 7614135c4c9..79f0b3c0014 100644 --- a/boa/src/syntax/parser/statement/iteration/while_statement.rs +++ b/boa/src/syntax/parser/statement/iteration/while_statement.rs @@ -1,5 +1,5 @@ use crate::syntax::{ - ast::{node::WhileLoop, Keyword, Node, Punctuator}, + ast::{node::WhileLoop, Keyword, Punctuator}, parser::{ expression::Expression, statement::Statement, AllowAwait, AllowReturn, AllowYield, Cursor, ParseError, TokenParser, diff --git a/boa/src/syntax/parser/statement/mod.rs b/boa/src/syntax/parser/statement/mod.rs index 40e638e6227..6892417725b 100644 --- a/boa/src/syntax/parser/statement/mod.rs +++ b/boa/src/syntax/parser/statement/mod.rs @@ -97,6 +97,7 @@ impl TokenParser for Statement { TokenKind::Keyword(Keyword::If) => { IfStatement::new(self.allow_yield, self.allow_await, self.allow_return) .parse(cursor) + .map(Node::from) } TokenKind::Keyword(Keyword::Var) => { VariableStatement::new(self.allow_yield, self.allow_await) @@ -106,10 +107,12 @@ impl TokenParser for Statement { TokenKind::Keyword(Keyword::While) => { WhileStatement::new(self.allow_yield, self.allow_await, self.allow_return) .parse(cursor) + .map(Node::from) } TokenKind::Keyword(Keyword::Do) => { DoWhileStatement::new(self.allow_yield, self.allow_await, self.allow_return) .parse(cursor) + .map(Node::from) } TokenKind::Keyword(Keyword::For) => { ForStatement::new(self.allow_yield, self.allow_await, self.allow_return) @@ -118,16 +121,22 @@ impl TokenParser for Statement { } TokenKind::Keyword(Keyword::Return) => { if self.allow_return.0 { - ReturnStatement::new(self.allow_yield, self.allow_await).parse(cursor) + ReturnStatement::new(self.allow_yield, self.allow_await) + .parse(cursor) + .map(Node::from) } else { Err(ParseError::unexpected(tok.clone(), "statement")) } } TokenKind::Keyword(Keyword::Break) => { - BreakStatement::new(self.allow_yield, self.allow_await).parse(cursor) + BreakStatement::new(self.allow_yield, self.allow_await) + .parse(cursor) + .map(Node::from) } TokenKind::Keyword(Keyword::Continue) => { - ContinueStatement::new(self.allow_yield, self.allow_await).parse(cursor) + ContinueStatement::new(self.allow_yield, self.allow_await) + .parse(cursor) + .map(Node::from) } TokenKind::Keyword(Keyword::Try) => { TryStatement::new(self.allow_yield, self.allow_await, self.allow_return) @@ -135,11 +144,14 @@ impl TokenParser for Statement { .map(Node::from) } TokenKind::Keyword(Keyword::Throw) => { - ThrowStatement::new(self.allow_yield, self.allow_await).parse(cursor) + ThrowStatement::new(self.allow_yield, self.allow_await) + .parse(cursor) + .map(Node::from) } TokenKind::Keyword(Keyword::Switch) => { SwitchStatement::new(self.allow_yield, self.allow_await, self.allow_return) .parse(cursor) + .map(Node::from) } TokenKind::Punctuator(Punctuator::OpenBlock) => { BlockStatement::new(self.allow_yield, self.allow_await, self.allow_return) diff --git a/boa/src/syntax/parser/statement/return_stm/mod.rs b/boa/src/syntax/parser/statement/return_stm/mod.rs index af44bb8d429..65f2391c994 100644 --- a/boa/src/syntax/parser/statement/return_stm/mod.rs +++ b/boa/src/syntax/parser/statement/return_stm/mod.rs @@ -51,7 +51,7 @@ impl TokenParser for ReturnStatement { _ => {} } - return Ok(Return::new::>(None).into()); + return Ok(Return::new::>(None)); } let expr = Expression::new(true, self.allow_yield, self.allow_await).parse(cursor)?; diff --git a/boa/src/syntax/parser/statement/switch/mod.rs b/boa/src/syntax/parser/statement/switch/mod.rs index f4ee31ab939..363fb5ddcc5 100644 --- a/boa/src/syntax/parser/statement/switch/mod.rs +++ b/boa/src/syntax/parser/statement/switch/mod.rs @@ -2,9 +2,12 @@ mod tests; use crate::syntax::{ - ast::{node::{Switch, Case}, Keyword, Node, Punctuator}, + ast::{ + node::{Case, Switch}, + Keyword, Node, Punctuator, + }, parser::{ - expression::Expression, AllowAwait, AllowReturn, AllowYield, Cursor, ParseError, + expression::Expression, AllowAwait, AllowReturn, AllowYield, Cursor, ParseError, TokenParser, }, }; @@ -53,7 +56,7 @@ impl TokenParser for SwitchStatement { let (cases, default) = CaseBlock::new(self.allow_yield, self.allow_await, self.allow_return).parse(cursor)?; - + Ok(Switch::new(condition, cases, default)) } } From b73182e18a4232a545f9815dea8ad07b3c988f6d Mon Sep 17 00:00:00 2001 From: Paul Lancaster Date: Tue, 2 Jun 2020 00:40:02 +0100 Subject: [PATCH 38/42] Update boa/src/syntax/ast/node/return_smt.rs Co-authored-by: Iban Eguia --- boa/src/syntax/ast/node/return_smt.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/boa/src/syntax/ast/node/return_smt.rs b/boa/src/syntax/ast/node/return_smt.rs index 23b80f16acb..2cf64fa4f3a 100644 --- a/boa/src/syntax/ast/node/return_smt.rs +++ b/boa/src/syntax/ast/node/return_smt.rs @@ -31,8 +31,8 @@ pub struct Return { } impl Return { - pub fn expr(&self) -> &Option> { - &self.expr + pub fn expr(&self) -> Option<&Node> { + self.expr.as_ref().map(Box::as_ref) } /// Creates a `Return` AST node. From e95b6e44e8e90c64acf064397216192249427892 Mon Sep 17 00:00:00 2001 From: Paul Lancaster Date: Tue, 2 Jun 2020 00:40:28 +0100 Subject: [PATCH 39/42] Update boa/src/syntax/ast/node/switch.rs Co-authored-by: Iban Eguia --- boa/src/syntax/ast/node/switch.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/boa/src/syntax/ast/node/switch.rs b/boa/src/syntax/ast/node/switch.rs index 94ca8b53bec..f4de8c07430 100644 --- a/boa/src/syntax/ast/node/switch.rs +++ b/boa/src/syntax/ast/node/switch.rs @@ -59,8 +59,8 @@ impl Switch { &self.cases } - pub fn default(&self) -> &Option> { - &self.default + pub fn default(&self) -> Option<&Node> { + self.default.as_ref().map(Box::as_ref) } /// Creates a `Switch` AST node. From e6072c8dd81dccf41444197b64d2caba716e4ad2 Mon Sep 17 00:00:00 2001 From: Paul Lancaster Date: Tue, 2 Jun 2020 00:40:42 +0100 Subject: [PATCH 40/42] Update boa/src/syntax/ast/node/return_smt.rs Co-authored-by: Iban Eguia --- boa/src/syntax/ast/node/return_smt.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/boa/src/syntax/ast/node/return_smt.rs b/boa/src/syntax/ast/node/return_smt.rs index 2cf64fa4f3a..e088fa72d57 100644 --- a/boa/src/syntax/ast/node/return_smt.rs +++ b/boa/src/syntax/ast/node/return_smt.rs @@ -42,7 +42,7 @@ impl Return { OE: Into>, { Self { - expr: expr.into().map(E::into).map(Box::new), + expr: Box::new(expr.into().map(E::into)), } } } From ad91f42db2a8c97e2067bec120cc9c586d799594 Mon Sep 17 00:00:00 2001 From: Paul Lancaster Date: Tue, 2 Jun 2020 00:48:55 +0100 Subject: [PATCH 41/42] Small fixes to return_smt --- boa/src/exec/return_smt/mod.rs | 2 +- boa/src/syntax/ast/node/return_smt.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/boa/src/exec/return_smt/mod.rs b/boa/src/exec/return_smt/mod.rs index a0ecc05bfbc..5a75d3610da 100644 --- a/boa/src/exec/return_smt/mod.rs +++ b/boa/src/exec/return_smt/mod.rs @@ -6,7 +6,7 @@ use crate::{ impl Executable for Return { fn run(&self, interpreter: &mut Interpreter) -> ResultValue { - let result = match *self.expr() { + let result = match self.expr() { Some(ref v) => v.run(interpreter), None => Ok(Value::undefined()), }; diff --git a/boa/src/syntax/ast/node/return_smt.rs b/boa/src/syntax/ast/node/return_smt.rs index e088fa72d57..2cf64fa4f3a 100644 --- a/boa/src/syntax/ast/node/return_smt.rs +++ b/boa/src/syntax/ast/node/return_smt.rs @@ -42,7 +42,7 @@ impl Return { OE: Into>, { Self { - expr: Box::new(expr.into().map(E::into)), + expr: expr.into().map(E::into).map(Box::new), } } } From e50a74116b68b517df34aa6520d9ee7906487a8b Mon Sep 17 00:00:00 2001 From: Paul Lancaster Date: Fri, 5 Jun 2020 16:06:05 +0100 Subject: [PATCH 42/42] Finished merge --- .../expression/assignment/arrow_function.rs | 22 ++++++++++--------- .../expression/assignment/conditional.rs | 12 +++++----- .../expression/left_hand_side/arguments.rs | 11 ++++++---- .../parser/expression/left_hand_side/call.rs | 22 ++++++++++--------- .../expression/left_hand_side/member.rs | 22 ++++++++++--------- .../primary/array_initializer/mod.rs | 17 ++++++++------ .../primary/object_initializer/mod.rs | 22 ++++++++++--------- .../syntax/parser/statement/break_stm/mod.rs | 7 +++--- .../parser/statement/continue_stm/mod.rs | 7 +++--- .../parser/statement/declaration/mod.rs | 7 +++--- boa/src/syntax/parser/statement/if_stm/mod.rs | 12 +++++----- .../statement/iteration/do_while_statement.rs | 12 +++++----- .../statement/iteration/while_statement.rs | 12 +++++----- .../syntax/parser/statement/return_stm/mod.rs | 7 +++--- boa/src/syntax/parser/statement/switch/mod.rs | 18 ++++++++------- boa/src/syntax/parser/statement/throw/mod.rs | 7 +++--- 16 files changed, 123 insertions(+), 94 deletions(-) diff --git a/boa/src/syntax/parser/expression/assignment/arrow_function.rs b/boa/src/syntax/parser/expression/assignment/arrow_function.rs index 6d90675afc1..a802ace594f 100644 --- a/boa/src/syntax/parser/expression/assignment/arrow_function.rs +++ b/boa/src/syntax/parser/expression/assignment/arrow_function.rs @@ -8,16 +8,18 @@ //! [spec]: https://tc39.es/ecma262/#sec-arrow-function-definitions use super::AssignmentExpression; -use crate::syntax::{ - ast::{ - node::{ArrowFunctionDecl, FormalParameter, Node, Return, StatementList}, - Punctuator, TokenKind, - }, - parser::{ - error::{ErrorContext, ParseError, ParseResult}, - function::{FormalParameters, FunctionBody}, - statement::BindingIdentifier, - AllowAwait, AllowIn, AllowYield, Cursor, TokenParser, +use crate::{ + syntax::{ + ast::{ + node::{ArrowFunctionDecl, FormalParameter, Node, Return, StatementList}, + Punctuator, TokenKind, + }, + parser::{ + error::{ErrorContext, ParseError, ParseResult}, + function::{FormalParameters, FunctionBody}, + statement::BindingIdentifier, + AllowAwait, AllowIn, AllowYield, Cursor, TokenParser, + }, }, BoaProfiler, }; diff --git a/boa/src/syntax/parser/expression/assignment/conditional.rs b/boa/src/syntax/parser/expression/assignment/conditional.rs index b1b0276726e..0bc8b7d7277 100644 --- a/boa/src/syntax/parser/expression/assignment/conditional.rs +++ b/boa/src/syntax/parser/expression/assignment/conditional.rs @@ -7,11 +7,13 @@ //! [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Conditional_Operator //! [spec]: https://tc39.es/ecma262/#sec-conditional-operator -use crate::syntax::{ - ast::{node::ConditionalOp, Node, Punctuator, TokenKind}, - parser::{ - expression::{AssignmentExpression, LogicalORExpression}, - AllowAwait, AllowIn, AllowYield, Cursor, ParseResult, TokenParser, +use crate::{ + syntax::{ + ast::{node::ConditionalOp, Node, Punctuator, TokenKind}, + parser::{ + expression::{AssignmentExpression, LogicalORExpression}, + AllowAwait, AllowIn, AllowYield, Cursor, ParseResult, TokenParser, + }, }, BoaProfiler, }; diff --git a/boa/src/syntax/parser/expression/left_hand_side/arguments.rs b/boa/src/syntax/parser/expression/left_hand_side/arguments.rs index e9e25cc33c7..a15c88077e6 100644 --- a/boa/src/syntax/parser/expression/left_hand_side/arguments.rs +++ b/boa/src/syntax/parser/expression/left_hand_side/arguments.rs @@ -7,10 +7,13 @@ //! [mdn]: https://developer.mozilla.org/en-US/docs/Glossary/Argument //! [spec]: https://tc39.es/ecma262/#prod-Arguments -use crate::syntax::{ - ast::{node::Spread, Node, Punctuator, TokenKind}, - parser::{ - expression::AssignmentExpression, AllowAwait, AllowYield, Cursor, ParseError, TokenParser, +use crate::{ + syntax::{ + ast::{node::Spread, Node, Punctuator, TokenKind}, + parser::{ + expression::AssignmentExpression, AllowAwait, AllowYield, Cursor, ParseError, + TokenParser, + }, }, BoaProfiler, }; diff --git a/boa/src/syntax/parser/expression/left_hand_side/call.rs b/boa/src/syntax/parser/expression/left_hand_side/call.rs index 21019847122..c1a5b958912 100644 --- a/boa/src/syntax/parser/expression/left_hand_side/call.rs +++ b/boa/src/syntax/parser/expression/left_hand_side/call.rs @@ -8,17 +8,19 @@ //! [spec]: https://tc39.es/ecma262/#prod-CallExpression use super::arguments::Arguments; -use crate::syntax::{ - ast::{ - node::{ - field::{GetConstField, GetField}, - Call, Node, +use crate::{ + syntax::{ + ast::{ + node::{ + field::{GetConstField, GetField}, + Call, Node, + }, + Punctuator, TokenKind, + }, + parser::{ + expression::Expression, AllowAwait, AllowYield, Cursor, ParseError, ParseResult, + TokenParser, }, - Punctuator, TokenKind, - }, - parser::{ - expression::Expression, AllowAwait, AllowYield, Cursor, ParseError, ParseResult, - TokenParser, }, BoaProfiler, }; diff --git a/boa/src/syntax/parser/expression/left_hand_side/member.rs b/boa/src/syntax/parser/expression/left_hand_side/member.rs index a5e496df43b..91a6f04a43f 100644 --- a/boa/src/syntax/parser/expression/left_hand_side/member.rs +++ b/boa/src/syntax/parser/expression/left_hand_side/member.rs @@ -6,17 +6,19 @@ //! [spec]: https://tc39.es/ecma262/#prod-MemberExpression use super::arguments::Arguments; -use crate::syntax::{ - ast::{ - node::{ - field::{GetConstField, GetField}, - Call, New, Node, +use crate::{ + syntax::{ + ast::{ + node::{ + field::{GetConstField, GetField}, + Call, New, Node, + }, + Keyword, Punctuator, TokenKind, + }, + parser::{ + expression::{primary::PrimaryExpression, Expression}, + AllowAwait, AllowYield, Cursor, ParseError, ParseResult, TokenParser, }, - Keyword, Punctuator, TokenKind, - }, - parser::{ - expression::{primary::PrimaryExpression, Expression}, - AllowAwait, AllowYield, Cursor, ParseError, ParseResult, TokenParser, }, BoaProfiler, }; diff --git a/boa/src/syntax/parser/expression/primary/array_initializer/mod.rs b/boa/src/syntax/parser/expression/primary/array_initializer/mod.rs index cf7b4fc1e08..a5cd2b826a6 100644 --- a/boa/src/syntax/parser/expression/primary/array_initializer/mod.rs +++ b/boa/src/syntax/parser/expression/primary/array_initializer/mod.rs @@ -10,13 +10,16 @@ #[cfg(test)] mod tests; -use crate::syntax::{ - ast::{ - node::{ArrayDecl, Node, Spread}, - Const, Punctuator, - }, - parser::{ - expression::AssignmentExpression, AllowAwait, AllowYield, Cursor, ParseError, TokenParser, +use crate::{ + syntax::{ + ast::{ + node::{ArrayDecl, Node, Spread}, + Const, Punctuator, + }, + parser::{ + expression::AssignmentExpression, AllowAwait, AllowYield, Cursor, ParseError, + TokenParser, + }, }, BoaProfiler, }; diff --git a/boa/src/syntax/parser/expression/primary/object_initializer/mod.rs b/boa/src/syntax/parser/expression/primary/object_initializer/mod.rs index 2be9bb24a0f..3d2dc14ea45 100644 --- a/boa/src/syntax/parser/expression/primary/object_initializer/mod.rs +++ b/boa/src/syntax/parser/expression/primary/object_initializer/mod.rs @@ -10,16 +10,18 @@ #[cfg(test)] mod tests; -use crate::syntax::{ - ast::{ - node::{self, FunctionExpr, MethodDefinitionKind, Node, Object}, - token::{Token, TokenKind}, - Punctuator, - }, - parser::{ - expression::AssignmentExpression, - function::{FormalParameters, FunctionBody}, - AllowAwait, AllowIn, AllowYield, Cursor, ParseError, ParseResult, TokenParser, +use crate::{ + syntax::{ + ast::{ + node::{self, FunctionExpr, MethodDefinitionKind, Node, Object}, + token::{Token, TokenKind}, + Punctuator, + }, + parser::{ + expression::AssignmentExpression, + function::{FormalParameters, FunctionBody}, + AllowAwait, AllowIn, AllowYield, Cursor, ParseError, ParseResult, TokenParser, + }, }, BoaProfiler, }; diff --git a/boa/src/syntax/parser/statement/break_stm/mod.rs b/boa/src/syntax/parser/statement/break_stm/mod.rs index 21a6d9b5cb3..526cd547a0f 100644 --- a/boa/src/syntax/parser/statement/break_stm/mod.rs +++ b/boa/src/syntax/parser/statement/break_stm/mod.rs @@ -11,9 +11,10 @@ mod tests; use super::LabelIdentifier; -use crate::syntax::{ - ast::{node::Break, Node, Keyword, Punctuator, TokenKind}, - parser::{AllowAwait, AllowYield, Cursor, ParseError, TokenParser}, +use crate::{ + syntax::{ + ast::{node::Break, Keyword, Punctuator, TokenKind}, + parser::{AllowAwait, AllowYield, Cursor, ParseError, TokenParser}, }, BoaProfiler, }; diff --git a/boa/src/syntax/parser/statement/continue_stm/mod.rs b/boa/src/syntax/parser/statement/continue_stm/mod.rs index c921c5395d5..8925f655fc5 100644 --- a/boa/src/syntax/parser/statement/continue_stm/mod.rs +++ b/boa/src/syntax/parser/statement/continue_stm/mod.rs @@ -11,9 +11,10 @@ mod tests; use super::LabelIdentifier; -use crate::syntax::{ - ast::{node::Continue, Keyword, Punctuator, TokenKind}, - parser::{AllowAwait, AllowYield, Cursor, ParseError, TokenParser}, +use crate::{ + syntax::{ + ast::{node::Continue, Keyword, Punctuator, TokenKind}, + parser::{AllowAwait, AllowYield, Cursor, ParseError, TokenParser}, }, BoaProfiler, }; diff --git a/boa/src/syntax/parser/statement/declaration/mod.rs b/boa/src/syntax/parser/statement/declaration/mod.rs index 4ea3d74a14a..0e0bc52e928 100644 --- a/boa/src/syntax/parser/statement/declaration/mod.rs +++ b/boa/src/syntax/parser/statement/declaration/mod.rs @@ -13,9 +13,10 @@ mod lexical; mod tests; use self::{hoistable::HoistableDeclaration, lexical::LexicalDeclaration}; -use crate::syntax::{ - ast::{Keyword, Node, TokenKind}, - parser::{AllowAwait, AllowYield, Cursor, ParseError, TokenParser}, +use crate::{ + syntax::{ + ast::{Keyword, Node, TokenKind}, + parser::{AllowAwait, AllowYield, Cursor, ParseError, TokenParser}, }, BoaProfiler, }; diff --git a/boa/src/syntax/parser/statement/if_stm/mod.rs b/boa/src/syntax/parser/statement/if_stm/mod.rs index 3767ace6af3..ff1e47de71d 100644 --- a/boa/src/syntax/parser/statement/if_stm/mod.rs +++ b/boa/src/syntax/parser/statement/if_stm/mod.rs @@ -2,11 +2,13 @@ mod tests; use super::Statement; -use crate::syntax::{ - ast::{node::If, Keyword, Node, Punctuator, TokenKind}, - parser::{ - expression::Expression, AllowAwait, AllowReturn, AllowYield, Cursor, ParseError, - TokenParser, +use crate::{ + syntax::{ + ast::{node::If, Keyword, Node, Punctuator, TokenKind}, + parser::{ + expression::Expression, AllowAwait, AllowReturn, AllowYield, Cursor, ParseError, + TokenParser, + }, }, BoaProfiler, }; diff --git a/boa/src/syntax/parser/statement/iteration/do_while_statement.rs b/boa/src/syntax/parser/statement/iteration/do_while_statement.rs index 3cbd5552aa4..91613fba1d6 100644 --- a/boa/src/syntax/parser/statement/iteration/do_while_statement.rs +++ b/boa/src/syntax/parser/statement/iteration/do_while_statement.rs @@ -7,11 +7,13 @@ //! [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/do...while //! [spec]: https://tc39.es/ecma262/#sec-do-while-statement -use crate::syntax::{ - ast::{node::DoWhileLoop, Keyword, Punctuator, TokenKind}, - parser::{ - expression::Expression, statement::Statement, AllowAwait, AllowReturn, AllowYield, Cursor, - ParseError, TokenParser, +use crate::{ + syntax::{ + ast::{node::DoWhileLoop, Keyword, Punctuator, TokenKind}, + parser::{ + expression::Expression, statement::Statement, AllowAwait, AllowReturn, AllowYield, + Cursor, ParseError, TokenParser, + }, }, BoaProfiler, }; diff --git a/boa/src/syntax/parser/statement/iteration/while_statement.rs b/boa/src/syntax/parser/statement/iteration/while_statement.rs index 541968ff86e..72f4d445793 100644 --- a/boa/src/syntax/parser/statement/iteration/while_statement.rs +++ b/boa/src/syntax/parser/statement/iteration/while_statement.rs @@ -1,8 +1,10 @@ -use crate::syntax::{ - ast::{node::WhileLoop, Keyword, Punctuator}, - parser::{ - expression::Expression, statement::Statement, AllowAwait, AllowReturn, AllowYield, Cursor, - ParseError, TokenParser, +use crate::{ + syntax::{ + ast::{node::WhileLoop, Keyword, Punctuator}, + parser::{ + expression::Expression, statement::Statement, AllowAwait, AllowReturn, AllowYield, + Cursor, ParseError, TokenParser, + }, }, BoaProfiler, }; diff --git a/boa/src/syntax/parser/statement/return_stm/mod.rs b/boa/src/syntax/parser/statement/return_stm/mod.rs index 2e9c22f10af..c1b0c6cf082 100644 --- a/boa/src/syntax/parser/statement/return_stm/mod.rs +++ b/boa/src/syntax/parser/statement/return_stm/mod.rs @@ -1,9 +1,10 @@ #[cfg(test)] mod tests; -use crate::syntax::{ - ast::{node::Return, Keyword, Node, Punctuator, TokenKind}, - parser::{expression::Expression, AllowAwait, AllowYield, Cursor, ParseError, TokenParser}, +use crate::{ + syntax::{ + ast::{node::Return, Keyword, Node, Punctuator, TokenKind}, + parser::{expression::Expression, AllowAwait, AllowYield, Cursor, ParseError, TokenParser}, }, BoaProfiler, }; diff --git a/boa/src/syntax/parser/statement/switch/mod.rs b/boa/src/syntax/parser/statement/switch/mod.rs index c4b60258995..8a64086cf12 100644 --- a/boa/src/syntax/parser/statement/switch/mod.rs +++ b/boa/src/syntax/parser/statement/switch/mod.rs @@ -1,14 +1,16 @@ #[cfg(test)] mod tests; -use crate::syntax::{ - ast::{ - node::{Case, Switch}, - Keyword, Node, Punctuator, - }, - parser::{ - expression::Expression, AllowAwait, AllowReturn, AllowYield, Cursor, ParseError, - TokenParser, +use crate::{ + syntax::{ + ast::{ + node::{Case, Switch}, + Keyword, Node, Punctuator, + }, + parser::{ + expression::Expression, AllowAwait, AllowReturn, AllowYield, Cursor, ParseError, + TokenParser, + }, }, BoaProfiler, }; diff --git a/boa/src/syntax/parser/statement/throw/mod.rs b/boa/src/syntax/parser/statement/throw/mod.rs index 564facee9e2..1be0260b2ce 100644 --- a/boa/src/syntax/parser/statement/throw/mod.rs +++ b/boa/src/syntax/parser/statement/throw/mod.rs @@ -1,9 +1,10 @@ #[cfg(test)] mod tests; -use crate::syntax::{ - ast::{node::Throw, Keyword, Punctuator, TokenKind}, - parser::{expression::Expression, AllowAwait, AllowYield, Cursor, ParseError, TokenParser}, +use crate::{ + syntax::{ + ast::{node::Throw, Keyword, Punctuator, TokenKind}, + parser::{expression::Expression, AllowAwait, AllowYield, Cursor, ParseError, TokenParser}, }, BoaProfiler, };