From e4ac2743aaebcf96e20db1e75bf4f55f2422fc7b Mon Sep 17 00:00:00 2001 From: Paul Lancaster Date: Fri, 9 Oct 2020 22:50:02 +0100 Subject: [PATCH 01/27] Add async keyword --- boa/src/syntax/ast/keyword.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/boa/src/syntax/ast/keyword.rs b/boa/src/syntax/ast/keyword.rs index 566d25b3224..925b8c9c9c6 100644 --- a/boa/src/syntax/ast/keyword.rs +++ b/boa/src/syntax/ast/keyword.rs @@ -36,6 +36,16 @@ pub enum Keyword { /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/await Await, + /// The `async` keyword. + /// + /// More information: + /// - [ECMAScript reference][spec] + /// - [MDN documentation][mdn] + /// + /// [spec]: https://tc39.es/ecma262/#prod-AsyncMethod + /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function + Async, + /// The `break` keyword. /// /// More information: @@ -454,6 +464,7 @@ impl Keyword { pub fn as_str(self) -> &'static str { match self { Self::Await => "await", + Self::Async => "async", Self::Break => "break", Self::Case => "case", Self::Catch => "catch", @@ -526,6 +537,7 @@ impl FromStr for Keyword { fn from_str(s: &str) -> Result { match s { "await" => Ok(Self::Await), + "async" => Ok(Self::Async), "break" => Ok(Self::Break), "case" => Ok(Self::Case), "catch" => Ok(Self::Catch), From f7ca45c3ff259e04a43d999c424df42e6561b577 Mon Sep 17 00:00:00 2001 From: Paul Lancaster Date: Fri, 9 Oct 2020 23:29:39 +0100 Subject: [PATCH 02/27] Created AsyncFunctionDecl/Expr nodes --- .../declaration/async_function_decl/mod.rs | 92 ++++++++++++++++++ .../declaration/async_function_expr/mod.rs | 94 +++++++++++++++++++ boa/src/syntax/ast/node/declaration/mod.rs | 4 + boa/src/syntax/ast/node/mod.rs | 16 +++- 4 files changed, 203 insertions(+), 3 deletions(-) create mode 100644 boa/src/syntax/ast/node/declaration/async_function_decl/mod.rs create mode 100644 boa/src/syntax/ast/node/declaration/async_function_expr/mod.rs diff --git a/boa/src/syntax/ast/node/declaration/async_function_decl/mod.rs b/boa/src/syntax/ast/node/declaration/async_function_decl/mod.rs new file mode 100644 index 00000000000..44d47e36ba3 --- /dev/null +++ b/boa/src/syntax/ast/node/declaration/async_function_decl/mod.rs @@ -0,0 +1,92 @@ +use crate::{ + exec::Executable, + syntax::ast::node::{join_nodes, FormalParameter, Node, StatementList}, + BoaProfiler, Context, Result, Value, +}; +use gc::{Finalize, Trace}; +use std::fmt; + +#[cfg(feature = "serde")] +use serde::{Deserialize, Serialize}; + +/// Async Function Declaration. +/// +/// More information: +/// - [ECMAScript reference][spec] +/// - [MDN documentation][mdn] +/// +/// [spec]: https://tc39.es/ecma262/#sec-async-function-prototype-properties +/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +#[derive(Clone, Debug, Trace, Finalize, PartialEq)] +pub struct AsyncFunctionDecl { + name: Box, + parameters: Box<[FormalParameter]>, + body: StatementList, +} + +impl AsyncFunctionDecl { + /// Creates a new async function declaration. + pub(in crate::syntax) fn new(name: N, parameters: P, body: B) -> Self + where + N: Into>, + P: Into>, + B: Into, + { + Self { + name: name.into(), + parameters: parameters.into(), + body: body.into(), + } + } + + /// Gets the name of the async function declaration. + pub fn name(&self) -> &str { + &self.name + } + + /// Gets the list of parameters of the async function declaration. + pub fn parameters(&self) -> &[FormalParameter] { + &self.parameters + } + + /// Gets the body of the async function declaration. + pub fn body(&self) -> &[Node] { + self.body.statements() + } + + /// Implements the display formatting with indentation. + pub(in crate::syntax::ast::node) fn display( + &self, + f: &mut fmt::Formatter<'_>, + indentation: usize, + ) -> fmt::Result { + write!(f, "async function {}(", self.name)?; + join_nodes(f, &self.parameters)?; + f.write_str(") {{")?; + + self.body.display(f, indentation + 1)?; + + writeln!(f, "}}") + } +} + +impl Executable for AsyncFunctionDecl { + fn run(&self, interpreter: &mut Context) -> Result { + let _timer = BoaProfiler::global().start_event("AsyncFunctionDecl", "exec"); + unimplemented!("Execute AsyncFunctionDecl"); + Ok(Value::undefined()) + } +} + +impl From for Node { + fn from(decl: AsyncFunctionDecl) -> Self { + Self::AsyncFunctionDecl(decl) + } +} + +impl fmt::Display for AsyncFunctionDecl { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.display(f, 0) + } +} diff --git a/boa/src/syntax/ast/node/declaration/async_function_expr/mod.rs b/boa/src/syntax/ast/node/declaration/async_function_expr/mod.rs new file mode 100644 index 00000000000..2a1979d717e --- /dev/null +++ b/boa/src/syntax/ast/node/declaration/async_function_expr/mod.rs @@ -0,0 +1,94 @@ +use crate::{ + exec::Executable, + syntax::ast::node::{join_nodes, FormalParameter, Node, StatementList}, + Context, Result, Value, +}; +use gc::{Finalize, Trace}; +use std::fmt; + +#[cfg(feature = "serde")] +use serde::{Deserialize, Serialize}; + +/// AsyncFunctionExpr. +/// +/// More information: +/// - [ECMAScript reference][spec] +/// - [MDN documentation][mdn] +/// +/// [spec]: https://tc39.es/ecma262/#prod-AsyncFunctionExpression +/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/async_function +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +#[derive(Clone, Debug, Trace, Finalize, PartialEq)] +pub struct AsyncFunctionExpr { + name: Option>, + parameters: Box<[FormalParameter]>, + body: StatementList, +} + +impl AsyncFunctionExpr { + /// Creates a new function expression + pub(in crate::syntax) fn new(name: N, parameters: P, body: B) -> Self + where + N: Into>>, + P: Into>, + B: Into, + { + Self { + name: name.into(), + parameters: parameters.into(), + body: body.into(), + } + } + + /// Gets the name of the function declaration. + pub fn name(&self) -> Option<&str> { + self.name.as_ref().map(Box::as_ref) + } + + /// Gets the list of parameters of the function declaration. + pub fn parameters(&self) -> &[FormalParameter] { + &self.parameters + } + + /// Gets the body of the function declaration. + pub fn body(&self) -> &[Node] { + self.body.statements() + } + + /// Implements the display formatting with indentation. + pub(in crate::syntax::ast::node) fn display( + &self, + f: &mut fmt::Formatter<'_>, + indentation: usize, + ) -> fmt::Result { + f.write_str("function")?; + if let Some(ref name) = self.name { + write!(f, " {}", name)?; + } + f.write_str("(")?; + join_nodes(f, &self.parameters)?; + f.write_str(") {{")?; + + self.body.display(f, indentation + 1)?; + + writeln!(f, "}}") + } +} + +impl Executable for AsyncFunctionExpr { + fn run(&self, interpreter: &mut Context) -> Result { + unimplemented!("Execute AsyncFunctionExpr"); + } +} + +impl fmt::Display for AsyncFunctionExpr { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.display(f, 0) + } +} + +impl From for Node { + fn from(expr: AsyncFunctionExpr) -> Self { + Self::AsyncFunctionExpr(expr) + } +} diff --git a/boa/src/syntax/ast/node/declaration/mod.rs b/boa/src/syntax/ast/node/declaration/mod.rs index 9e5d181a81f..a256a75e87f 100644 --- a/boa/src/syntax/ast/node/declaration/mod.rs +++ b/boa/src/syntax/ast/node/declaration/mod.rs @@ -1,6 +1,8 @@ //! Declaration nodes pub mod arrow_function_decl; +pub mod async_function_decl; +pub mod async_function_expr; pub mod const_decl_list; pub mod function_decl; pub mod function_expr; @@ -9,6 +11,8 @@ pub mod var_decl_list; pub use self::{ arrow_function_decl::ArrowFunctionDecl, + async_function_decl::AsyncFunctionDecl, + async_function_expr::AsyncFunctionExpr, const_decl_list::{ConstDecl, ConstDeclList}, function_decl::FunctionDecl, function_expr::FunctionExpr, diff --git a/boa/src/syntax/ast/node/mod.rs b/boa/src/syntax/ast/node/mod.rs index 5180c1ad706..d65914c9e8f 100644 --- a/boa/src/syntax/ast/node/mod.rs +++ b/boa/src/syntax/ast/node/mod.rs @@ -26,8 +26,8 @@ pub use self::{ call::Call, conditional::{ConditionalOp, If}, declaration::{ - ArrowFunctionDecl, ConstDecl, ConstDeclList, FunctionDecl, FunctionExpr, LetDecl, - LetDeclList, VarDecl, VarDeclList, + ArrowFunctionDecl, AsyncFunctionDecl, AsyncFunctionExpr, ConstDecl, ConstDeclList, + FunctionDecl, FunctionExpr, LetDecl, LetDeclList, VarDecl, VarDeclList, }, field::{GetConstField, GetField}, identifier::Identifier, @@ -65,6 +65,12 @@ pub enum Node { /// An assignment operator node. [More information](./operator/struct.Assign.html). Assign(Assign), + /// An async function declaration node. [More information](./declaration/struct.AsyncFunctionDecl.html). + AsyncFunctionDecl(AsyncFunctionDecl), + + /// An async function expression node. [More information](./declaration/struct.AsyncFunctionExpr.html). + AsyncFunctionExpr(AsyncFunctionExpr), + /// A binary operator node. [More information](./operator/struct.BinOp.html). BinOp(BinOp), @@ -104,7 +110,7 @@ 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 expression node. [More information](./declaration/struct.FunctionExpr.html). FunctionExpr(FunctionExpr), /// Provides access to an object types' constant properties. [More information](./declaration/struct.GetConstField.html). @@ -243,6 +249,8 @@ impl Node { Self::Assign(ref op) => Display::fmt(op, f), Self::LetDeclList(ref decl) => Display::fmt(decl, f), Self::ConstDeclList(ref decl) => Display::fmt(decl, f), + Self::AsyncFunctionDecl(ref decl) => decl.display(f, indentation), + Self::AsyncFunctionExpr(ref expr) => expr.display(f, indentation), } } } @@ -251,6 +259,8 @@ impl Executable for Node { fn run(&self, interpreter: &mut Context) -> Result { let _timer = BoaProfiler::global().start_event("Executable", "exec"); match *self { + Node::AsyncFunctionDecl(ref decl) => decl.run(interpreter), + Node::AsyncFunctionExpr(ref function_expr) => function_expr.run(interpreter), Node::Call(ref call) => call.run(interpreter), Node::Const(Const::Null) => Ok(Value::null()), Node::Const(Const::Num(num)) => Ok(Value::rational(num)), From c2bf1b3cfbcd157236ed06f381bd8e69078417ef Mon Sep 17 00:00:00 2001 From: Paul Lancaster Date: Fri, 9 Oct 2020 23:47:35 +0100 Subject: [PATCH 03/27] AsyncFunctionDecl/Expr parser created (not impl) --- .../primary/async_function_expression.rs | 42 +++++++++++++++++ .../syntax/parser/expression/primary/mod.rs | 8 +++- .../parser/statement/declaration/hoistable.rs | 47 ++++++++++++++++++- 3 files changed, 94 insertions(+), 3 deletions(-) create mode 100644 boa/src/syntax/parser/expression/primary/async_function_expression.rs diff --git a/boa/src/syntax/parser/expression/primary/async_function_expression.rs b/boa/src/syntax/parser/expression/primary/async_function_expression.rs new file mode 100644 index 00000000000..61f24e84129 --- /dev/null +++ b/boa/src/syntax/parser/expression/primary/async_function_expression.rs @@ -0,0 +1,42 @@ +//! Async Function expression parsing. +//! +//! More information: +//! - [MDN documentation][mdn] +//! - [ECMAScript specification][spec] +//! +//! [mdn]: +//! [spec]: + +use crate::{ + syntax::{ + ast::node::AsyncFunctionExpr, + parser::{Cursor, ParseError, TokenParser}, + }, + BoaProfiler, +}; + +use std::io::Read; + +/// Async Function expression parsing. +/// +/// More information: +/// - [MDN documentation][mdn] +/// - [ECMAScript specification][spec] +/// +/// [mdn]: +/// [spec]: +#[derive(Debug, Clone, Copy)] +pub(super) struct AsyncFunctionExpression; + +impl TokenParser for AsyncFunctionExpression +where + R: Read, +{ + type Output = AsyncFunctionExpr; + + fn parse(self, cursor: &mut Cursor) -> Result { + let _timer = BoaProfiler::global().start_event("AsyncFunctionExpression", "Parsing"); + + unimplemented!("Async function expression parse"); + } +} diff --git a/boa/src/syntax/parser/expression/primary/mod.rs b/boa/src/syntax/parser/expression/primary/mod.rs index 50cc95cc8af..9963df4b572 100644 --- a/boa/src/syntax/parser/expression/primary/mod.rs +++ b/boa/src/syntax/parser/expression/primary/mod.rs @@ -8,14 +8,15 @@ //! [spec]: https://tc39.es/ecma262/#prod-PrimaryExpression mod array_initializer; +mod async_function_expression; mod function_expression; mod object_initializer; #[cfg(test)] mod tests; use self::{ - array_initializer::ArrayLiteral, function_expression::FunctionExpression, - object_initializer::ObjectLiteral, + array_initializer::ArrayLiteral, async_function_expression::AsyncFunctionExpression, + function_expression::FunctionExpression, object_initializer::ObjectLiteral, }; use super::Expression; use crate::{ @@ -77,6 +78,9 @@ where TokenKind::Keyword(Keyword::Function) => { FunctionExpression.parse(cursor).map(Node::from) } + TokenKind::Keyword(Keyword::Async) => { + AsyncFunctionExpression.parse(cursor).map(Node::from) + } TokenKind::Punctuator(Punctuator::OpenParen) => { cursor.set_goal(InputElement::RegExp); let expr = diff --git a/boa/src/syntax/parser/statement/declaration/hoistable.rs b/boa/src/syntax/parser/statement/declaration/hoistable.rs index 1f18c099762..a059bbe95db 100644 --- a/boa/src/syntax/parser/statement/declaration/hoistable.rs +++ b/boa/src/syntax/parser/statement/declaration/hoistable.rs @@ -7,7 +7,10 @@ use crate::{ syntax::{ - ast::{node::FunctionDecl, Keyword, Node, Punctuator}, + ast::{ + node::{AsyncFunctionDecl, FunctionDecl}, + Keyword, Node, Punctuator, + }, parser::{ function::FormalParameters, function::FunctionBody, statement::BindingIdentifier, AllowAwait, AllowDefault, AllowYield, Cursor, ParseError, ParseResult, TokenParser, @@ -119,3 +122,45 @@ where Ok(FunctionDecl::new(name, params, body)) } } + +/// Async Function declaration parsing. +/// +/// More information: +/// - [MDN documentation][mdn] +/// - [ECMAScript specification][spec] +/// +/// [mdn]: +/// [spec]: +#[derive(Debug, Clone, Copy)] +struct AsyncFunctionDeclaration { + allow_yield: AllowYield, + allow_await: AllowAwait, + is_default: AllowDefault, +} + +impl AsyncFunctionDeclaration { + /// Creates a new `FunctionDeclaration` parser. + fn new(allow_yield: Y, allow_await: A, is_default: D) -> Self + where + Y: Into, + A: Into, + D: Into, + { + Self { + allow_yield: allow_yield.into(), + allow_await: allow_await.into(), + is_default: is_default.into(), + } + } +} + +impl TokenParser for AsyncFunctionDeclaration +where + R: Read, +{ + type Output = AsyncFunctionDecl; + + fn parse(self, cursor: &mut Cursor) -> Result { + unimplemented!("AsyncFunctionDecl parse"); + } +} From 5bc89413debbbb0211c4a99e55e6cc009767250b Mon Sep 17 00:00:00 2001 From: Paul Lancaster Date: Sat, 10 Oct 2020 00:00:55 +0100 Subject: [PATCH 04/27] Add async to HoistableDeclaration --- .../parser/statement/declaration/hoistable.rs | 22 ++++++++++++++----- .../parser/statement/declaration/mod.rs | 2 +- 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/boa/src/syntax/parser/statement/declaration/hoistable.rs b/boa/src/syntax/parser/statement/declaration/hoistable.rs index a059bbe95db..1fb5fe1fc56 100644 --- a/boa/src/syntax/parser/statement/declaration/hoistable.rs +++ b/boa/src/syntax/parser/statement/declaration/hoistable.rs @@ -11,6 +11,7 @@ use crate::{ node::{AsyncFunctionDecl, FunctionDecl}, Keyword, Node, Punctuator, }, + lexer::TokenKind, parser::{ function::FormalParameters, function::FunctionBody, statement::BindingIdentifier, AllowAwait, AllowDefault, AllowYield, Cursor, ParseError, ParseResult, TokenParser, @@ -18,7 +19,6 @@ use crate::{ }, BoaProfiler, }; - use std::io::Read; /// Hoistable declaration parsing. @@ -58,10 +58,21 @@ where fn parse(self, cursor: &mut Cursor) -> ParseResult { let _timer = BoaProfiler::global().start_event("HoistableDeclaration", "Parsing"); - // TODO: check for generators and async functions + generators - FunctionDeclaration::new(self.allow_yield, self.allow_await, self.is_default) - .parse(cursor) - .map(Node::from) + let tok = cursor.peek(0)?.ok_or(ParseError::AbruptEnd)?; + + match tok.kind() { + TokenKind::Keyword(Keyword::Function) => { + FunctionDeclaration::new(self.allow_yield, self.allow_await, self.is_default) + .parse(cursor) + .map(Node::from) + } + TokenKind::Keyword(Keyword::Async) => { + AsyncFunctionDeclaration::new(self.allow_yield, self.allow_await, false) + .parse(cursor) + .map(Node::from) + } + _ => unreachable!("unknown token found: {:?}", tok), + } } } @@ -161,6 +172,7 @@ where type Output = AsyncFunctionDecl; fn parse(self, cursor: &mut Cursor) -> Result { + cursor.expect(Keyword::Async, "async function declaration")?; unimplemented!("AsyncFunctionDecl parse"); } } diff --git a/boa/src/syntax/parser/statement/declaration/mod.rs b/boa/src/syntax/parser/statement/declaration/mod.rs index d1c1c9dd985..518748d2e7a 100644 --- a/boa/src/syntax/parser/statement/declaration/mod.rs +++ b/boa/src/syntax/parser/statement/declaration/mod.rs @@ -63,7 +63,7 @@ where let tok = cursor.peek(0)?.ok_or(ParseError::AbruptEnd)?; match tok.kind() { - TokenKind::Keyword(Keyword::Function) => { + TokenKind::Keyword(Keyword::Function) | TokenKind::Keyword(Keyword::Async) => { HoistableDeclaration::new(self.allow_yield, self.allow_await, false).parse(cursor) } TokenKind::Keyword(Keyword::Const) | TokenKind::Keyword(Keyword::Let) => { From 8849bacbd55b52139fea8c8b1ef0f0592d30688a Mon Sep 17 00:00:00 2001 From: Paul Lancaster Date: Sat, 10 Oct 2020 10:21:08 +0100 Subject: [PATCH 05/27] Added expect_no_lineterminator, updated some cursor docs --- boa/src/syntax/parser/cursor/mod.rs | 31 ++++++++++++++----- .../parser/statement/declaration/hoistable.rs | 7 +++++ 2 files changed, 31 insertions(+), 7 deletions(-) diff --git a/boa/src/syntax/parser/cursor/mod.rs b/boa/src/syntax/parser/cursor/mod.rs index b33851f7fd9..0d938741f7a 100644 --- a/boa/src/syntax/parser/cursor/mod.rs +++ b/boa/src/syntax/parser/cursor/mod.rs @@ -67,10 +67,6 @@ where } /// Returns an error if the next token is not of kind `kind`. - /// - /// Note: it will consume the next token only if the next token is the expected type. - /// - /// If skip_line_terminators is true then line terminators will be discarded. #[inline] pub(super) fn expect(&mut self, kind: K, context: &'static str) -> Result where @@ -134,7 +130,7 @@ where /// /// It expects that the token stream does not end here. /// - /// This is just syntatic sugar for a .peek(skip_n, false) call followed by a check that the result is not a line terminator or None. + /// This is just syntatic sugar for a .peek(skip_n) call followed by a check that the result is not a line terminator or None. #[inline] pub(super) fn peek_expect_no_lineterminator( &mut self, @@ -151,13 +147,34 @@ where } } + /// Returns an error if the next token is not of kind `kind`. + #[inline] + pub(super) fn expect_no_skip_lineterminator( + &mut self, + kind: K, + context: &'static str, + ) -> Result + where + K: Into, + { + let next_token = self + .buffered_lexer + .next(false)? + .ok_or(ParseError::AbruptEnd)?; + let kind = kind.into(); + + if next_token.kind() == &kind { + Ok(next_token) + } else { + Err(ParseError::expected(vec![kind], next_token, context)) + } + } + /// Advance the cursor to the next token and retrieve it, only if it's of `kind` type. /// /// When the next token is a `kind` token, get the token, otherwise return `None`. /// /// No next token also returns None. - /// - /// If skip_line_terminators is true then line terminators will be discarded. #[inline] pub(super) fn next_if(&mut self, kind: K) -> Result, ParseError> where diff --git a/boa/src/syntax/parser/statement/declaration/hoistable.rs b/boa/src/syntax/parser/statement/declaration/hoistable.rs index 1fb5fe1fc56..66fa732b1b2 100644 --- a/boa/src/syntax/parser/statement/declaration/hoistable.rs +++ b/boa/src/syntax/parser/statement/declaration/hoistable.rs @@ -173,6 +173,13 @@ where fn parse(self, cursor: &mut Cursor) -> Result { cursor.expect(Keyword::Async, "async function declaration")?; + let tok = cursor.peek_expect_no_lineterminator(0)?; + + match tok.kind() { + TokenKind::Keyword(Keyword::Function) => {} + _ => {} + } + unimplemented!("AsyncFunctionDecl parse"); } } From 0bfe141b6ae88fb1f034a4f1cf8c8f18cc4ea80e Mon Sep 17 00:00:00 2001 From: Paul Lancaster Date: Sat, 10 Oct 2020 11:07:36 +0100 Subject: [PATCH 06/27] AsyncFunctionDecl parsing --- .../declaration/async_function_decl/mod.rs | 17 ++++++--- .../parser/statement/declaration/hoistable.rs | 38 ++++++++++++++++--- 2 files changed, 44 insertions(+), 11 deletions(-) diff --git a/boa/src/syntax/ast/node/declaration/async_function_decl/mod.rs b/boa/src/syntax/ast/node/declaration/async_function_decl/mod.rs index 44d47e36ba3..f38a6ef0ff4 100644 --- a/boa/src/syntax/ast/node/declaration/async_function_decl/mod.rs +++ b/boa/src/syntax/ast/node/declaration/async_function_decl/mod.rs @@ -20,7 +20,7 @@ use serde::{Deserialize, Serialize}; #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[derive(Clone, Debug, Trace, Finalize, PartialEq)] pub struct AsyncFunctionDecl { - name: Box, + name: Option>, parameters: Box<[FormalParameter]>, body: StatementList, } @@ -29,7 +29,7 @@ impl AsyncFunctionDecl { /// Creates a new async function declaration. pub(in crate::syntax) fn new(name: N, parameters: P, body: B) -> Self where - N: Into>, + N: Into>>, P: Into>, B: Into, { @@ -41,8 +41,8 @@ impl AsyncFunctionDecl { } /// Gets the name of the async function declaration. - pub fn name(&self) -> &str { - &self.name + pub fn name(&self) -> Option<&str> { + self.name.as_deref() } /// Gets the list of parameters of the async function declaration. @@ -61,7 +61,14 @@ impl AsyncFunctionDecl { f: &mut fmt::Formatter<'_>, indentation: usize, ) -> fmt::Result { - write!(f, "async function {}(", self.name)?; + match &self.name { + Some(name) => { + write!(f, "async function {}(", name)?; + } + None => { + write!(f, "async function (")?; + } + } join_nodes(f, &self.parameters)?; f.write_str(") {{")?; diff --git a/boa/src/syntax/parser/statement/declaration/hoistable.rs b/boa/src/syntax/parser/statement/declaration/hoistable.rs index 66fa732b1b2..04e5704f9f1 100644 --- a/boa/src/syntax/parser/statement/declaration/hoistable.rs +++ b/boa/src/syntax/parser/statement/declaration/hoistable.rs @@ -173,13 +173,39 @@ where fn parse(self, cursor: &mut Cursor) -> Result { cursor.expect(Keyword::Async, "async function declaration")?; - let tok = cursor.peek_expect_no_lineterminator(0)?; + cursor.expect_no_skip_lineterminator(Keyword::Function, "async function declaration")?; + let tok = cursor.peek(0)?; + + let name = if let Some(token) = tok { + match token.kind() { + TokenKind::Punctuator(Punctuator::OpenParen) => { + if !self.is_default.0 { + return Err(ParseError::unexpected( + token.clone(), + "Unexpected missing identifier for async function decl", + )); + } + None + } + _ => { + Some(BindingIdentifier::new(self.allow_yield, self.allow_await).parse(cursor)?) + } + } + } else { + return Err(ParseError::AbruptEnd); + }; - match tok.kind() { - TokenKind::Keyword(Keyword::Function) => {} - _ => {} - } + cursor.expect(Punctuator::OpenParen, "async function declaration")?; + + let params = FormalParameters::new(!self.allow_yield.0, true).parse(cursor)?; + + cursor.expect(Punctuator::CloseParen, "async function declaration")?; + cursor.expect(Punctuator::OpenBlock, "async function declaration")?; + + let body = FunctionBody::new(!self.allow_yield.0, true).parse(cursor)?; + + cursor.expect(Punctuator::CloseBlock, "async function declaration")?; - unimplemented!("AsyncFunctionDecl parse"); + Ok(AsyncFunctionDecl::new(name, params, body)) } } From 35fb7455cac402452b5d4d1d4bb93cef50e51d94 Mon Sep 17 00:00:00 2001 From: Paul Lancaster Date: Sat, 10 Oct 2020 11:22:27 +0100 Subject: [PATCH 07/27] AsyncFunctionExpr parsing --- .../primary/async_function_expression.rs | 51 +++++++++++++++++-- .../syntax/parser/expression/primary/mod.rs | 6 +-- 2 files changed, 49 insertions(+), 8 deletions(-) diff --git a/boa/src/syntax/parser/expression/primary/async_function_expression.rs b/boa/src/syntax/parser/expression/primary/async_function_expression.rs index 61f24e84129..d030f848d62 100644 --- a/boa/src/syntax/parser/expression/primary/async_function_expression.rs +++ b/boa/src/syntax/parser/expression/primary/async_function_expression.rs @@ -6,11 +6,15 @@ //! //! [mdn]: //! [spec]: - use crate::{ syntax::{ - ast::node::AsyncFunctionExpr, - parser::{Cursor, ParseError, TokenParser}, + ast::{node::AsyncFunctionExpr, Keyword, Punctuator}, + lexer::TokenKind, + parser::{ + function::{FormalParameters, FunctionBody}, + statement::BindingIdentifier, + AllowYield, Cursor, ParseError, TokenParser, + }, }, BoaProfiler, }; @@ -26,7 +30,21 @@ use std::io::Read; /// [mdn]: /// [spec]: #[derive(Debug, Clone, Copy)] -pub(super) struct AsyncFunctionExpression; +pub(super) struct AsyncFunctionExpression { + allow_yield: AllowYield, +} + +impl AsyncFunctionExpression { + /// Creates a new `AsyncFunctionExpression` parser. + pub(super) fn new(allow_yield: Y) -> Self + where + Y: Into, + { + Self { + allow_yield: allow_yield.into(), + } + } +} impl TokenParser for AsyncFunctionExpression where @@ -36,7 +54,30 @@ where fn parse(self, cursor: &mut Cursor) -> Result { let _timer = BoaProfiler::global().start_event("AsyncFunctionExpression", "Parsing"); + cursor.expect_no_skip_lineterminator(Keyword::Function, "async function expression")?; + + let tok = cursor.peek(0)?; + + let name = if let Some(token) = tok { + match token.kind() { + TokenKind::Punctuator(Punctuator::OpenParen) => None, + _ => Some(BindingIdentifier::new(self.allow_yield, true).parse(cursor)?), + } + } else { + return Err(ParseError::AbruptEnd); + }; + + cursor.expect(Punctuator::OpenParen, "function expression")?; + + let params = FormalParameters::new(!self.allow_yield.0, true).parse(cursor)?; + + cursor.expect(Punctuator::CloseParen, "function expression")?; + cursor.expect(Punctuator::OpenBlock, "function expression")?; + + let body = FunctionBody::new(!self.allow_yield.0, true).parse(cursor)?; + + cursor.expect(Punctuator::CloseBlock, "function expression")?; - unimplemented!("Async function expression parse"); + Ok(AsyncFunctionExpr::new(name, params, body)) } } diff --git a/boa/src/syntax/parser/expression/primary/mod.rs b/boa/src/syntax/parser/expression/primary/mod.rs index 9963df4b572..7f55346663e 100644 --- a/boa/src/syntax/parser/expression/primary/mod.rs +++ b/boa/src/syntax/parser/expression/primary/mod.rs @@ -78,9 +78,9 @@ where TokenKind::Keyword(Keyword::Function) => { FunctionExpression.parse(cursor).map(Node::from) } - TokenKind::Keyword(Keyword::Async) => { - AsyncFunctionExpression.parse(cursor).map(Node::from) - } + TokenKind::Keyword(Keyword::Async) => AsyncFunctionExpression::new(self.allow_yield) + .parse(cursor) + .map(Node::from), TokenKind::Punctuator(Punctuator::OpenParen) => { cursor.set_goal(InputElement::RegExp); let expr = From 9aa6c77b0e29b9dcbf89612e03fec6ae789b8d0f Mon Sep 17 00:00:00 2001 From: Paul Lancaster Date: Sat, 10 Oct 2020 12:40:05 +0100 Subject: [PATCH 08/27] Await expression parsing --- boa/src/syntax/ast/node/await_expr/mod.rs | 59 +++++++++++++++++++ boa/src/syntax/ast/node/mod.rs | 7 +++ .../syntax/parser/expression/await_expr.rs | 58 ++++++++++++++++++ boa/src/syntax/parser/expression/mod.rs | 2 + .../primary/object_initializer/mod.rs | 8 +++ boa/src/syntax/parser/expression/unary.rs | 4 +- boa/src/syntax/parser/statement/mod.rs | 4 ++ 7 files changed, 140 insertions(+), 2 deletions(-) create mode 100644 boa/src/syntax/ast/node/await_expr/mod.rs create mode 100644 boa/src/syntax/parser/expression/await_expr.rs diff --git a/boa/src/syntax/ast/node/await_expr/mod.rs b/boa/src/syntax/ast/node/await_expr/mod.rs new file mode 100644 index 00000000000..2d8b3410e56 --- /dev/null +++ b/boa/src/syntax/ast/node/await_expr/mod.rs @@ -0,0 +1,59 @@ +//! Await expression node. + +use super::Node; +use crate::{exec::Executable, BoaProfiler, Context, Result, Value}; +use gc::{Finalize, Trace}; +use std::fmt; + +#[cfg(feature = "serde")] +use serde::{Deserialize, Serialize}; + +/// +/// +/// More information: +/// - [ECMAScript reference][spec] +/// - [MDN documentation][mdn] +/// +/// [spec]: +/// [mdn]: +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +#[derive(Clone, Debug, Trace, Finalize, PartialEq)] +pub struct AwaitExpr { + expr: Box, +} + +impl Executable for AwaitExpr { + fn run(&self, interpreter: &mut Context) -> Result { + let _timer = BoaProfiler::global().start_event("AwaitExpression", "exec"); + unimplemented!("Await expression execution"); + } +} + +impl AwaitExpr { + /// Implements the display formatting with indentation. + pub(super) fn display(&self, f: &mut fmt::Formatter<'_>, indentation: usize) -> fmt::Result { + writeln!(f, "await ")?; + self.expr.display(f, indentation) + } +} + +impl From for AwaitExpr +where + T: Into>, +{ + fn from(e: T) -> Self { + Self { expr: e.into() } + } +} + +impl fmt::Display for AwaitExpr { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.display(f, 0) + } +} + +impl From for Node { + fn from(awaitexpr: AwaitExpr) -> Self { + Self::AwaitExpr(awaitexpr) + } +} diff --git a/boa/src/syntax/ast/node/mod.rs b/boa/src/syntax/ast/node/mod.rs index d65914c9e8f..70515bf144c 100644 --- a/boa/src/syntax/ast/node/mod.rs +++ b/boa/src/syntax/ast/node/mod.rs @@ -1,6 +1,7 @@ //! This module implements the `Node` structure, which composes the AST. pub mod array; +pub mod await_expr; pub mod block; pub mod break_node; pub mod call; @@ -21,6 +22,7 @@ pub mod try_node; pub use self::{ array::ArrayDecl, + await_expr::AwaitExpr, block::Block, break_node::Break, call::Call, @@ -71,6 +73,9 @@ pub enum Node { /// An async function expression node. [More information](./declaration/struct.AsyncFunctionExpr.html). AsyncFunctionExpr(AsyncFunctionExpr), + /// An await expression node. [More information](./await_expr/struct.AwaitExpression.html). + AwaitExpr(AwaitExpr), + /// A binary operator node. [More information](./operator/struct.BinOp.html). BinOp(BinOp), @@ -251,6 +256,7 @@ impl Node { Self::ConstDeclList(ref decl) => Display::fmt(decl, f), Self::AsyncFunctionDecl(ref decl) => decl.display(f, indentation), Self::AsyncFunctionExpr(ref expr) => expr.display(f, indentation), + Self::AwaitExpr(ref expr) => expr.display(f, indentation), } } } @@ -261,6 +267,7 @@ impl Executable for Node { match *self { Node::AsyncFunctionDecl(ref decl) => decl.run(interpreter), Node::AsyncFunctionExpr(ref function_expr) => function_expr.run(interpreter), + Node::AwaitExpr(ref expr) => expr.run(interpreter), Node::Call(ref call) => call.run(interpreter), Node::Const(Const::Null) => Ok(Value::null()), Node::Const(Const::Num(num)) => Ok(Value::rational(num)), diff --git a/boa/src/syntax/parser/expression/await_expr.rs b/boa/src/syntax/parser/expression/await_expr.rs new file mode 100644 index 00000000000..6dc5b41871a --- /dev/null +++ b/boa/src/syntax/parser/expression/await_expr.rs @@ -0,0 +1,58 @@ +//! Await expression parsing. +//! +//! More information: +//! - [MDN documentation][mdn] +//! - [ECMAScript specification][spec] +//! +//! [mdn]: +//! [spec]: + +use super::unary::UnaryExpression; + +use crate::syntax::{ + ast::{node::AwaitExpr, Keyword}, + lexer::TokenKind, + parser::{AllowYield, Cursor, ParseError, TokenParser}, +}; +use std::io::Read; + +/// Parses a await expression. +/// +/// More information: +/// - [MDN documentation][mdn] +/// - [ECMAScript specification][spec] +/// +/// [mdn]: +/// [spec]: +#[derive(Debug, Clone, Copy)] +pub(in crate::syntax::parser) struct AwaitExpression { + allow_yield: AllowYield, +} + +impl AwaitExpression { + /// Creates a new `AwaitExpression` parser. + pub(in crate::syntax::parser) fn new(allow_yield: Y) -> Self + where + Y: Into, + { + Self { + allow_yield: allow_yield.into(), + } + } +} + +impl TokenParser for AwaitExpression +where + R: Read, +{ + type Output = AwaitExpr; + + fn parse(self, cursor: &mut Cursor) -> Result { + cursor.expect( + TokenKind::Keyword(Keyword::Await), + "Await expression parsing", + )?; + let expr = UnaryExpression::new(self.allow_yield, true).parse(cursor)?; + Ok(expr.into()) + } +} diff --git a/boa/src/syntax/parser/expression/mod.rs b/boa/src/syntax/parser/expression/mod.rs index 66ef2a99dec..68ff35d7d2e 100644 --- a/boa/src/syntax/parser/expression/mod.rs +++ b/boa/src/syntax/parser/expression/mod.rs @@ -15,6 +15,8 @@ mod tests; mod unary; mod update; +pub(in crate::syntax::parser) mod await_expr; + use self::assignment::ExponentiationExpression; pub(super) use self::{assignment::AssignmentExpression, primary::Initializer}; use super::{AllowAwait, AllowIn, AllowYield, Cursor, ParseResult, TokenParser}; 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 7ba38ac3ab3..0294d1d0ccd 100644 --- a/boa/src/syntax/parser/expression/primary/object_initializer/mod.rs +++ b/boa/src/syntax/parser/expression/primary/object_initializer/mod.rs @@ -141,6 +141,14 @@ where return Ok(node::PropertyDefinition::property(prop_name, val)); } + // TODO GeneratorMethod + + if prop_name.as_str() == "async" { + // TODO - AsyncMethod. + + // TODO - AsyncGeneratorMethod + } + if cursor .next_if(TokenKind::Punctuator(Punctuator::OpenParen))? .is_some() diff --git a/boa/src/syntax/parser/expression/unary.rs b/boa/src/syntax/parser/expression/unary.rs index 6ed9f5378c2..ac8da4227e6 100644 --- a/boa/src/syntax/parser/expression/unary.rs +++ b/boa/src/syntax/parser/expression/unary.rs @@ -33,14 +33,14 @@ use std::io::Read; /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Expressions_and_Operators#Unary /// [spec]: https://tc39.es/ecma262/#prod-UnaryExpression #[derive(Debug, Clone, Copy)] -pub(super) struct UnaryExpression { +pub(in crate::syntax::parser) struct UnaryExpression { allow_yield: AllowYield, allow_await: AllowAwait, } impl UnaryExpression { /// Creates a new `UnaryExpression` parser. - pub(super) fn new(allow_yield: Y, allow_await: A) -> Self + pub(in crate::syntax::parser) fn new(allow_yield: Y, allow_await: A) -> Self where Y: Into, A: Into, diff --git a/boa/src/syntax/parser/statement/mod.rs b/boa/src/syntax/parser/statement/mod.rs index 1fab174adfe..757d642db9e 100644 --- a/boa/src/syntax/parser/statement/mod.rs +++ b/boa/src/syntax/parser/statement/mod.rs @@ -42,6 +42,7 @@ use crate::{ syntax::{ ast::{node, Keyword, Node, Punctuator}, lexer::{Error as LexError, InputElement, TokenKind}, + parser::expression::await_expr::AwaitExpression, }, BoaProfiler, }; @@ -110,6 +111,9 @@ where let tok = cursor.peek(0)?.ok_or(ParseError::AbruptEnd)?; match tok.kind() { + TokenKind::Keyword(Keyword::Await) => AwaitExpression::new(self.allow_yield) + .parse(cursor) + .map(Node::from), TokenKind::Keyword(Keyword::If) => { IfStatement::new(self.allow_yield, self.allow_await, self.allow_return) .parse(cursor) From 0aaf7026fd15fd61edbe2198387cf08ca16cf616 Mon Sep 17 00:00:00 2001 From: Paul Lancaster Date: Sat, 10 Oct 2020 14:19:19 +0100 Subject: [PATCH 09/27] Added some async function expr parsing tests --- .../mod.rs} | 4 ++ .../async_function_expression/tests.rs | 66 +++++++++++++++++++ 2 files changed, 70 insertions(+) rename boa/src/syntax/parser/expression/primary/{async_function_expression.rs => async_function_expression/mod.rs} (98%) create mode 100644 boa/src/syntax/parser/expression/primary/async_function_expression/tests.rs diff --git a/boa/src/syntax/parser/expression/primary/async_function_expression.rs b/boa/src/syntax/parser/expression/primary/async_function_expression/mod.rs similarity index 98% rename from boa/src/syntax/parser/expression/primary/async_function_expression.rs rename to boa/src/syntax/parser/expression/primary/async_function_expression/mod.rs index d030f848d62..b810246e9c1 100644 --- a/boa/src/syntax/parser/expression/primary/async_function_expression.rs +++ b/boa/src/syntax/parser/expression/primary/async_function_expression/mod.rs @@ -6,6 +6,10 @@ //! //! [mdn]: //! [spec]: + +#[cfg(test)] +mod tests; + use crate::{ syntax::{ ast::{node::AsyncFunctionExpr, Keyword, Punctuator}, diff --git a/boa/src/syntax/parser/expression/primary/async_function_expression/tests.rs b/boa/src/syntax/parser/expression/primary/async_function_expression/tests.rs new file mode 100644 index 00000000000..55e8c43b084 --- /dev/null +++ b/boa/src/syntax/parser/expression/primary/async_function_expression/tests.rs @@ -0,0 +1,66 @@ +use crate::syntax::{ + ast::{ + node::{AsyncFunctionExpr, ConstDecl, ConstDeclList, Return, StatementList}, + Const, + }, + parser::tests::check_parser, +}; + +/// Checks async expression parsing. +#[test] +fn check_async_expression() { + check_parser( + "const add = async function() { + return 1; + }; + ", + vec![ConstDeclList::from(vec![ConstDecl::new( + "add", + Some( + AsyncFunctionExpr::new::>, _, StatementList>( + None, + [], + vec![Return::new::<_, _, Option>>(Const::from(1), None).into()].into(), + ), + ), + )]) + .into()], + ); +} + +/// Checks async expression parsing. +#[test] +fn check_nested_async_expression() { + check_parser( + "const a = async function() { + const b = async function() { + return 1; + }; + }; + ", + vec![ConstDeclList::from(vec![ConstDecl::new( + "a", + Some( + AsyncFunctionExpr::new::>, _, StatementList>( + None, + [], + vec![ConstDeclList::from(vec![ConstDecl::new( + "b", + Some( + AsyncFunctionExpr::new::>, _, StatementList>( + None, + [], + vec![Return::new::<_, _, Option>>(Const::from(1), None) + .into()] + .into(), + ), + ), + )]) + .into()] + .into(), + ), + ), + )]) + .into()], + ); +} From 1c8c6f9c87de13812b68d406ea36d3498afe9b87 Mon Sep 17 00:00:00 2001 From: Paul Lancaster Date: Sat, 10 Oct 2020 14:34:10 +0100 Subject: [PATCH 10/27] Reposition declaration parsing ready to add tests --- .../parser/statement/declaration/hoistable.rs | 211 ------------------ .../hoistable/async_function_decl/mod.rs | 88 ++++++++ .../hoistable/async_function_decl/tests.rs | 1 + .../hoistable/function_decl/mod.rs | 72 ++++++ .../hoistable/function_decl/tests.rs | 1 + .../statement/declaration/hoistable/mod.rs | 82 +++++++ .../statement/declaration/hoistable/tests.rs | 1 + 7 files changed, 245 insertions(+), 211 deletions(-) delete mode 100644 boa/src/syntax/parser/statement/declaration/hoistable.rs create mode 100644 boa/src/syntax/parser/statement/declaration/hoistable/async_function_decl/mod.rs create mode 100644 boa/src/syntax/parser/statement/declaration/hoistable/async_function_decl/tests.rs create mode 100644 boa/src/syntax/parser/statement/declaration/hoistable/function_decl/mod.rs create mode 100644 boa/src/syntax/parser/statement/declaration/hoistable/function_decl/tests.rs create mode 100644 boa/src/syntax/parser/statement/declaration/hoistable/mod.rs create mode 100644 boa/src/syntax/parser/statement/declaration/hoistable/tests.rs diff --git a/boa/src/syntax/parser/statement/declaration/hoistable.rs b/boa/src/syntax/parser/statement/declaration/hoistable.rs deleted file mode 100644 index 04e5704f9f1..00000000000 --- a/boa/src/syntax/parser/statement/declaration/hoistable.rs +++ /dev/null @@ -1,211 +0,0 @@ -//! Hoistable declaration parsing. -//! -//! More information: -//! - [ECMAScript specification][spec] -//! -//! [spec]: https://tc39.es/ecma262/#prod-HoistableDeclaration - -use crate::{ - syntax::{ - ast::{ - node::{AsyncFunctionDecl, FunctionDecl}, - Keyword, Node, Punctuator, - }, - lexer::TokenKind, - parser::{ - function::FormalParameters, function::FunctionBody, statement::BindingIdentifier, - AllowAwait, AllowDefault, AllowYield, Cursor, ParseError, ParseResult, TokenParser, - }, - }, - BoaProfiler, -}; -use std::io::Read; - -/// Hoistable declaration parsing. -/// -/// More information: -/// - [ECMAScript specification][spec] -/// -/// [spec]: https://tc39.es/ecma262/#prod-FunctionDeclaration -#[derive(Debug, Clone, Copy)] -pub(super) struct HoistableDeclaration { - allow_yield: AllowYield, - allow_await: AllowAwait, - is_default: AllowDefault, -} - -impl HoistableDeclaration { - /// Creates a new `HoistableDeclaration` parser. - pub(super) fn new(allow_yield: Y, allow_await: A, is_default: D) -> Self - where - Y: Into, - A: Into, - D: Into, - { - Self { - allow_yield: allow_yield.into(), - allow_await: allow_await.into(), - is_default: is_default.into(), - } - } -} - -impl TokenParser for HoistableDeclaration -where - R: Read, -{ - type Output = Node; - - fn parse(self, cursor: &mut Cursor) -> ParseResult { - let _timer = BoaProfiler::global().start_event("HoistableDeclaration", "Parsing"); - let tok = cursor.peek(0)?.ok_or(ParseError::AbruptEnd)?; - - match tok.kind() { - TokenKind::Keyword(Keyword::Function) => { - FunctionDeclaration::new(self.allow_yield, self.allow_await, self.is_default) - .parse(cursor) - .map(Node::from) - } - TokenKind::Keyword(Keyword::Async) => { - AsyncFunctionDeclaration::new(self.allow_yield, self.allow_await, false) - .parse(cursor) - .map(Node::from) - } - _ => unreachable!("unknown token found: {:?}", tok), - } - } -} - -/// Function declaration parsing. -/// -/// More information: -/// - [MDN documentation][mdn] -/// - [ECMAScript specification][spec] -/// -/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/function -/// [spec]: https://tc39.es/ecma262/#prod-FunctionDeclaration -#[derive(Debug, Clone, Copy)] -struct FunctionDeclaration { - allow_yield: AllowYield, - allow_await: AllowAwait, - is_default: AllowDefault, -} - -impl FunctionDeclaration { - /// Creates a new `FunctionDeclaration` parser. - fn new(allow_yield: Y, allow_await: A, is_default: D) -> Self - where - Y: Into, - A: Into, - D: Into, - { - Self { - allow_yield: allow_yield.into(), - allow_await: allow_await.into(), - is_default: is_default.into(), - } - } -} - -impl TokenParser for FunctionDeclaration -where - R: Read, -{ - type Output = FunctionDecl; - - fn parse(self, cursor: &mut Cursor) -> Result { - cursor.expect(Keyword::Function, "function declaration")?; - - // TODO: If self.is_default, then this can be empty. - let name = BindingIdentifier::new(self.allow_yield, self.allow_await).parse(cursor)?; - - cursor.expect(Punctuator::OpenParen, "function declaration")?; - - let params = FormalParameters::new(false, false).parse(cursor)?; - - cursor.expect(Punctuator::CloseParen, "function declaration")?; - cursor.expect(Punctuator::OpenBlock, "function declaration")?; - - let body = FunctionBody::new(self.allow_yield, self.allow_await).parse(cursor)?; - - cursor.expect(Punctuator::CloseBlock, "function declaration")?; - - Ok(FunctionDecl::new(name, params, body)) - } -} - -/// Async Function declaration parsing. -/// -/// More information: -/// - [MDN documentation][mdn] -/// - [ECMAScript specification][spec] -/// -/// [mdn]: -/// [spec]: -#[derive(Debug, Clone, Copy)] -struct AsyncFunctionDeclaration { - allow_yield: AllowYield, - allow_await: AllowAwait, - is_default: AllowDefault, -} - -impl AsyncFunctionDeclaration { - /// Creates a new `FunctionDeclaration` parser. - fn new(allow_yield: Y, allow_await: A, is_default: D) -> Self - where - Y: Into, - A: Into, - D: Into, - { - Self { - allow_yield: allow_yield.into(), - allow_await: allow_await.into(), - is_default: is_default.into(), - } - } -} - -impl TokenParser for AsyncFunctionDeclaration -where - R: Read, -{ - type Output = AsyncFunctionDecl; - - fn parse(self, cursor: &mut Cursor) -> Result { - cursor.expect(Keyword::Async, "async function declaration")?; - cursor.expect_no_skip_lineterminator(Keyword::Function, "async function declaration")?; - let tok = cursor.peek(0)?; - - let name = if let Some(token) = tok { - match token.kind() { - TokenKind::Punctuator(Punctuator::OpenParen) => { - if !self.is_default.0 { - return Err(ParseError::unexpected( - token.clone(), - "Unexpected missing identifier for async function decl", - )); - } - None - } - _ => { - Some(BindingIdentifier::new(self.allow_yield, self.allow_await).parse(cursor)?) - } - } - } else { - return Err(ParseError::AbruptEnd); - }; - - cursor.expect(Punctuator::OpenParen, "async function declaration")?; - - let params = FormalParameters::new(!self.allow_yield.0, true).parse(cursor)?; - - cursor.expect(Punctuator::CloseParen, "async function declaration")?; - cursor.expect(Punctuator::OpenBlock, "async function declaration")?; - - let body = FunctionBody::new(!self.allow_yield.0, true).parse(cursor)?; - - cursor.expect(Punctuator::CloseBlock, "async function declaration")?; - - Ok(AsyncFunctionDecl::new(name, params, body)) - } -} diff --git a/boa/src/syntax/parser/statement/declaration/hoistable/async_function_decl/mod.rs b/boa/src/syntax/parser/statement/declaration/hoistable/async_function_decl/mod.rs new file mode 100644 index 00000000000..bfb73e44c0b --- /dev/null +++ b/boa/src/syntax/parser/statement/declaration/hoistable/async_function_decl/mod.rs @@ -0,0 +1,88 @@ +#[cfg(test)] +mod tests; + +use crate::syntax::{ + ast::{node::AsyncFunctionDecl, Keyword, Punctuator}, + lexer::TokenKind, + parser::{ + function::FormalParameters, function::FunctionBody, statement::BindingIdentifier, + AllowAwait, AllowDefault, AllowYield, Cursor, ParseError, TokenParser, + }, +}; +use std::io::Read; + +/// Async Function declaration parsing. +/// +/// More information: +/// - [MDN documentation][mdn] +/// - [ECMAScript specification][spec] +/// +/// [mdn]: +/// [spec]: +#[derive(Debug, Clone, Copy)] +pub(super) struct AsyncFunctionDeclaration { + allow_yield: AllowYield, + allow_await: AllowAwait, + is_default: AllowDefault, +} + +impl AsyncFunctionDeclaration { + /// Creates a new `FunctionDeclaration` parser. + pub(super) fn new(allow_yield: Y, allow_await: A, is_default: D) -> Self + where + Y: Into, + A: Into, + D: Into, + { + Self { + allow_yield: allow_yield.into(), + allow_await: allow_await.into(), + is_default: is_default.into(), + } + } +} + +impl TokenParser for AsyncFunctionDeclaration +where + R: Read, +{ + type Output = AsyncFunctionDecl; + + fn parse(self, cursor: &mut Cursor) -> Result { + cursor.expect(Keyword::Async, "async function declaration")?; + cursor.expect_no_skip_lineterminator(Keyword::Function, "async function declaration")?; + let tok = cursor.peek(0)?; + + let name = if let Some(token) = tok { + match token.kind() { + TokenKind::Punctuator(Punctuator::OpenParen) => { + if !self.is_default.0 { + return Err(ParseError::unexpected( + token.clone(), + "Unexpected missing identifier for async function decl", + )); + } + None + } + _ => { + Some(BindingIdentifier::new(self.allow_yield, self.allow_await).parse(cursor)?) + } + } + } else { + return Err(ParseError::AbruptEnd); + }; + + cursor.expect(Punctuator::OpenParen, "async function declaration")?; + + let params = FormalParameters::new(!self.allow_yield.0, true).parse(cursor)?; + + cursor.expect(Punctuator::CloseParen, "async function declaration")?; + cursor.expect(Punctuator::OpenBlock, "async function declaration")?; + + let body = FunctionBody::new(!self.allow_yield.0, true).parse(cursor)?; + + cursor.expect(Punctuator::CloseBlock, "async function declaration")?; + + Ok(AsyncFunctionDecl::new(name, params, body)) + } +} diff --git a/boa/src/syntax/parser/statement/declaration/hoistable/async_function_decl/tests.rs b/boa/src/syntax/parser/statement/declaration/hoistable/async_function_decl/tests.rs new file mode 100644 index 00000000000..8b137891791 --- /dev/null +++ b/boa/src/syntax/parser/statement/declaration/hoistable/async_function_decl/tests.rs @@ -0,0 +1 @@ + diff --git a/boa/src/syntax/parser/statement/declaration/hoistable/function_decl/mod.rs b/boa/src/syntax/parser/statement/declaration/hoistable/function_decl/mod.rs new file mode 100644 index 00000000000..14529226862 --- /dev/null +++ b/boa/src/syntax/parser/statement/declaration/hoistable/function_decl/mod.rs @@ -0,0 +1,72 @@ +#[cfg(test)] +mod tests; + +use crate::{ + syntax::{ + ast::{node::FunctionDecl, Keyword, Punctuator}, + parser::{ + function::FormalParameters, function::FunctionBody, statement::BindingIdentifier, + AllowAwait, AllowDefault, AllowYield, Cursor, ParseError, TokenParser, + }, + }, +}; +use std::io::Read; + +/// Function declaration parsing. +/// +/// More information: +/// - [MDN documentation][mdn] +/// - [ECMAScript specification][spec] +/// +/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/function +/// [spec]: https://tc39.es/ecma262/#prod-FunctionDeclaration + +#[derive(Debug, Clone, Copy)] +pub(super) struct FunctionDeclaration { + allow_yield: AllowYield, + allow_await: AllowAwait, + is_default: AllowDefault, +} + +impl FunctionDeclaration { + /// Creates a new `FunctionDeclaration` parser. + pub(super) fn new(allow_yield: Y, allow_await: A, is_default: D) -> Self + where + Y: Into, + A: Into, + D: Into, + { + Self { + allow_yield: allow_yield.into(), + allow_await: allow_await.into(), + is_default: is_default.into(), + } + } +} + +impl TokenParser for FunctionDeclaration +where + R: Read, +{ + type Output = FunctionDecl; + + fn parse(self, cursor: &mut Cursor) -> Result { + cursor.expect(Keyword::Function, "function declaration")?; + + // TODO: If self.is_default, then this can be empty. + let name = BindingIdentifier::new(self.allow_yield, self.allow_await).parse(cursor)?; + + cursor.expect(Punctuator::OpenParen, "function declaration")?; + + let params = FormalParameters::new(false, false).parse(cursor)?; + + cursor.expect(Punctuator::CloseParen, "function declaration")?; + cursor.expect(Punctuator::OpenBlock, "function declaration")?; + + let body = FunctionBody::new(self.allow_yield, self.allow_await).parse(cursor)?; + + cursor.expect(Punctuator::CloseBlock, "function declaration")?; + + Ok(FunctionDecl::new(name, params, body)) + } +} diff --git a/boa/src/syntax/parser/statement/declaration/hoistable/function_decl/tests.rs b/boa/src/syntax/parser/statement/declaration/hoistable/function_decl/tests.rs new file mode 100644 index 00000000000..8b137891791 --- /dev/null +++ b/boa/src/syntax/parser/statement/declaration/hoistable/function_decl/tests.rs @@ -0,0 +1 @@ + diff --git a/boa/src/syntax/parser/statement/declaration/hoistable/mod.rs b/boa/src/syntax/parser/statement/declaration/hoistable/mod.rs new file mode 100644 index 00000000000..bfb104d67d6 --- /dev/null +++ b/boa/src/syntax/parser/statement/declaration/hoistable/mod.rs @@ -0,0 +1,82 @@ +//! Hoistable declaration parsing. +//! +//! More information: +//! - [ECMAScript specification][spec] +//! +//! [spec]: https://tc39.es/ecma262/#prod-HoistableDeclaration + +#[cfg(test)] +mod tests; + +mod async_function_decl; +mod function_decl; + +use async_function_decl::AsyncFunctionDeclaration; +use function_decl::FunctionDeclaration; + +use crate::{ + syntax::{ + ast::{Keyword, Node}, + lexer::TokenKind, + parser::{ + AllowAwait, AllowDefault, AllowYield, Cursor, ParseError, ParseResult, TokenParser, + }, + }, + BoaProfiler, +}; +use std::io::Read; + +/// Hoistable declaration parsing. +/// +/// More information: +/// - [ECMAScript specification][spec] +/// +/// [spec]: https://tc39.es/ecma262/#prod-FunctionDeclaration +#[derive(Debug, Clone, Copy)] +pub(super) struct HoistableDeclaration { + allow_yield: AllowYield, + allow_await: AllowAwait, + is_default: AllowDefault, +} + +impl HoistableDeclaration { + /// Creates a new `HoistableDeclaration` parser. + pub(super) fn new(allow_yield: Y, allow_await: A, is_default: D) -> Self + where + Y: Into, + A: Into, + D: Into, + { + Self { + allow_yield: allow_yield.into(), + allow_await: allow_await.into(), + is_default: is_default.into(), + } + } +} + +impl TokenParser for HoistableDeclaration +where + R: Read, +{ + type Output = Node; + + fn parse(self, cursor: &mut Cursor) -> ParseResult { + let _timer = BoaProfiler::global().start_event("HoistableDeclaration", "Parsing"); + let tok = cursor.peek(0)?.ok_or(ParseError::AbruptEnd)?; + + match tok.kind() { + TokenKind::Keyword(Keyword::Function) => { + FunctionDeclaration::new(self.allow_yield, self.allow_await, self.is_default) + .parse(cursor) + .map(Node::from) + } + TokenKind::Keyword(Keyword::Async) => { + AsyncFunctionDeclaration::new(self.allow_yield, self.allow_await, false) + .parse(cursor) + .map(Node::from) + } + _ => unreachable!("unknown token found: {:?}", tok), + } + } +} diff --git a/boa/src/syntax/parser/statement/declaration/hoistable/tests.rs b/boa/src/syntax/parser/statement/declaration/hoistable/tests.rs new file mode 100644 index 00000000000..8b137891791 --- /dev/null +++ b/boa/src/syntax/parser/statement/declaration/hoistable/tests.rs @@ -0,0 +1 @@ + From 2b286f9b46841e99921065a6caafaaeb7c465904 Mon Sep 17 00:00:00 2001 From: Paul Lancaster Date: Sat, 10 Oct 2020 14:36:12 +0100 Subject: [PATCH 11/27] Moved function decl tests --- .../hoistable/function_decl/mod.rs | 12 ++++------ .../hoistable/function_decl/tests.rs | 23 +++++++++++++++++++ 2 files changed, 28 insertions(+), 7 deletions(-) diff --git a/boa/src/syntax/parser/statement/declaration/hoistable/function_decl/mod.rs b/boa/src/syntax/parser/statement/declaration/hoistable/function_decl/mod.rs index 14529226862..f40045b5fd1 100644 --- a/boa/src/syntax/parser/statement/declaration/hoistable/function_decl/mod.rs +++ b/boa/src/syntax/parser/statement/declaration/hoistable/function_decl/mod.rs @@ -1,13 +1,11 @@ #[cfg(test)] mod tests; -use crate::{ - syntax::{ - ast::{node::FunctionDecl, Keyword, Punctuator}, - parser::{ - function::FormalParameters, function::FunctionBody, statement::BindingIdentifier, - AllowAwait, AllowDefault, AllowYield, Cursor, ParseError, TokenParser, - }, +use crate::syntax::{ + ast::{node::FunctionDecl, Keyword, Punctuator}, + parser::{ + function::FormalParameters, function::FunctionBody, statement::BindingIdentifier, + AllowAwait, AllowDefault, AllowYield, Cursor, ParseError, TokenParser, }, }; use std::io::Read; diff --git a/boa/src/syntax/parser/statement/declaration/hoistable/function_decl/tests.rs b/boa/src/syntax/parser/statement/declaration/hoistable/function_decl/tests.rs index 8b137891791..c9cff722c90 100644 --- a/boa/src/syntax/parser/statement/declaration/hoistable/function_decl/tests.rs +++ b/boa/src/syntax/parser/statement/declaration/hoistable/function_decl/tests.rs @@ -1 +1,24 @@ +use crate::syntax::{ast::node::FunctionDecl, parser::tests::check_parser}; +/// Function declaration parsing. +#[test] +fn function_declaration() { + check_parser( + "function hello() {}", + vec![FunctionDecl::new(Box::from("hello"), vec![], vec![]).into()], + ); +} + +/// Function declaration parsing with keywords. +#[test] +fn function_declaration_keywords() { + check_parser( + "function yield() {}", + vec![FunctionDecl::new(Box::from("yield"), vec![], vec![]).into()], + ); + + check_parser( + "function await() {}", + vec![FunctionDecl::new(Box::from("await"), vec![], vec![]).into()], + ); +} From 8507b04f0831bf1973a3677c0524a2b8c5a41c8e Mon Sep 17 00:00:00 2001 From: Paul Lancaster Date: Sat, 10 Oct 2020 14:39:00 +0100 Subject: [PATCH 12/27] Added some failing async func decl tests --- .../hoistable/async_function_decl/tests.rs | 23 +++++++++++++++++++ .../parser/statement/declaration/tests.rs | 23 ------------------- 2 files changed, 23 insertions(+), 23 deletions(-) diff --git a/boa/src/syntax/parser/statement/declaration/hoistable/async_function_decl/tests.rs b/boa/src/syntax/parser/statement/declaration/hoistable/async_function_decl/tests.rs index 8b137891791..a7648b74e57 100644 --- a/boa/src/syntax/parser/statement/declaration/hoistable/async_function_decl/tests.rs +++ b/boa/src/syntax/parser/statement/declaration/hoistable/async_function_decl/tests.rs @@ -1 +1,24 @@ +use crate::syntax::{ast::node::AsyncFunctionDecl, parser::tests::check_parser}; +/// Async function declaration parsing. +#[test] +fn async_function_declaration() { + check_parser( + "async function hello() {}", + vec![AsyncFunctionDecl::new(Box::from("hello"), vec![], vec![]).into()], + ); +} + +/// Async function declaration parsing with keywords. +#[test] +fn async_function_declaration_keywords() { + check_parser( + "async function yield() {}", + vec![AsyncFunctionDecl::new(Box::from("yield"), vec![], vec![]).into()], + ); + + check_parser( + "async function await() {}", + vec![AsyncFunctionDecl::new(Box::from("await"), vec![], vec![]).into()], + ); +} diff --git a/boa/src/syntax/parser/statement/declaration/tests.rs b/boa/src/syntax/parser/statement/declaration/tests.rs index 5ed9bd2d146..1d501148b92 100644 --- a/boa/src/syntax/parser/statement/declaration/tests.rs +++ b/boa/src/syntax/parser/statement/declaration/tests.rs @@ -169,26 +169,3 @@ fn multiple_const_declaration() { .into()], ); } - -/// Function declaration parsing. -#[test] -fn function_declaration() { - check_parser( - "function hello() {}", - vec![FunctionDecl::new(Box::from("hello"), vec![], vec![]).into()], - ); -} - -/// Function declaration parsing with keywords. -#[test] -fn function_declaration_keywords() { - check_parser( - "function yield() {}", - vec![FunctionDecl::new(Box::from("yield"), vec![], vec![]).into()], - ); - - check_parser( - "function await() {}", - vec![FunctionDecl::new(Box::from("await"), vec![], vec![]).into()], - ); -} From 740a285794d20f415c27b99cd403e640c9b585a9 Mon Sep 17 00:00:00 2001 From: Paul Lancaster Date: Sun, 11 Oct 2020 10:41:18 +0100 Subject: [PATCH 13/27] mdn/spec links@ --- .../primary/async_function_expression/mod.rs | 13 ++----------- .../hoistable/async_function_decl/mod.rs | 4 ++-- .../syntax/parser/statement/declaration/tests.rs | 2 +- 3 files changed, 5 insertions(+), 14 deletions(-) diff --git a/boa/src/syntax/parser/expression/primary/async_function_expression/mod.rs b/boa/src/syntax/parser/expression/primary/async_function_expression/mod.rs index b810246e9c1..bf63eec03a7 100644 --- a/boa/src/syntax/parser/expression/primary/async_function_expression/mod.rs +++ b/boa/src/syntax/parser/expression/primary/async_function_expression/mod.rs @@ -1,12 +1,3 @@ -//! Async Function expression parsing. -//! -//! More information: -//! - [MDN documentation][mdn] -//! - [ECMAScript specification][spec] -//! -//! [mdn]: -//! [spec]: - #[cfg(test)] mod tests; @@ -31,8 +22,8 @@ use std::io::Read; /// - [MDN documentation][mdn] /// - [ECMAScript specification][spec] /// -/// [mdn]: -/// [spec]: +/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/async_function +/// [spec]: https://www.ecma-international.org/ecma-262/11.0/index.html#prod-AsyncFunctionExpression #[derive(Debug, Clone, Copy)] pub(super) struct AsyncFunctionExpression { allow_yield: AllowYield, diff --git a/boa/src/syntax/parser/statement/declaration/hoistable/async_function_decl/mod.rs b/boa/src/syntax/parser/statement/declaration/hoistable/async_function_decl/mod.rs index bfb73e44c0b..0d00e508b40 100644 --- a/boa/src/syntax/parser/statement/declaration/hoistable/async_function_decl/mod.rs +++ b/boa/src/syntax/parser/statement/declaration/hoistable/async_function_decl/mod.rs @@ -17,8 +17,8 @@ use std::io::Read; /// - [MDN documentation][mdn] /// - [ECMAScript specification][spec] /// -/// [mdn]: -/// [spec]: +/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function +/// [spec]: https://www.ecma-international.org/ecma-262/11.0/index.html#prod-AsyncFunctionDeclaration #[derive(Debug, Clone, Copy)] pub(super) struct AsyncFunctionDeclaration { allow_yield: AllowYield, diff --git a/boa/src/syntax/parser/statement/declaration/tests.rs b/boa/src/syntax/parser/statement/declaration/tests.rs index 1d501148b92..9e09cfe8c3a 100644 --- a/boa/src/syntax/parser/statement/declaration/tests.rs +++ b/boa/src/syntax/parser/statement/declaration/tests.rs @@ -1,7 +1,7 @@ use crate::syntax::{ ast::{ node::{ - ConstDecl, ConstDeclList, FunctionDecl, LetDecl, LetDeclList, Node, VarDecl, + ConstDecl, ConstDeclList, LetDecl, LetDeclList, Node, VarDecl, VarDeclList, }, Const, From 57db0583df17c5df579f9f8c69502f16f340e3ad Mon Sep 17 00:00:00 2001 From: Paul Lancaster Date: Sun, 11 Oct 2020 10:51:07 +0100 Subject: [PATCH 14/27] Function expression parsing into own folder --- .../mod.rs} | 3 ++ .../primary/function_expression/tests.rs | 29 +++++++++++++++++++ 2 files changed, 32 insertions(+) rename boa/src/syntax/parser/expression/primary/{function_expression.rs => function_expression/mod.rs} (98%) create mode 100644 boa/src/syntax/parser/expression/primary/function_expression/tests.rs diff --git a/boa/src/syntax/parser/expression/primary/function_expression.rs b/boa/src/syntax/parser/expression/primary/function_expression/mod.rs similarity index 98% rename from boa/src/syntax/parser/expression/primary/function_expression.rs rename to boa/src/syntax/parser/expression/primary/function_expression/mod.rs index 25840ada6fa..645a5888668 100644 --- a/boa/src/syntax/parser/expression/primary/function_expression.rs +++ b/boa/src/syntax/parser/expression/primary/function_expression/mod.rs @@ -7,6 +7,9 @@ //! [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/function //! [spec]: https://tc39.es/ecma262/#prod-FunctionExpression +#[cfg(test)] +mod tests; + use crate::{ syntax::{ ast::{node::FunctionExpr, Keyword, Punctuator}, diff --git a/boa/src/syntax/parser/expression/primary/function_expression/tests.rs b/boa/src/syntax/parser/expression/primary/function_expression/tests.rs new file mode 100644 index 00000000000..f305c3b5e81 --- /dev/null +++ b/boa/src/syntax/parser/expression/primary/function_expression/tests.rs @@ -0,0 +1,29 @@ +use crate::syntax::{ + ast::{ + node::{FunctionExpr, ConstDecl, ConstDeclList, Return, StatementList}, + Const, + }, + parser::tests::check_parser, +}; + +/// Checks async expression parsing. +#[test] +fn check_function_expression() { + check_parser( + "const add = function() { + return 1; + }; + ", + vec![ConstDeclList::from(vec![ConstDecl::new( + "add", + Some( + FunctionExpr::new::>, _, StatementList>( + None, + [], + vec![Return::new::<_, _, Option>>(Const::from(1), None).into()].into(), + ), + ), + )]) + .into()], + ); +} From f0581626e28b754034b61daff3c8600b3225176d Mon Sep 17 00:00:00 2001 From: Paul Lancaster Date: Sun, 11 Oct 2020 10:52:42 +0100 Subject: [PATCH 15/27] Added function expression test --- .../async_function_expression/tests.rs | 1 - .../primary/function_expression/tests.rs | 45 +++++++++++++++---- .../parser/statement/declaration/tests.rs | 5 +-- 3 files changed, 38 insertions(+), 13 deletions(-) diff --git a/boa/src/syntax/parser/expression/primary/async_function_expression/tests.rs b/boa/src/syntax/parser/expression/primary/async_function_expression/tests.rs index 55e8c43b084..450aec94d92 100644 --- a/boa/src/syntax/parser/expression/primary/async_function_expression/tests.rs +++ b/boa/src/syntax/parser/expression/primary/async_function_expression/tests.rs @@ -28,7 +28,6 @@ fn check_async_expression() { ); } -/// Checks async expression parsing. #[test] fn check_nested_async_expression() { check_parser( diff --git a/boa/src/syntax/parser/expression/primary/function_expression/tests.rs b/boa/src/syntax/parser/expression/primary/function_expression/tests.rs index f305c3b5e81..f86a54579ba 100644 --- a/boa/src/syntax/parser/expression/primary/function_expression/tests.rs +++ b/boa/src/syntax/parser/expression/primary/function_expression/tests.rs @@ -1,6 +1,6 @@ use crate::syntax::{ ast::{ - node::{FunctionExpr, ConstDecl, ConstDeclList, Return, StatementList}, + node::{ConstDecl, ConstDeclList, FunctionExpr, Return, StatementList}, Const, }, parser::tests::check_parser, @@ -16,13 +16,42 @@ fn check_function_expression() { ", vec![ConstDeclList::from(vec![ConstDecl::new( "add", - Some( - FunctionExpr::new::>, _, StatementList>( - None, - [], - vec![Return::new::<_, _, Option>>(Const::from(1), None).into()].into(), - ), - ), + Some(FunctionExpr::new::>, _, StatementList>( + None, + [], + vec![Return::new::<_, _, Option>>(Const::from(1), None).into()].into(), + )), + )]) + .into()], + ); +} + +#[test] +fn check_nested_function_expression() { + check_parser( + "const a = function() { + const b = function() { + return 1; + }; + }; + ", + vec![ConstDeclList::from(vec![ConstDecl::new( + "a", + Some(FunctionExpr::new::>, _, StatementList>( + None, + [], + vec![ConstDeclList::from(vec![ConstDecl::new( + "b", + Some(FunctionExpr::new::>, _, StatementList>( + None, + [], + vec![Return::new::<_, _, Option>>(Const::from(1), None).into()] + .into(), + )), + )]) + .into()] + .into(), + )), )]) .into()], ); diff --git a/boa/src/syntax/parser/statement/declaration/tests.rs b/boa/src/syntax/parser/statement/declaration/tests.rs index 9e09cfe8c3a..00884139178 100644 --- a/boa/src/syntax/parser/statement/declaration/tests.rs +++ b/boa/src/syntax/parser/statement/declaration/tests.rs @@ -1,9 +1,6 @@ use crate::syntax::{ ast::{ - node::{ - ConstDecl, ConstDeclList, LetDecl, LetDeclList, Node, VarDecl, - VarDeclList, - }, + node::{ConstDecl, ConstDeclList, LetDecl, LetDeclList, Node, VarDecl, VarDeclList}, Const, }, parser::tests::{check_invalid, check_parser}, From 5568fd41ebf50705fb6d94e6856d0b65da049941 Mon Sep 17 00:00:00 2001 From: Paul Lancaster Date: Sun, 11 Oct 2020 10:57:32 +0100 Subject: [PATCH 16/27] Fixed async function decl parse --- boa/src/syntax/parser/statement/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/boa/src/syntax/parser/statement/mod.rs b/boa/src/syntax/parser/statement/mod.rs index 757d642db9e..928741ceb15 100644 --- a/boa/src/syntax/parser/statement/mod.rs +++ b/boa/src/syntax/parser/statement/mod.rs @@ -390,7 +390,7 @@ where let tok = cursor.peek(0)?.ok_or(ParseError::AbruptEnd)?; match *tok.kind() { - TokenKind::Keyword(Keyword::Function) => { + TokenKind::Keyword(Keyword::Function) | TokenKind::Keyword(Keyword::Async) => { if strict_mode && self.in_block { return Err(ParseError::lex(LexError::Syntax( "Function declaration in blocks not allowed in strict mode".into(), From 758a765ca20fe73ce7e59f82fe21ee4e21580bd0 Mon Sep 17 00:00:00 2001 From: Paul Lancaster Date: Sun, 11 Oct 2020 10:59:43 +0100 Subject: [PATCH 17/27] Async/await run returns undefined rather than panic --- boa/src/syntax/ast/node/await_expr/mod.rs | 5 +++-- .../syntax/ast/node/declaration/async_function_decl/mod.rs | 4 ++-- .../syntax/ast/node/declaration/async_function_expr/mod.rs | 5 +++-- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/boa/src/syntax/ast/node/await_expr/mod.rs b/boa/src/syntax/ast/node/await_expr/mod.rs index 2d8b3410e56..d85b42f2d91 100644 --- a/boa/src/syntax/ast/node/await_expr/mod.rs +++ b/boa/src/syntax/ast/node/await_expr/mod.rs @@ -23,9 +23,10 @@ pub struct AwaitExpr { } impl Executable for AwaitExpr { - fn run(&self, interpreter: &mut Context) -> Result { + fn run(&self, _: &mut Context) -> Result { let _timer = BoaProfiler::global().start_event("AwaitExpression", "exec"); - unimplemented!("Await expression execution"); + // unimplemented!("Await expression execution"); + return Ok(Value::Undefined); } } diff --git a/boa/src/syntax/ast/node/declaration/async_function_decl/mod.rs b/boa/src/syntax/ast/node/declaration/async_function_decl/mod.rs index f38a6ef0ff4..94a506a3ec6 100644 --- a/boa/src/syntax/ast/node/declaration/async_function_decl/mod.rs +++ b/boa/src/syntax/ast/node/declaration/async_function_decl/mod.rs @@ -79,9 +79,9 @@ impl AsyncFunctionDecl { } impl Executable for AsyncFunctionDecl { - fn run(&self, interpreter: &mut Context) -> Result { + fn run(&self, _: &mut Context) -> Result { let _timer = BoaProfiler::global().start_event("AsyncFunctionDecl", "exec"); - unimplemented!("Execute AsyncFunctionDecl"); + // unimplemented!("Execute AsyncFunctionDecl"); Ok(Value::undefined()) } } diff --git a/boa/src/syntax/ast/node/declaration/async_function_expr/mod.rs b/boa/src/syntax/ast/node/declaration/async_function_expr/mod.rs index 2a1979d717e..126c00b740e 100644 --- a/boa/src/syntax/ast/node/declaration/async_function_expr/mod.rs +++ b/boa/src/syntax/ast/node/declaration/async_function_expr/mod.rs @@ -76,8 +76,9 @@ impl AsyncFunctionExpr { } impl Executable for AsyncFunctionExpr { - fn run(&self, interpreter: &mut Context) -> Result { - unimplemented!("Execute AsyncFunctionExpr"); + fn run(&self, _: &mut Context) -> Result { + // unimplemented!("Execute AsyncFunctionExpr"); + return Ok(Value::Undefined); } } From d4201c05587a54b14197a698270574d1bf064069 Mon Sep 17 00:00:00 2001 From: Paul Lancaster Date: Sun, 11 Oct 2020 11:07:12 +0100 Subject: [PATCH 18/27] Clippy :( -> :) --- boa/src/syntax/ast/node/await_expr/mod.rs | 2 +- boa/src/syntax/ast/node/declaration/async_function_expr/mod.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/boa/src/syntax/ast/node/await_expr/mod.rs b/boa/src/syntax/ast/node/await_expr/mod.rs index d85b42f2d91..d49ca1eb8df 100644 --- a/boa/src/syntax/ast/node/await_expr/mod.rs +++ b/boa/src/syntax/ast/node/await_expr/mod.rs @@ -26,7 +26,7 @@ impl Executable for AwaitExpr { fn run(&self, _: &mut Context) -> Result { let _timer = BoaProfiler::global().start_event("AwaitExpression", "exec"); // unimplemented!("Await expression execution"); - return Ok(Value::Undefined); + Ok(Value::Undefined) } } diff --git a/boa/src/syntax/ast/node/declaration/async_function_expr/mod.rs b/boa/src/syntax/ast/node/declaration/async_function_expr/mod.rs index 126c00b740e..f1d580c0a2a 100644 --- a/boa/src/syntax/ast/node/declaration/async_function_expr/mod.rs +++ b/boa/src/syntax/ast/node/declaration/async_function_expr/mod.rs @@ -78,7 +78,7 @@ impl AsyncFunctionExpr { impl Executable for AsyncFunctionExpr { fn run(&self, _: &mut Context) -> Result { // unimplemented!("Execute AsyncFunctionExpr"); - return Ok(Value::Undefined); + Ok(Value::Undefined) } } From 7e4f3d1c8639f61d9e87841c423bd76706d67ca8 Mon Sep 17 00:00:00 2001 From: Paul Lancaster Date: Sun, 11 Oct 2020 11:28:53 +0100 Subject: [PATCH 19/27] Missing docs --- boa/src/syntax/ast/node/await_expr/mod.rs | 7 ++++--- .../ast/node/declaration/async_function_decl/mod.rs | 4 +++- .../ast/node/declaration/async_function_expr/mod.rs | 5 ++++- boa/src/syntax/parser/expression/await_expr.rs | 10 +++++----- 4 files changed, 16 insertions(+), 10 deletions(-) diff --git a/boa/src/syntax/ast/node/await_expr/mod.rs b/boa/src/syntax/ast/node/await_expr/mod.rs index d49ca1eb8df..b4c6925a9b8 100644 --- a/boa/src/syntax/ast/node/await_expr/mod.rs +++ b/boa/src/syntax/ast/node/await_expr/mod.rs @@ -8,14 +8,15 @@ use std::fmt; #[cfg(feature = "serde")] use serde::{Deserialize, Serialize}; -/// +/// An await expression is used within an async function to pause execution and wait for a +/// promise to resolve. /// /// More information: /// - [ECMAScript reference][spec] /// - [MDN documentation][mdn] /// -/// [spec]: -/// [mdn]: +/// [spec]: https://tc39.es/ecma262/#prod-AwaitExpression +/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/await #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[derive(Clone, Debug, Trace, Finalize, PartialEq)] pub struct AwaitExpr { diff --git a/boa/src/syntax/ast/node/declaration/async_function_decl/mod.rs b/boa/src/syntax/ast/node/declaration/async_function_decl/mod.rs index 94a506a3ec6..dd9c2f39680 100644 --- a/boa/src/syntax/ast/node/declaration/async_function_decl/mod.rs +++ b/boa/src/syntax/ast/node/declaration/async_function_decl/mod.rs @@ -1,3 +1,5 @@ +//! Async Function Declaration. + use crate::{ exec::Executable, syntax::ast::node::{join_nodes, FormalParameter, Node, StatementList}, @@ -9,7 +11,7 @@ use std::fmt; #[cfg(feature = "serde")] use serde::{Deserialize, Serialize}; -/// Async Function Declaration. +/// An async function is used to specify an action (or series of actions) to perform asynchronously. /// /// More information: /// - [ECMAScript reference][spec] diff --git a/boa/src/syntax/ast/node/declaration/async_function_expr/mod.rs b/boa/src/syntax/ast/node/declaration/async_function_expr/mod.rs index f1d580c0a2a..04a549c816f 100644 --- a/boa/src/syntax/ast/node/declaration/async_function_expr/mod.rs +++ b/boa/src/syntax/ast/node/declaration/async_function_expr/mod.rs @@ -1,3 +1,5 @@ +//! Async Function Expression. + use crate::{ exec::Executable, syntax::ast::node::{join_nodes, FormalParameter, Node, StatementList}, @@ -9,7 +11,8 @@ use std::fmt; #[cfg(feature = "serde")] use serde::{Deserialize, Serialize}; -/// AsyncFunctionExpr. +/// An async function expression is very similar to an async function declaration except used within +/// a wider expression (for example during an assignment). /// /// More information: /// - [ECMAScript reference][spec] diff --git a/boa/src/syntax/parser/expression/await_expr.rs b/boa/src/syntax/parser/expression/await_expr.rs index 6dc5b41871a..2ecf34a6fe5 100644 --- a/boa/src/syntax/parser/expression/await_expr.rs +++ b/boa/src/syntax/parser/expression/await_expr.rs @@ -4,8 +4,8 @@ //! - [MDN documentation][mdn] //! - [ECMAScript specification][spec] //! -//! [mdn]: -//! [spec]: +//! [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/await +//! [spec]: https://tc39.es/ecma262/#prod-AwaitExpression use super::unary::UnaryExpression; @@ -16,14 +16,14 @@ use crate::syntax::{ }; use std::io::Read; -/// Parses a await expression. +/// Parses an await expression. /// /// More information: /// - [MDN documentation][mdn] /// - [ECMAScript specification][spec] /// -/// [mdn]: -/// [spec]: +/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/await +/// [spec]: https://tc39.es/ecma262/#prod-AwaitExpression #[derive(Debug, Clone, Copy)] pub(in crate::syntax::parser) struct AwaitExpression { allow_yield: AllowYield, From 964800fbf47015d33b6d48d756ee4335b6eba1b5 Mon Sep 17 00:00:00 2001 From: Paul Lancaster Date: Sun, 11 Oct 2020 11:29:22 +0100 Subject: [PATCH 20/27] Update boa/src/syntax/ast/node/declaration/async_function_decl/mod.rs Co-authored-by: Halid Odat --- boa/src/syntax/ast/node/declaration/async_function_decl/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/boa/src/syntax/ast/node/declaration/async_function_decl/mod.rs b/boa/src/syntax/ast/node/declaration/async_function_decl/mod.rs index dd9c2f39680..91ee9edc50a 100644 --- a/boa/src/syntax/ast/node/declaration/async_function_decl/mod.rs +++ b/boa/src/syntax/ast/node/declaration/async_function_decl/mod.rs @@ -83,7 +83,7 @@ impl AsyncFunctionDecl { impl Executable for AsyncFunctionDecl { fn run(&self, _: &mut Context) -> Result { let _timer = BoaProfiler::global().start_event("AsyncFunctionDecl", "exec"); - // unimplemented!("Execute AsyncFunctionDecl"); + // TODO: Implement AsyncFunctionDecl Ok(Value::undefined()) } } From e0a3218e1ee1a636580ce940724c955958da65d7 Mon Sep 17 00:00:00 2001 From: Paul Lancaster Date: Sun, 11 Oct 2020 11:29:30 +0100 Subject: [PATCH 21/27] Update boa/src/syntax/ast/node/declaration/async_function_expr/mod.rs Co-authored-by: Halid Odat --- boa/src/syntax/ast/node/declaration/async_function_expr/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/boa/src/syntax/ast/node/declaration/async_function_expr/mod.rs b/boa/src/syntax/ast/node/declaration/async_function_expr/mod.rs index 04a549c816f..ac00989ee83 100644 --- a/boa/src/syntax/ast/node/declaration/async_function_expr/mod.rs +++ b/boa/src/syntax/ast/node/declaration/async_function_expr/mod.rs @@ -80,7 +80,7 @@ impl AsyncFunctionExpr { impl Executable for AsyncFunctionExpr { fn run(&self, _: &mut Context) -> Result { - // unimplemented!("Execute AsyncFunctionExpr"); + // TODO: Implement AsyncFunctionExpr Ok(Value::Undefined) } } From 4c0c1238ec439a1eedc29780bd57c63a8fa6264f Mon Sep 17 00:00:00 2001 From: Paul Lancaster Date: Sun, 11 Oct 2020 11:29:37 +0100 Subject: [PATCH 22/27] Update boa/src/syntax/parser/statement/mod.rs Co-authored-by: Halid Odat --- boa/src/syntax/parser/statement/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/boa/src/syntax/parser/statement/mod.rs b/boa/src/syntax/parser/statement/mod.rs index 928741ceb15..544840626e3 100644 --- a/boa/src/syntax/parser/statement/mod.rs +++ b/boa/src/syntax/parser/statement/mod.rs @@ -390,7 +390,7 @@ where let tok = cursor.peek(0)?.ok_or(ParseError::AbruptEnd)?; match *tok.kind() { - TokenKind::Keyword(Keyword::Function) | TokenKind::Keyword(Keyword::Async) => { + TokenKind::Keyword(Keyword::Function | Keyword::Async) => { if strict_mode && self.in_block { return Err(ParseError::lex(LexError::Syntax( "Function declaration in blocks not allowed in strict mode".into(), From 46b291753039af2fee23e9390d6b64b632b703ab Mon Sep 17 00:00:00 2001 From: Paul Lancaster Date: Sun, 11 Oct 2020 11:29:44 +0100 Subject: [PATCH 23/27] Update boa/src/syntax/parser/statement/declaration/mod.rs Co-authored-by: Halid Odat --- boa/src/syntax/parser/statement/declaration/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/boa/src/syntax/parser/statement/declaration/mod.rs b/boa/src/syntax/parser/statement/declaration/mod.rs index 518748d2e7a..f539d5c4acd 100644 --- a/boa/src/syntax/parser/statement/declaration/mod.rs +++ b/boa/src/syntax/parser/statement/declaration/mod.rs @@ -63,7 +63,7 @@ where let tok = cursor.peek(0)?.ok_or(ParseError::AbruptEnd)?; match tok.kind() { - TokenKind::Keyword(Keyword::Function) | TokenKind::Keyword(Keyword::Async) => { + TokenKind::Keyword(Keyword::Function | Keyword::Async) => { HoistableDeclaration::new(self.allow_yield, self.allow_await, false).parse(cursor) } TokenKind::Keyword(Keyword::Const) | TokenKind::Keyword(Keyword::Let) => { From 3c8d9bd7bc731271baeddf95b4c7dde428679cb1 Mon Sep 17 00:00:00 2001 From: Paul Lancaster Date: Sun, 11 Oct 2020 11:29:52 +0100 Subject: [PATCH 24/27] Update boa/src/syntax/ast/node/await_expr/mod.rs Co-authored-by: Halid Odat --- boa/src/syntax/ast/node/await_expr/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/boa/src/syntax/ast/node/await_expr/mod.rs b/boa/src/syntax/ast/node/await_expr/mod.rs index b4c6925a9b8..168b3e37d91 100644 --- a/boa/src/syntax/ast/node/await_expr/mod.rs +++ b/boa/src/syntax/ast/node/await_expr/mod.rs @@ -26,7 +26,7 @@ pub struct AwaitExpr { impl Executable for AwaitExpr { fn run(&self, _: &mut Context) -> Result { let _timer = BoaProfiler::global().start_event("AwaitExpression", "exec"); - // unimplemented!("Await expression execution"); + // TODO: Implement AwaitExpr Ok(Value::Undefined) } } From f21ee51c5b283f1c8015d1e5408d7e67f7eb498e Mon Sep 17 00:00:00 2001 From: Paul Lancaster Date: Sun, 11 Oct 2020 11:39:17 +0100 Subject: [PATCH 25/27] Revert "Update boa/src/syntax/parser/statement/declaration/mod.rs" This reverts commit 46b291753039af2fee23e9390d6b64b632b703ab. --- boa/src/syntax/parser/statement/declaration/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/boa/src/syntax/parser/statement/declaration/mod.rs b/boa/src/syntax/parser/statement/declaration/mod.rs index f539d5c4acd..518748d2e7a 100644 --- a/boa/src/syntax/parser/statement/declaration/mod.rs +++ b/boa/src/syntax/parser/statement/declaration/mod.rs @@ -63,7 +63,7 @@ where let tok = cursor.peek(0)?.ok_or(ParseError::AbruptEnd)?; match tok.kind() { - TokenKind::Keyword(Keyword::Function | Keyword::Async) => { + TokenKind::Keyword(Keyword::Function) | TokenKind::Keyword(Keyword::Async) => { HoistableDeclaration::new(self.allow_yield, self.allow_await, false).parse(cursor) } TokenKind::Keyword(Keyword::Const) | TokenKind::Keyword(Keyword::Let) => { From 5eeea0a4465b4e0d7cf8ddcf35bfb81aa2e0be12 Mon Sep 17 00:00:00 2001 From: Paul Lancaster Date: Sun, 11 Oct 2020 11:40:02 +0100 Subject: [PATCH 26/27] Revert "Update boa/src/syntax/parser/statement/mod.rs" This reverts commit 4c0c1238ec439a1eedc29780bd57c63a8fa6264f. --- boa/src/syntax/parser/statement/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/boa/src/syntax/parser/statement/mod.rs b/boa/src/syntax/parser/statement/mod.rs index 544840626e3..928741ceb15 100644 --- a/boa/src/syntax/parser/statement/mod.rs +++ b/boa/src/syntax/parser/statement/mod.rs @@ -390,7 +390,7 @@ where let tok = cursor.peek(0)?.ok_or(ParseError::AbruptEnd)?; match *tok.kind() { - TokenKind::Keyword(Keyword::Function | Keyword::Async) => { + TokenKind::Keyword(Keyword::Function) | TokenKind::Keyword(Keyword::Async) => { if strict_mode && self.in_block { return Err(ParseError::lex(LexError::Syntax( "Function declaration in blocks not allowed in strict mode".into(), From 127d03829aa5e96fe2d39c63d6d687ca0afb0f3c Mon Sep 17 00:00:00 2001 From: Paul Lancaster Date: Sun, 11 Oct 2020 20:14:32 +0100 Subject: [PATCH 27/27] Update boa/src/syntax/parser/expression/primary/async_function_expression/mod.rs Co-authored-by: Iban Eguia --- .../parser/expression/primary/async_function_expression/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/boa/src/syntax/parser/expression/primary/async_function_expression/mod.rs b/boa/src/syntax/parser/expression/primary/async_function_expression/mod.rs index bf63eec03a7..f67796e700e 100644 --- a/boa/src/syntax/parser/expression/primary/async_function_expression/mod.rs +++ b/boa/src/syntax/parser/expression/primary/async_function_expression/mod.rs @@ -62,7 +62,7 @@ where return Err(ParseError::AbruptEnd); }; - cursor.expect(Punctuator::OpenParen, "function expression")?; + cursor.expect(Punctuator::OpenParen, "async function expression")?; let params = FormalParameters::new(!self.allow_yield.0, true).parse(cursor)?;