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")?;