From e4ac2743aaebcf96e20db1e75bf4f55f2422fc7b Mon Sep 17 00:00:00 2001 From: Paul Lancaster Date: Fri, 9 Oct 2020 22:50:02 +0100 Subject: [PATCH 1/7] 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 2/7] 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 3/7] 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 4/7] 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 5/7] 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 6/7] 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 7/7] 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 =