Skip to content

Commit

Permalink
Merge 970534e into f62a77d
Browse files Browse the repository at this point in the history
  • Loading branch information
Paul Lancaster authored Jan 12, 2021
2 parents f62a77d + 970534e commit 97327de
Show file tree
Hide file tree
Showing 16 changed files with 451 additions and 94 deletions.
Original file line number Diff line number Diff line change
@@ -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<P, B>(params: P, body: B) -> Self
where
P: Into<Box<[FormalParameter]>>,
B: Into<StatementList>,
{
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<Value> {
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<AsyncArrowFunctionDecl> for Node {
fn from(decl: AsyncArrowFunctionDecl) -> Self {
Self::AsyncArrowFunctionDecl(decl)
}
}
2 changes: 2 additions & 0 deletions boa/src/syntax/ast/node/declaration/mod.rs
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -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},
Expand Down
9 changes: 7 additions & 2 deletions boa/src/syntax/ast/node/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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),

Expand Down Expand Up @@ -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),
Expand All @@ -282,6 +286,7 @@ impl Executable for Node {
fn run(&self, context: &mut Context) -> Result<Value> {
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),
Expand Down
86 changes: 7 additions & 79 deletions boa/src/syntax/parser/expression/assignment/arrow_function.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
},
Expand Down Expand Up @@ -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 {
Expand All @@ -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))
}
}

/// <https://tc39.es/ecma262/#prod-ConciseBody>
#[derive(Debug, Clone, Copy)]
struct ConciseBody {
allow_in: AllowIn,
}

impl ConciseBody {
/// Creates a new `ConcideBody` parser.
fn new<I>(allow_in: I) -> Self
where
I: Into<AllowIn>,
{
Self {
allow_in: allow_in.into(),
}
}
}

impl<R> TokenParser<R> for ConciseBody
where
R: Read,
{
type Output = StatementList;

fn parse(self, cursor: &mut Cursor<R>) -> Result<Self::Output, ParseError> {
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()])),
}
}
}

/// <https://tc39.es/ecma262/#prod-ExpressionBody>
#[derive(Debug, Clone, Copy)]
struct ExpressionBody {
allow_in: AllowIn,
allow_await: AllowAwait,
}

impl ExpressionBody {
/// Creates a new `ExpressionBody` parser.
fn new<I, A>(allow_in: I, allow_await: A) -> Self
where
I: Into<AllowIn>,
A: Into<AllowAwait>,
{
Self {
allow_in: allow_in.into(),
allow_await: allow_await.into(),
}
}
}

impl<R> TokenParser<R> for ExpressionBody
where
R: Read,
{
type Output = Node;

fn parse(self, cursor: &mut Cursor<R>) -> ParseResult {
AssignmentExpression::new(self.allow_in, false, self.allow_await).parse(cursor)
}
}
Original file line number Diff line number Diff line change
@@ -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<I, Y, A>(
allow_in: I,
allow_yield: Y,
allow_await: A,
) -> Self
where
I: Into<AllowIn>,
Y: Into<AllowYield>,
A: Into<AllowAwait>,
{
Self {
allow_in: allow_in.into(),
allow_yield: allow_yield.into(),
allow_await: allow_await.into(),
}
}
}

impl<R> TokenParser<R> for AsyncArrowFunction
where
R: Read,
{
type Output = AsyncArrowFunctionDecl;

fn parse(self, cursor: &mut Cursor<R>) -> Result<Self::Output, ParseError> {
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))
}
}
Loading

0 comments on commit 97327de

Please sign in to comment.