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), 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)), 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"); + } +}