Browse Source

Reposition declaration parsing ready to add tests

pull/836/head
Paul Lancaster 4 years ago
parent
commit
1c8c6f9c87
  1. 211
      boa/src/syntax/parser/statement/declaration/hoistable.rs
  2. 88
      boa/src/syntax/parser/statement/declaration/hoistable/async_function_decl/mod.rs
  3. 1
      boa/src/syntax/parser/statement/declaration/hoistable/async_function_decl/tests.rs
  4. 72
      boa/src/syntax/parser/statement/declaration/hoistable/function_decl/mod.rs
  5. 1
      boa/src/syntax/parser/statement/declaration/hoistable/function_decl/tests.rs
  6. 82
      boa/src/syntax/parser/statement/declaration/hoistable/mod.rs
  7. 1
      boa/src/syntax/parser/statement/declaration/hoistable/tests.rs

211
boa/src/syntax/parser/statement/declaration/hoistable.rs

@ -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<Y, A, D>(allow_yield: Y, allow_await: A, is_default: D) -> Self
where
Y: Into<AllowYield>,
A: Into<AllowAwait>,
D: Into<AllowDefault>,
{
Self {
allow_yield: allow_yield.into(),
allow_await: allow_await.into(),
is_default: is_default.into(),
}
}
}
impl<R> TokenParser<R> for HoistableDeclaration
where
R: Read,
{
type Output = Node;
fn parse(self, cursor: &mut Cursor<R>) -> 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<Y, A, D>(allow_yield: Y, allow_await: A, is_default: D) -> Self
where
Y: Into<AllowYield>,
A: Into<AllowAwait>,
D: Into<AllowDefault>,
{
Self {
allow_yield: allow_yield.into(),
allow_await: allow_await.into(),
is_default: is_default.into(),
}
}
}
impl<R> TokenParser<R> for FunctionDeclaration
where
R: Read,
{
type Output = FunctionDecl;
fn parse(self, cursor: &mut Cursor<R>) -> Result<Self::Output, ParseError> {
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<Y, A, D>(allow_yield: Y, allow_await: A, is_default: D) -> Self
where
Y: Into<AllowYield>,
A: Into<AllowAwait>,
D: Into<AllowDefault>,
{
Self {
allow_yield: allow_yield.into(),
allow_await: allow_await.into(),
is_default: is_default.into(),
}
}
}
impl<R> TokenParser<R> for AsyncFunctionDeclaration
where
R: Read,
{
type Output = AsyncFunctionDecl;
fn parse(self, cursor: &mut Cursor<R>) -> Result<Self::Output, ParseError> {
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))
}
}

88
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<Y, A, D>(allow_yield: Y, allow_await: A, is_default: D) -> Self
where
Y: Into<AllowYield>,
A: Into<AllowAwait>,
D: Into<AllowDefault>,
{
Self {
allow_yield: allow_yield.into(),
allow_await: allow_await.into(),
is_default: is_default.into(),
}
}
}
impl<R> TokenParser<R> for AsyncFunctionDeclaration
where
R: Read,
{
type Output = AsyncFunctionDecl;
fn parse(self, cursor: &mut Cursor<R>) -> Result<Self::Output, ParseError> {
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))
}
}

1
boa/src/syntax/parser/statement/declaration/hoistable/async_function_decl/tests.rs

@ -0,0 +1 @@

72
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<Y, A, D>(allow_yield: Y, allow_await: A, is_default: D) -> Self
where
Y: Into<AllowYield>,
A: Into<AllowAwait>,
D: Into<AllowDefault>,
{
Self {
allow_yield: allow_yield.into(),
allow_await: allow_await.into(),
is_default: is_default.into(),
}
}
}
impl<R> TokenParser<R> for FunctionDeclaration
where
R: Read,
{
type Output = FunctionDecl;
fn parse(self, cursor: &mut Cursor<R>) -> Result<Self::Output, ParseError> {
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))
}
}

1
boa/src/syntax/parser/statement/declaration/hoistable/function_decl/tests.rs

@ -0,0 +1 @@

82
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<Y, A, D>(allow_yield: Y, allow_await: A, is_default: D) -> Self
where
Y: Into<AllowYield>,
A: Into<AllowAwait>,
D: Into<AllowDefault>,
{
Self {
allow_yield: allow_yield.into(),
allow_await: allow_await.into(),
is_default: is_default.into(),
}
}
}
impl<R> TokenParser<R> for HoistableDeclaration
where
R: Read,
{
type Output = Node;
fn parse(self, cursor: &mut Cursor<R>) -> 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),
}
}
}

1
boa/src/syntax/parser/statement/declaration/hoistable/tests.rs

@ -0,0 +1 @@
Loading…
Cancel
Save