From 1c8c6f9c87de13812b68d406ea36d3498afe9b87 Mon Sep 17 00:00:00 2001 From: Paul Lancaster Date: Sat, 10 Oct 2020 14:34:10 +0100 Subject: [PATCH] Reposition declaration parsing ready to add tests --- .../parser/statement/declaration/hoistable.rs | 211 ------------------ .../hoistable/async_function_decl/mod.rs | 88 ++++++++ .../hoistable/async_function_decl/tests.rs | 1 + .../hoistable/function_decl/mod.rs | 72 ++++++ .../hoistable/function_decl/tests.rs | 1 + .../statement/declaration/hoistable/mod.rs | 82 +++++++ .../statement/declaration/hoistable/tests.rs | 1 + 7 files changed, 245 insertions(+), 211 deletions(-) delete mode 100644 boa/src/syntax/parser/statement/declaration/hoistable.rs create mode 100644 boa/src/syntax/parser/statement/declaration/hoistable/async_function_decl/mod.rs create mode 100644 boa/src/syntax/parser/statement/declaration/hoistable/async_function_decl/tests.rs create mode 100644 boa/src/syntax/parser/statement/declaration/hoistable/function_decl/mod.rs create mode 100644 boa/src/syntax/parser/statement/declaration/hoistable/function_decl/tests.rs create mode 100644 boa/src/syntax/parser/statement/declaration/hoistable/mod.rs create mode 100644 boa/src/syntax/parser/statement/declaration/hoistable/tests.rs diff --git a/boa/src/syntax/parser/statement/declaration/hoistable.rs b/boa/src/syntax/parser/statement/declaration/hoistable.rs deleted file mode 100644 index 04e5704f9f..0000000000 --- a/boa/src/syntax/parser/statement/declaration/hoistable.rs +++ /dev/null @@ -1,211 +0,0 @@ -//! Hoistable declaration parsing. -//! -//! More information: -//! - [ECMAScript specification][spec] -//! -//! [spec]: https://tc39.es/ecma262/#prod-HoistableDeclaration - -use crate::{ - syntax::{ - ast::{ - node::{AsyncFunctionDecl, FunctionDecl}, - Keyword, Node, Punctuator, - }, - lexer::TokenKind, - parser::{ - function::FormalParameters, function::FunctionBody, statement::BindingIdentifier, - AllowAwait, AllowDefault, AllowYield, Cursor, ParseError, ParseResult, TokenParser, - }, - }, - BoaProfiler, -}; -use std::io::Read; - -/// Hoistable declaration parsing. -/// -/// More information: -/// - [ECMAScript specification][spec] -/// -/// [spec]: https://tc39.es/ecma262/#prod-FunctionDeclaration -#[derive(Debug, Clone, Copy)] -pub(super) struct HoistableDeclaration { - allow_yield: AllowYield, - allow_await: AllowAwait, - is_default: AllowDefault, -} - -impl HoistableDeclaration { - /// Creates a new `HoistableDeclaration` parser. - pub(super) 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 HoistableDeclaration -where - R: Read, -{ - type Output = Node; - - fn parse(self, cursor: &mut Cursor) -> ParseResult { - let _timer = BoaProfiler::global().start_event("HoistableDeclaration", "Parsing"); - 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), - } - } -} - -/// Function declaration parsing. -/// -/// More information: -/// - [MDN documentation][mdn] -/// - [ECMAScript specification][spec] -/// -/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/function -/// [spec]: https://tc39.es/ecma262/#prod-FunctionDeclaration -#[derive(Debug, Clone, Copy)] -struct FunctionDeclaration { - allow_yield: AllowYield, - allow_await: AllowAwait, - is_default: AllowDefault, -} - -impl FunctionDeclaration { - /// 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 FunctionDeclaration -where - R: Read, -{ - type Output = FunctionDecl; - - fn parse(self, cursor: &mut Cursor) -> Result { - cursor.expect(Keyword::Function, "function declaration")?; - - // TODO: If self.is_default, then this can be empty. - let name = BindingIdentifier::new(self.allow_yield, self.allow_await).parse(cursor)?; - - cursor.expect(Punctuator::OpenParen, "function declaration")?; - - let params = FormalParameters::new(false, false).parse(cursor)?; - - cursor.expect(Punctuator::CloseParen, "function declaration")?; - cursor.expect(Punctuator::OpenBlock, "function declaration")?; - - let body = FunctionBody::new(self.allow_yield, self.allow_await).parse(cursor)?; - - cursor.expect(Punctuator::CloseBlock, "function declaration")?; - - 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 { - cursor.expect(Keyword::Async, "async function declaration")?; - 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); - }; - - 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")?; - - Ok(AsyncFunctionDecl::new(name, params, body)) - } -} 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 new file mode 100644 index 0000000000..bfb73e44c0 --- /dev/null +++ b/boa/src/syntax/parser/statement/declaration/hoistable/async_function_decl/mod.rs @@ -0,0 +1,88 @@ +#[cfg(test)] +mod tests; + +use crate::syntax::{ + ast::{node::AsyncFunctionDecl, Keyword, Punctuator}, + lexer::TokenKind, + parser::{ + function::FormalParameters, function::FunctionBody, statement::BindingIdentifier, + AllowAwait, AllowDefault, AllowYield, Cursor, ParseError, TokenParser, + }, +}; +use std::io::Read; + +/// Async Function declaration parsing. +/// +/// More information: +/// - [MDN documentation][mdn] +/// - [ECMAScript specification][spec] +/// +/// [mdn]: +/// [spec]: +#[derive(Debug, Clone, Copy)] +pub(super) struct AsyncFunctionDeclaration { + allow_yield: AllowYield, + allow_await: AllowAwait, + is_default: AllowDefault, +} + +impl AsyncFunctionDeclaration { + /// Creates a new `FunctionDeclaration` parser. + pub(super) 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 { + cursor.expect(Keyword::Async, "async function declaration")?; + 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); + }; + + 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")?; + + Ok(AsyncFunctionDecl::new(name, params, body)) + } +} diff --git a/boa/src/syntax/parser/statement/declaration/hoistable/async_function_decl/tests.rs b/boa/src/syntax/parser/statement/declaration/hoistable/async_function_decl/tests.rs new file mode 100644 index 0000000000..8b13789179 --- /dev/null +++ b/boa/src/syntax/parser/statement/declaration/hoistable/async_function_decl/tests.rs @@ -0,0 +1 @@ + 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 new file mode 100644 index 0000000000..1452922686 --- /dev/null +++ b/boa/src/syntax/parser/statement/declaration/hoistable/function_decl/mod.rs @@ -0,0 +1,72 @@ +#[cfg(test)] +mod tests; + +use crate::{ + syntax::{ + ast::{node::FunctionDecl, Keyword, Punctuator}, + parser::{ + function::FormalParameters, function::FunctionBody, statement::BindingIdentifier, + AllowAwait, AllowDefault, AllowYield, Cursor, ParseError, TokenParser, + }, + }, +}; +use std::io::Read; + +/// Function declaration parsing. +/// +/// More information: +/// - [MDN documentation][mdn] +/// - [ECMAScript specification][spec] +/// +/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/function +/// [spec]: https://tc39.es/ecma262/#prod-FunctionDeclaration + +#[derive(Debug, Clone, Copy)] +pub(super) struct FunctionDeclaration { + allow_yield: AllowYield, + allow_await: AllowAwait, + is_default: AllowDefault, +} + +impl FunctionDeclaration { + /// Creates a new `FunctionDeclaration` parser. + pub(super) 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 FunctionDeclaration +where + R: Read, +{ + type Output = FunctionDecl; + + fn parse(self, cursor: &mut Cursor) -> Result { + cursor.expect(Keyword::Function, "function declaration")?; + + // TODO: If self.is_default, then this can be empty. + let name = BindingIdentifier::new(self.allow_yield, self.allow_await).parse(cursor)?; + + cursor.expect(Punctuator::OpenParen, "function declaration")?; + + let params = FormalParameters::new(false, false).parse(cursor)?; + + cursor.expect(Punctuator::CloseParen, "function declaration")?; + cursor.expect(Punctuator::OpenBlock, "function declaration")?; + + let body = FunctionBody::new(self.allow_yield, self.allow_await).parse(cursor)?; + + cursor.expect(Punctuator::CloseBlock, "function declaration")?; + + Ok(FunctionDecl::new(name, params, body)) + } +} diff --git a/boa/src/syntax/parser/statement/declaration/hoistable/function_decl/tests.rs b/boa/src/syntax/parser/statement/declaration/hoistable/function_decl/tests.rs new file mode 100644 index 0000000000..8b13789179 --- /dev/null +++ b/boa/src/syntax/parser/statement/declaration/hoistable/function_decl/tests.rs @@ -0,0 +1 @@ + diff --git a/boa/src/syntax/parser/statement/declaration/hoistable/mod.rs b/boa/src/syntax/parser/statement/declaration/hoistable/mod.rs new file mode 100644 index 0000000000..bfb104d67d --- /dev/null +++ b/boa/src/syntax/parser/statement/declaration/hoistable/mod.rs @@ -0,0 +1,82 @@ +//! Hoistable declaration parsing. +//! +//! More information: +//! - [ECMAScript specification][spec] +//! +//! [spec]: https://tc39.es/ecma262/#prod-HoistableDeclaration + +#[cfg(test)] +mod tests; + +mod async_function_decl; +mod function_decl; + +use async_function_decl::AsyncFunctionDeclaration; +use function_decl::FunctionDeclaration; + +use crate::{ + syntax::{ + ast::{Keyword, Node}, + lexer::TokenKind, + parser::{ + AllowAwait, AllowDefault, AllowYield, Cursor, ParseError, ParseResult, TokenParser, + }, + }, + BoaProfiler, +}; +use std::io::Read; + +/// Hoistable declaration parsing. +/// +/// More information: +/// - [ECMAScript specification][spec] +/// +/// [spec]: https://tc39.es/ecma262/#prod-FunctionDeclaration +#[derive(Debug, Clone, Copy)] +pub(super) struct HoistableDeclaration { + allow_yield: AllowYield, + allow_await: AllowAwait, + is_default: AllowDefault, +} + +impl HoistableDeclaration { + /// Creates a new `HoistableDeclaration` parser. + pub(super) 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 HoistableDeclaration +where + R: Read, +{ + type Output = Node; + + fn parse(self, cursor: &mut Cursor) -> ParseResult { + let _timer = BoaProfiler::global().start_event("HoistableDeclaration", "Parsing"); + 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), + } + } +} diff --git a/boa/src/syntax/parser/statement/declaration/hoistable/tests.rs b/boa/src/syntax/parser/statement/declaration/hoistable/tests.rs new file mode 100644 index 0000000000..8b13789179 --- /dev/null +++ b/boa/src/syntax/parser/statement/declaration/hoistable/tests.rs @@ -0,0 +1 @@ +