mod block;
mod break_stm;
mod continue_stm;
mod declaration;
mod expression;
mod if_stm;
mod iteration;
mod labelled_stm;
mod return_stm;
mod switch;
mod throw;
mod try_stm;
mod variable;
use self::{
block::BlockStatement,
break_stm::BreakStatement,
continue_stm::ContinueStatement,
declaration::Declaration,
expression::ExpressionStatement,
if_stm::IfStatement,
iteration::{DoWhileStatement, ForStatement, WhileStatement},
return_stm::ReturnStatement,
switch::SwitchStatement,
throw::ThrowStatement,
try_stm::TryStatement,
variable::VariableStatement,
};
use super::{AllowAwait, AllowReturn, AllowYield, Cursor, ParseError, TokenParser};
use crate::syntax::lexer::{InputElement, TokenKind};
use crate::{
syntax::ast::{node, Keyword, Node, Punctuator},
BoaProfiler,
};
use labelled_stm::LabelledStatement;
use std::io::Read;
#[derive(Debug, Clone, Copy)]
pub(super) struct Statement {
allow_yield: AllowYield,
allow_await: AllowAwait,
allow_return: AllowReturn,
}
impl Statement {
pub(super) fn new<Y, A, R>(allow_yield: Y, allow_await: A, allow_return: R) -> Self
where
Y: Into<AllowYield>,
A: Into<AllowAwait>,
R: Into<AllowReturn>,
{
Self {
allow_yield: allow_yield.into(),
allow_await: allow_await.into(),
allow_return: allow_return.into(),
}
}
}
impl<R> TokenParser<R> for Statement
where
R: Read,
{
type Output = Node;
fn parse(self, cursor: &mut Cursor<R>) -> Result<Self::Output, ParseError> {
let _timer = BoaProfiler::global().start_event("Statement", "Parsing");
let tok = cursor.peek(0)?.ok_or(ParseError::AbruptEnd)?;
match tok.kind() {
TokenKind::Keyword(Keyword::If) => {
IfStatement::new(self.allow_yield, self.allow_await, self.allow_return)
.parse(cursor)
.map(Node::from)
}
TokenKind::Keyword(Keyword::Var) => {
VariableStatement::new(self.allow_yield, self.allow_await)
.parse(cursor)
.map(Node::from)
}
TokenKind::Keyword(Keyword::While) => {
WhileStatement::new(self.allow_yield, self.allow_await, self.allow_return)
.parse(cursor)
.map(Node::from)
}
TokenKind::Keyword(Keyword::Do) => {
DoWhileStatement::new(self.allow_yield, self.allow_await, self.allow_return)
.parse(cursor)
.map(Node::from)
}
TokenKind::Keyword(Keyword::For) => {
ForStatement::new(self.allow_yield, self.allow_await, self.allow_return)
.parse(cursor)
.map(Node::from)
}
TokenKind::Keyword(Keyword::Return) => {
if self.allow_return.0 {
ReturnStatement::new(self.allow_yield, self.allow_await)
.parse(cursor)
.map(Node::from)
} else {
Err(ParseError::unexpected(tok.clone(), "statement"))
}
}
TokenKind::Keyword(Keyword::Break) => {
BreakStatement::new(self.allow_yield, self.allow_await)
.parse(cursor)
.map(Node::from)
}
TokenKind::Keyword(Keyword::Continue) => {
ContinueStatement::new(self.allow_yield, self.allow_await)
.parse(cursor)
.map(Node::from)
}
TokenKind::Keyword(Keyword::Try) => {
TryStatement::new(self.allow_yield, self.allow_await, self.allow_return)
.parse(cursor)
.map(Node::from)
}
TokenKind::Keyword(Keyword::Throw) => {
ThrowStatement::new(self.allow_yield, self.allow_await)
.parse(cursor)
.map(Node::from)
}
TokenKind::Keyword(Keyword::Switch) => {
SwitchStatement::new(self.allow_yield, self.allow_await, self.allow_return)
.parse(cursor)
.map(Node::from)
}
TokenKind::Punctuator(Punctuator::OpenBlock) => {
BlockStatement::new(self.allow_yield, self.allow_await, self.allow_return)
.parse(cursor)
.map(Node::from)
}
TokenKind::Identifier(_) => {
cursor.set_goal(InputElement::Div);
let tok = cursor.peek(1)?;
if tok.is_some()
&& matches!(
tok.unwrap().kind(),
TokenKind::Punctuator(Punctuator::Colon)
)
{
return LabelledStatement::new(
self.allow_yield,
self.allow_await,
self.allow_return,
)
.parse(cursor)
.map(Node::from);
}
ExpressionStatement::new(self.allow_yield, self.allow_await).parse(cursor)
}
_ => ExpressionStatement::new(self.allow_yield, self.allow_await).parse(cursor),
}
}
}
#[derive(Debug, Clone, Copy)]
pub(super) struct StatementList {
allow_yield: AllowYield,
allow_await: AllowAwait,
allow_return: AllowReturn,
break_when_closingbraces: bool,
}
impl StatementList {
pub(super) fn new<Y, A, R>(
allow_yield: Y,
allow_await: A,
allow_return: R,
break_when_closingbraces: bool,
) -> Self
where
Y: Into<AllowYield>,
A: Into<AllowAwait>,
R: Into<AllowReturn>,
{
Self {
allow_yield: allow_yield.into(),
allow_await: allow_await.into(),
allow_return: allow_return.into(),
break_when_closingbraces,
}
}
pub(crate) fn parse_generalised<R>(
self,
cursor: &mut Cursor<R>,
break_nodes: &[TokenKind],
) -> Result<node::StatementList, ParseError>
where
R: Read,
{
let mut items = Vec::new();
loop {
if let Some(token) = cursor.peek(0)? {
if break_nodes.contains(token.kind()) {
break;
}
} else {
return Err(ParseError::AbruptEnd);
}
let item =
StatementListItem::new(self.allow_yield, self.allow_await, self.allow_return)
.parse(cursor)?;
items.push(item);
while cursor.next_if(Punctuator::Semicolon)?.is_some() {}
}
items.sort_by(Node::hoistable_order);
Ok(items.into())
}
}
impl<R> TokenParser<R> for StatementList
where
R: Read,
{
type Output = node::StatementList;
fn parse(self, cursor: &mut Cursor<R>) -> Result<Self::Output, ParseError> {
let _timer = BoaProfiler::global().start_event("StatementList", "Parsing");
let mut items = Vec::new();
loop {
match cursor.peek(0)? {
Some(token) if token.kind() == &TokenKind::Punctuator(Punctuator::CloseBlock) => {
if self.break_when_closingbraces {
break;
} else {
return Err(ParseError::unexpected(token.clone(), None));
}
}
None => {
if self.break_when_closingbraces {
return Err(ParseError::AbruptEnd);
} else {
break;
}
}
_ => {}
}
let item =
StatementListItem::new(self.allow_yield, self.allow_await, self.allow_return)
.parse(cursor)?;
items.push(item);
while cursor.next_if(Punctuator::Semicolon)?.is_some() {}
}
items.sort_by(Node::hoistable_order);
Ok(items.into())
}
}
#[derive(Debug, Clone, Copy)]
struct StatementListItem {
allow_yield: AllowYield,
allow_await: AllowAwait,
allow_return: AllowReturn,
}
impl StatementListItem {
fn new<Y, A, R>(allow_yield: Y, allow_await: A, allow_return: R) -> Self
where
Y: Into<AllowYield>,
A: Into<AllowAwait>,
R: Into<AllowReturn>,
{
Self {
allow_yield: allow_yield.into(),
allow_await: allow_await.into(),
allow_return: allow_return.into(),
}
}
}
impl<R> TokenParser<R> for StatementListItem
where
R: Read,
{
type Output = Node;
fn parse(self, cursor: &mut Cursor<R>) -> Result<Self::Output, ParseError> {
let _timer = BoaProfiler::global().start_event("StatementListItem", "Parsing");
let tok = cursor.peek(0)?.ok_or(ParseError::AbruptEnd)?;
match *tok.kind() {
TokenKind::Keyword(Keyword::Function)
| TokenKind::Keyword(Keyword::Const)
| TokenKind::Keyword(Keyword::Let) => {
Declaration::new(self.allow_yield, self.allow_await).parse(cursor)
}
_ => {
Statement::new(self.allow_yield, self.allow_await, self.allow_return).parse(cursor)
}
}
}
}
pub(super) type LabelIdentifier = BindingIdentifier;
#[derive(Debug, Clone, Copy)]
pub(super) struct BindingIdentifier {
allow_yield: AllowYield,
allow_await: AllowAwait,
}
impl BindingIdentifier {
pub(super) fn new<Y, A>(allow_yield: Y, allow_await: A) -> Self
where
Y: Into<AllowYield>,
A: Into<AllowAwait>,
{
Self {
allow_yield: allow_yield.into(),
allow_await: allow_await.into(),
}
}
}
impl<R> TokenParser<R> for BindingIdentifier
where
R: Read,
{
type Output = Box<str>;
fn parse(self, cursor: &mut Cursor<R>) -> Result<Self::Output, ParseError> {
let _timer = BoaProfiler::global().start_event("BindingIdentifier", "Parsing");
let next_token = cursor.next()?.ok_or(ParseError::AbruptEnd)?;
match next_token.kind() {
TokenKind::Identifier(ref s) => Ok(s.clone()),
TokenKind::Keyword(k @ Keyword::Yield) if !self.allow_yield.0 => Ok(k.as_str().into()),
TokenKind::Keyword(k @ Keyword::Await) if !self.allow_await.0 => Ok(k.as_str().into()),
_ => Err(ParseError::expected(
vec![TokenKind::identifier("identifier")],
next_token,
"binding identifier",
)),
}
}
}