diff --git a/boa/src/syntax/ast/node/declaration/async_arrow_function_decl/mod.rs b/boa/src/syntax/ast/node/declaration/async_arrow_function_decl/mod.rs
new file mode 100644
index 00000000000..8d6410151ba
--- /dev/null
+++ b/boa/src/syntax/ast/node/declaration/async_arrow_function_decl/mod.rs
@@ -0,0 +1,88 @@
+use crate::{
+ builtins::function::FunctionFlags,
+ exec::Executable,
+ gc::{Finalize, Trace},
+ syntax::ast::node::{join_nodes, FormalParameter, Node, StatementList},
+ Context, Result, Value,
+};
+use std::fmt;
+
+#[cfg(feature = "deser")]
+use serde::{Deserialize, Serialize};
+
+///
+///
+///
+///
+/// More information:
+/// - [ECMAScript reference][spec]
+/// - [MDN documentation][mdn]
+///
+/// [spec]:
+/// [mdn]:
+#[cfg_attr(feature = "deser", derive(Serialize, Deserialize))]
+#[derive(Clone, Debug, Trace, Finalize, PartialEq)]
+pub struct AsyncArrowFunctionDecl {
+ params: Box<[FormalParameter]>,
+ body: StatementList,
+}
+
+impl AsyncArrowFunctionDecl {
+ /// Creates a new `AsyncArrowFunctionDecl` AST node.
+ pub(in crate::syntax) fn new
(params: P, body: B) -> Self
+ where
+ P: Into>,
+ B: Into,
+ {
+ Self {
+ params: params.into(),
+ body: body.into(),
+ }
+ }
+
+ /// Gets the list of parameters of the arrow function.
+ pub(crate) fn params(&self) -> &[FormalParameter] {
+ &self.params
+ }
+
+ /// Gets the body of the arrow function.
+ pub(crate) fn body(&self) -> &[Node] {
+ &self.body.items()
+ }
+
+ /// 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 (")?;
+ join_nodes(f, &self.params)?;
+ f.write_str(") => ")?;
+ self.body.display(f, indentation)
+ }
+}
+
+impl Executable for AsyncArrowFunctionDecl {
+ fn run(&self, context: &mut Context) -> Result {
+ Ok(context.create_function(
+ self.params().to_vec(),
+ self.body().to_vec(),
+ FunctionFlags::CALLABLE
+ | FunctionFlags::CONSTRUCTABLE
+ | FunctionFlags::LEXICAL_THIS_MODE,
+ )?)
+ }
+}
+
+impl fmt::Display for AsyncArrowFunctionDecl {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ self.display(f, 0)
+ }
+}
+
+impl From for Node {
+ fn from(decl: AsyncArrowFunctionDecl) -> Self {
+ Self::AsyncArrowFunctionDecl(decl)
+ }
+}
diff --git a/boa/src/syntax/ast/node/declaration/mod.rs b/boa/src/syntax/ast/node/declaration/mod.rs
index ac5a0dbbb92..b72f128d24f 100644
--- a/boa/src/syntax/ast/node/declaration/mod.rs
+++ b/boa/src/syntax/ast/node/declaration/mod.rs
@@ -1,6 +1,7 @@
//! Declaration nodes
pub mod arrow_function_decl;
+pub mod async_arrow_function_decl;
pub mod async_function_decl;
pub mod async_function_expr;
pub mod const_decl_list;
@@ -11,6 +12,7 @@ pub mod var_decl_list;
pub use self::{
arrow_function_decl::ArrowFunctionDecl,
+ async_arrow_function_decl::AsyncArrowFunctionDecl,
async_function_decl::AsyncFunctionDecl,
async_function_expr::AsyncFunctionExpr,
const_decl_list::{ConstDecl, ConstDeclList},
diff --git a/boa/src/syntax/ast/node/mod.rs b/boa/src/syntax/ast/node/mod.rs
index 06119dc9fd0..8c8b1fdf10e 100644
--- a/boa/src/syntax/ast/node/mod.rs
+++ b/boa/src/syntax/ast/node/mod.rs
@@ -29,8 +29,8 @@ pub use self::{
call::Call,
conditional::{ConditionalOp, If},
declaration::{
- ArrowFunctionDecl, AsyncFunctionDecl, AsyncFunctionExpr, ConstDecl, ConstDeclList,
- FunctionDecl, FunctionExpr, LetDecl, LetDeclList, VarDecl, VarDeclList,
+ ArrowFunctionDecl, AsyncArrowFunctionDecl, AsyncFunctionDecl, AsyncFunctionExpr, ConstDecl,
+ ConstDeclList, FunctionDecl, FunctionExpr, LetDecl, LetDeclList, VarDecl, VarDeclList,
},
field::{GetConstField, GetField},
identifier::Identifier,
@@ -72,6 +72,9 @@ pub enum Node {
/// An assignment operator node. [More information](./operator/struct.Assign.html).
Assign(Assign),
+ /// An async arrow function declaration node. [More information](./declaration/struct.AsyncArrowFunctionDecl.html).
+ AsyncArrowFunctionDecl(AsyncArrowFunctionDecl),
+
/// An async function declaration node. [More information](./declaration/struct.AsyncFunctionDecl.html).
AsyncFunctionDecl(AsyncFunctionDecl),
@@ -271,6 +274,7 @@ 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::AsyncArrowFunctionDecl(ref decl) => decl.display(f, indentation),
Self::AsyncFunctionDecl(ref decl) => decl.display(f, indentation),
Self::AsyncFunctionExpr(ref expr) => expr.display(f, indentation),
Self::AwaitExpr(ref expr) => expr.display(f, indentation),
@@ -282,6 +286,7 @@ impl Executable for Node {
fn run(&self, context: &mut Context) -> Result {
let _timer = BoaProfiler::global().start_event("Executable", "exec");
match *self {
+ Node::AsyncArrowFunctionDecl(ref decl) => decl.run(context),
Node::AsyncFunctionDecl(ref decl) => decl.run(context),
Node::AsyncFunctionExpr(ref function_expr) => function_expr.run(context),
Node::AwaitExpr(ref expr) => expr.run(context),
diff --git a/boa/src/syntax/parser/expression/assignment/arrow_function.rs b/boa/src/syntax/parser/expression/assignment/arrow_function.rs
index 43b717b7843..030e82c5a08 100644
--- a/boa/src/syntax/parser/expression/assignment/arrow_function.rs
+++ b/boa/src/syntax/parser/expression/assignment/arrow_function.rs
@@ -7,17 +7,17 @@
//! [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions
//! [spec]: https://tc39.es/ecma262/#sec-arrow-function-definitions
-use super::AssignmentExpression;
+use super::ConciseBody;
use crate::syntax::lexer::TokenKind;
use crate::{
syntax::{
ast::{
- node::{ArrowFunctionDecl, FormalParameter, Node, Return, StatementList},
+ node::{ArrowFunctionDecl, FormalParameter},
Punctuator,
},
parser::{
- error::{ErrorContext, ParseError, ParseResult},
- function::{FormalParameters, FunctionBody},
+ error::{ErrorContext, ParseError},
+ function::FormalParameters,
statement::BindingIdentifier,
AllowAwait, AllowIn, AllowYield, Cursor, TokenParser,
},
@@ -76,7 +76,8 @@ where
// CoverParenthesizedExpressionAndArrowParameterList
cursor.expect(Punctuator::OpenParen, "arrow function")?;
- let params = FormalParameters::new(self.allow_yield, self.allow_await).parse(cursor)?;
+ let params =
+ FormalParameters::new(self.allow_yield, self.allow_await, false).parse(cursor)?;
cursor.expect(Punctuator::CloseParen, "arrow function")?;
params
} else {
@@ -89,80 +90,7 @@ where
cursor.peek_expect_no_lineterminator(0, "arrow function")?;
cursor.expect(TokenKind::Punctuator(Punctuator::Arrow), "arrow function")?;
- let body = ConciseBody::new(self.allow_in).parse(cursor)?;
+ let body = ConciseBody::new(self.allow_in, false).parse(cursor)?;
Ok(ArrowFunctionDecl::new(params, body))
}
}
-
-///
-#[derive(Debug, Clone, Copy)]
-struct ConciseBody {
- allow_in: AllowIn,
-}
-
-impl ConciseBody {
- /// Creates a new `ConcideBody` parser.
- fn new(allow_in: I) -> Self
- where
- I: Into,
- {
- Self {
- allow_in: allow_in.into(),
- }
- }
-}
-
-impl TokenParser for ConciseBody
-where
- R: Read,
-{
- type Output = StatementList;
-
- fn parse(self, cursor: &mut Cursor) -> Result {
- match cursor.peek(0)?.ok_or(ParseError::AbruptEnd)?.kind() {
- TokenKind::Punctuator(Punctuator::OpenBlock) => {
- let _ = cursor.next();
- let body = FunctionBody::new(false, false).parse(cursor)?;
- cursor.expect(Punctuator::CloseBlock, "arrow function")?;
- Ok(body)
- }
- _ => Ok(StatementList::from(vec![Return::new(
- ExpressionBody::new(self.allow_in, false).parse(cursor)?,
- None,
- )
- .into()])),
- }
- }
-}
-
-///
-#[derive(Debug, Clone, Copy)]
-struct ExpressionBody {
- allow_in: AllowIn,
- allow_await: AllowAwait,
-}
-
-impl ExpressionBody {
- /// Creates a new `ExpressionBody` parser.
- fn new(allow_in: I, allow_await: A) -> Self
- where
- I: Into,
- A: Into,
- {
- Self {
- allow_in: allow_in.into(),
- allow_await: allow_await.into(),
- }
- }
-}
-
-impl TokenParser for ExpressionBody
-where
- R: Read,
-{
- type Output = Node;
-
- fn parse(self, cursor: &mut Cursor) -> ParseResult {
- AssignmentExpression::new(self.allow_in, false, self.allow_await).parse(cursor)
- }
-}
diff --git a/boa/src/syntax/parser/expression/assignment/async_arrow_function/mod.rs b/boa/src/syntax/parser/expression/assignment/async_arrow_function/mod.rs
new file mode 100644
index 00000000000..ec9bf2dd3dd
--- /dev/null
+++ b/boa/src/syntax/parser/expression/assignment/async_arrow_function/mod.rs
@@ -0,0 +1,104 @@
+//! Async Arrow function parsing.
+//!
+//! More information:
+//! - [MDN documentation][mdn]
+//! - [ECMAScript specification][spec]
+//!
+//! [mdn]:
+//! [spec]: https://tc39.es/ecma262/#prod-AsyncArrowFunction
+#[cfg(test)]
+mod tests;
+
+use super::ConciseBody;
+use crate::{
+ syntax::{
+ ast::{
+ node::{AsyncArrowFunctionDecl, FormalParameter},
+ Keyword, Punctuator,
+ },
+ lexer::TokenKind,
+ parser::{
+ error::{ErrorContext, ParseError},
+ function::FormalParameters,
+ statement::BindingIdentifier,
+ AllowAwait, AllowIn, AllowYield, Cursor, TokenParser,
+ },
+ },
+ BoaProfiler,
+};
+
+use std::io::Read;
+
+/// Arrow function parsing.
+///
+/// More information:
+/// - [MDN documentation][mdn]
+/// - [ECMAScript specification][spec]
+///
+/// [mdn]:
+/// [spec]: https://tc39.es/ecma262/#prod-AsyncArrowFunction
+#[derive(Debug, Clone, Copy)]
+pub(in crate::syntax::parser) struct AsyncArrowFunction {
+ allow_in: AllowIn,
+ allow_yield: AllowYield,
+ allow_await: AllowAwait,
+}
+
+impl AsyncArrowFunction {
+ /// Creates a new `AsyncArrowFunction` parser.
+ pub(in crate::syntax::parser) fn new(
+ allow_in: I,
+ allow_yield: Y,
+ allow_await: A,
+ ) -> Self
+ where
+ I: Into,
+ Y: Into,
+ A: Into,
+ {
+ Self {
+ allow_in: allow_in.into(),
+ allow_yield: allow_yield.into(),
+ allow_await: allow_await.into(),
+ }
+ }
+}
+
+impl TokenParser for AsyncArrowFunction
+where
+ R: Read,
+{
+ type Output = AsyncArrowFunctionDecl;
+
+ fn parse(self, cursor: &mut Cursor) -> Result {
+ let _timer = BoaProfiler::global().start_event("AsyncArrowFunction", "Parsing");
+ cursor.expect(
+ TokenKind::Keyword(Keyword::Async),
+ "async arrow function parsing",
+ )?;
+ let token = cursor.peek_expect_no_lineterminator(0, "async arrow function parsing")?;
+
+ let params = if let TokenKind::Punctuator(Punctuator::OpenParen) = &token.kind() {
+ // CoverCallExpressionAndAsyncArrowHead
+ cursor.expect(Punctuator::OpenParen, "async arrow function")?;
+
+ let params = FormalParameters::new(false, true, true).parse(cursor)?;
+ cursor.expect(Punctuator::CloseParen, "async arrow function")?;
+ params
+ } else {
+ // AsyncArrowBindingIdentifier
+ let param = BindingIdentifier::new(self.allow_yield, true)
+ .parse(cursor)
+ .context("async arrow function")?;
+ Box::new([FormalParameter::new(param, None, false)])
+ };
+
+ cursor.peek_expect_no_lineterminator(0, "async arrow function")?;
+ cursor.expect(
+ TokenKind::Punctuator(Punctuator::Arrow),
+ "async arrow function",
+ )?;
+ let body = ConciseBody::new(self.allow_in, true).parse(cursor)?;
+ Ok(AsyncArrowFunctionDecl::new(params, body))
+ }
+}
diff --git a/boa/src/syntax/parser/expression/assignment/async_arrow_function/tests.rs b/boa/src/syntax/parser/expression/assignment/async_arrow_function/tests.rs
new file mode 100644
index 00000000000..98197d531f1
--- /dev/null
+++ b/boa/src/syntax/parser/expression/assignment/async_arrow_function/tests.rs
@@ -0,0 +1,72 @@
+use crate::syntax::{
+ ast::node::{
+ AsyncArrowFunctionDecl, BinOp, FormalParameter, Identifier, LetDecl, LetDeclList, Node,
+ Return,
+ },
+ ast::op::NumOp,
+ parser::tests::check_parser,
+};
+
+/// Checks an arrow function with expression return.
+#[test]
+fn check_async_arrow() {
+ check_parser(
+ "async (a, b) => { return a + b; }",
+ vec![AsyncArrowFunctionDecl::new(
+ vec![
+ FormalParameter::new("a", None, false),
+ FormalParameter::new("b", None, false),
+ ],
+ vec![Return::new(
+ BinOp::new(NumOp::Add, Identifier::from("a"), Identifier::from("b")),
+ None,
+ )
+ .into()],
+ )
+ .into()],
+ );
+}
+
+#[test]
+fn check_async_arrow_assignment() {
+ check_parser(
+ "let foo = async (a) => { return a };",
+ vec![LetDeclList::from(vec![LetDecl::new::<_, Option>(
+ Identifier::from("foo"),
+ Some(
+ AsyncArrowFunctionDecl::new(
+ vec![FormalParameter::new("a", None, false)],
+ vec![Return::new::, Option<_>>(
+ Some(Identifier::from("a").into()),
+ None,
+ )
+ .into()],
+ )
+ .into(),
+ ),
+ )])
+ .into()],
+ );
+}
+
+#[test]
+fn check_async_arrow_assignment_noparenthesis() {
+ check_parser(
+ "let foo = async a => { return a };",
+ vec![LetDeclList::from(vec![LetDecl::new::<_, Option>(
+ Identifier::from("foo"),
+ Some(
+ AsyncArrowFunctionDecl::new(
+ vec![FormalParameter::new("a", None, false)],
+ vec![Return::new::, Option<_>>(
+ Some(Identifier::from("a").into()),
+ None,
+ )
+ .into()],
+ )
+ .into(),
+ ),
+ )])
+ .into()],
+ );
+}
diff --git a/boa/src/syntax/parser/expression/assignment/concise_body.rs b/boa/src/syntax/parser/expression/assignment/concise_body.rs
new file mode 100644
index 00000000000..990aaf1b24f
--- /dev/null
+++ b/boa/src/syntax/parser/expression/assignment/concise_body.rs
@@ -0,0 +1,74 @@
+use super::ExpressionBody;
+use crate::syntax::{
+ ast::{
+ node::{Return, StatementList},
+ Punctuator,
+ },
+ lexer::TokenKind,
+ parser::{error::ParseError, function::FunctionBody, AllowIn, Cursor, TokenParser},
+};
+
+use std::io::Read;
+
+/// ConciseBody / AsyncConciseBody parsing.
+///
+/// As these are effectively the same we just use a flag to reduce code duplication.
+///
+/// More information:
+/// - [MDN documentation][mdn]
+/// - [ECMAScript specification][spec]
+///
+/// Async More information:
+/// - [MDN documentation][async-mdn]
+/// - [ECMAScript specification][async-spec]
+///
+/// [mdn]:
+/// [spec]: https://tc39.es/ecma262/#prod-ConciseBody
+/// [mdn-async]:
+/// [spec-async]: https://tc39.es/ecma262/#prod-AsyncConciseBody
+#[derive(Debug, Clone, Copy)]
+pub(super) struct ConciseBody {
+ allow_in: AllowIn,
+ is_async: bool,
+}
+
+impl ConciseBody {
+ /// Creates a new `ConcideBody` parser.
+ pub(super) fn new(allow_in: I, is_async: bool) -> Self
+ where
+ I: Into,
+ {
+ Self {
+ allow_in: allow_in.into(),
+ is_async,
+ }
+ }
+}
+
+impl TokenParser for ConciseBody
+where
+ R: Read,
+{
+ type Output = StatementList;
+
+ fn parse(self, cursor: &mut Cursor) -> Result {
+ match cursor.peek(0)?.ok_or(ParseError::AbruptEnd)?.kind() {
+ TokenKind::Punctuator(Punctuator::OpenBlock) => {
+ let _ = cursor.next();
+ let body = FunctionBody::new(false, self.is_async).parse(cursor)?;
+ if self.is_async {
+ cursor.expect(Punctuator::CloseBlock, "async concise body")?;
+ } else {
+ cursor.expect(Punctuator::CloseBlock, "concise body")?;
+ }
+
+ Ok(body)
+ }
+ _ => Ok(StatementList::from(vec![Return::new(
+ ExpressionBody::new(self.allow_in, self.is_async).parse(cursor)?,
+ None,
+ )
+ .into()])),
+ }
+ }
+}
diff --git a/boa/src/syntax/parser/expression/assignment/expression_body.rs b/boa/src/syntax/parser/expression/assignment/expression_body.rs
new file mode 100644
index 00000000000..57c8cf27662
--- /dev/null
+++ b/boa/src/syntax/parser/expression/assignment/expression_body.rs
@@ -0,0 +1,39 @@
+use super::AssignmentExpression;
+use crate::syntax::{
+ ast::node::Node,
+ parser::{error::ParseResult, AllowAwait, AllowIn, Cursor, TokenParser},
+};
+
+use std::io::Read;
+
+///
+#[derive(Debug, Clone, Copy)]
+pub(super) struct ExpressionBody {
+ allow_in: AllowIn,
+ allow_await: AllowAwait,
+}
+
+impl ExpressionBody {
+ /// Creates a new `ExpressionBody` parser.
+ pub(super) fn new(allow_in: I, allow_await: A) -> Self
+ where
+ I: Into,
+ A: Into,
+ {
+ Self {
+ allow_in: allow_in.into(),
+ allow_await: allow_await.into(),
+ }
+ }
+}
+
+impl TokenParser for ExpressionBody
+where
+ R: Read,
+{
+ type Output = Node;
+
+ fn parse(self, cursor: &mut Cursor) -> ParseResult {
+ AssignmentExpression::new(self.allow_in, false, self.allow_await).parse(cursor)
+ }
+}
diff --git a/boa/src/syntax/parser/expression/assignment/mod.rs b/boa/src/syntax/parser/expression/assignment/mod.rs
index 0a7cf4c4d07..64a407508f0 100644
--- a/boa/src/syntax/parser/expression/assignment/mod.rs
+++ b/boa/src/syntax/parser/expression/assignment/mod.rs
@@ -8,10 +8,16 @@
//! [spec]: https://tc39.es/ecma262/#sec-assignment-operators
mod arrow_function;
+mod async_arrow_function;
+mod concise_body;
mod conditional;
mod exponentiation;
+mod expression_body;
-use self::{arrow_function::ArrowFunction, conditional::ConditionalExpression};
+use self::{
+ arrow_function::ArrowFunction, async_arrow_function::AsyncArrowFunction,
+ concise_body::ConciseBody, conditional::ConditionalExpression, expression_body::ExpressionBody,
+};
use crate::syntax::lexer::{Error as LexError, InputElement, TokenKind};
use crate::{
syntax::{
@@ -82,8 +88,33 @@ where
let _timer = BoaProfiler::global().start_event("AssignmentExpression", "Parsing");
cursor.set_goal(InputElement::Div);
+ println!("Assignment expression");
// Arrow function
match cursor.peek(0)?.ok_or(ParseError::AbruptEnd)?.kind() {
+ // Async a => {} or Async function or Async (a) => {}
+ TokenKind::Keyword(Keyword::Async) => {
+ if let Some(next_token) = cursor.peek(1)? {
+ match *next_token.kind() {
+ TokenKind::Identifier(_) => {
+ return AsyncArrowFunction::new(
+ self.allow_in,
+ self.allow_yield,
+ self.allow_await,
+ )
+ .parse(cursor)
+ .map(Node::AsyncArrowFunctionDecl);
+ }
+ TokenKind::Punctuator(Punctuator::OpenParen) => {
+ println!("OpenParen");
+ todo!("Async arrow func with () params");
+ }
+ _ => {
+ println!("Async not open Paren / Identifier");
+ }
+ }
+ }
+ }
+
// a=>{}
TokenKind::Identifier(_)
| TokenKind::Keyword(Keyword::Yield)
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 3bc2a5e2712..c8aaf0bf801 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
@@ -65,7 +65,7 @@ where
cursor.expect(Punctuator::OpenParen, "async function expression")?;
- let params = FormalParameters::new(false, true).parse(cursor)?;
+ let params = FormalParameters::new(false, true, false).parse(cursor)?;
cursor.expect(Punctuator::CloseParen, "async function expression")?;
cursor.expect(Punctuator::OpenBlock, "async function expression")?;
diff --git a/boa/src/syntax/parser/expression/primary/function_expression/mod.rs b/boa/src/syntax/parser/expression/primary/function_expression/mod.rs
index 645a5888668..2ce2694a132 100644
--- a/boa/src/syntax/parser/expression/primary/function_expression/mod.rs
+++ b/boa/src/syntax/parser/expression/primary/function_expression/mod.rs
@@ -60,7 +60,7 @@ where
cursor.expect(Punctuator::OpenParen, "function expression")?;
- let params = FormalParameters::new(false, false).parse(cursor)?;
+ let params = FormalParameters::new(false, false, false).parse(cursor)?;
cursor.expect(Punctuator::CloseParen, "function expression")?;
cursor.expect(Punctuator::OpenBlock, "function expression")?;
diff --git a/boa/src/syntax/parser/expression/primary/mod.rs b/boa/src/syntax/parser/expression/primary/mod.rs
index 16183f002ec..57db07fffba 100644
--- a/boa/src/syntax/parser/expression/primary/mod.rs
+++ b/boa/src/syntax/parser/expression/primary/mod.rs
@@ -82,9 +82,17 @@ where
TokenKind::Keyword(Keyword::Function) => {
FunctionExpression.parse(cursor).map(Node::from)
}
- TokenKind::Keyword(Keyword::Async) => AsyncFunctionExpression::new(self.allow_yield)
- .parse(cursor)
- .map(Node::from),
+ TokenKind::Keyword(Keyword::Async) => {
+ println!("Keyword async");
+ match cursor.peek(0)?.ok_or(ParseError::AbruptEnd)?.kind() {
+ TokenKind::Keyword(Keyword::Function) => {
+ AsyncFunctionExpression::new(self.allow_yield)
+ .parse(cursor)
+ .map(Node::from)
+ }
+ _ => Err(ParseError::unexpected(tok.clone(), "primary expression")),
+ }
+ }
TokenKind::Punctuator(Punctuator::OpenParen) => {
cursor.set_goal(InputElement::RegExp);
let expr =
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 5138be9251e..4596fb12187 100644
--- a/boa/src/syntax/parser/expression/primary/object_initializer/mod.rs
+++ b/boa/src/syntax/parser/expression/primary/object_initializer/mod.rs
@@ -212,7 +212,7 @@ where
"property method definition",
)?;
let first_param = cursor.peek(0)?.expect("current token disappeared").clone();
- let params = FormalParameters::new(false, false).parse(cursor)?;
+ let params = FormalParameters::new(false, false, false).parse(cursor)?;
cursor.expect(Punctuator::CloseParen, "method definition")?;
if idn == "get" {
if !params.is_empty() {
@@ -233,7 +233,7 @@ where
}
}
prop_name => {
- let params = FormalParameters::new(false, false).parse(cursor)?;
+ let params = FormalParameters::new(false, false, true).parse(cursor)?;
cursor.expect(Punctuator::CloseParen, "method definition")?;
(
MethodDefinitionKind::Ordinary,
diff --git a/boa/src/syntax/parser/function/mod.rs b/boa/src/syntax/parser/function/mod.rs
index 8340fe79640..e644547473e 100644
--- a/boa/src/syntax/parser/function/mod.rs
+++ b/boa/src/syntax/parser/function/mod.rs
@@ -27,23 +27,27 @@ use crate::{
};
use std::io::Read;
-/// Formal parameters parsing.
+/// UniqueFormalParameters / FormalParameters parsing.
+///
+/// Due to the similarity between these productions we use a unique flag rather than
+/// duplicating the code.
///
/// More information:
/// - [MDN documentation][mdn]
/// - [ECMAScript specification][spec]
///
/// [mdn]: https://developer.mozilla.org/en-US/docs/Glossary/Parameter
-/// [spec]: https://tc39.es/ecma262/#prod-FormalParameters
+/// [spec]: https://tc39.es/ecma262/#sec-function-definitions
#[derive(Debug, Clone, Copy)]
pub(in crate::syntax::parser) struct FormalParameters {
allow_yield: AllowYield,
allow_await: AllowAwait,
+ unique: bool,
}
impl FormalParameters {
/// Creates a new `FormalParameters` parser.
- pub(in crate::syntax::parser) fn new(allow_yield: Y, allow_await: A) -> Self
+ pub(in crate::syntax::parser) fn new(allow_yield: Y, allow_await: A, unique: bool) -> Self
where
Y: Into,
A: Into,
@@ -51,6 +55,7 @@ impl FormalParameters {
Self {
allow_yield: allow_yield.into(),
allow_await: allow_await.into(),
+ unique,
}
}
}
@@ -62,6 +67,7 @@ where
type Output = Box<[node::FormalParameter]>;
fn parse(self, cursor: &mut Cursor) -> Result {
+ // TODO UniqueFormalParameters
let _timer = BoaProfiler::global().start_event("FormalParameters", "Parsing");
cursor.set_goal(InputElement::RegExp);
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 049b458b3be..763fa68fdd9 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
@@ -75,7 +75,7 @@ where
cursor.expect(Punctuator::OpenParen, "async function declaration")?;
- let params = FormalParameters::new(false, true).parse(cursor)?;
+ let params = FormalParameters::new(false, true, false).parse(cursor)?;
cursor.expect(Punctuator::CloseParen, "async function declaration")?;
cursor.expect(Punctuator::OpenBlock, "async function declaration")?;
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 f40045b5fd1..fdf0def453d 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
@@ -56,7 +56,7 @@ where
cursor.expect(Punctuator::OpenParen, "function declaration")?;
- let params = FormalParameters::new(false, false).parse(cursor)?;
+ let params = FormalParameters::new(false, false, false).parse(cursor)?;
cursor.expect(Punctuator::CloseParen, "function declaration")?;
cursor.expect(Punctuator::OpenBlock, "function declaration")?;