use crate::{
syntax::{
ast::{
node::{VarDecl, VarDeclList},
Keyword, Punctuator, TokenKind,
},
parser::{
expression::Initializer, statement::BindingIdentifier, AllowAwait, AllowIn, AllowYield,
Cursor, ParseError, TokenParser,
},
},
BoaProfiler,
};
#[derive(Debug, Clone, Copy)]
pub(in crate::syntax::parser::statement) struct VariableStatement {
allow_yield: AllowYield,
allow_await: AllowAwait,
}
impl VariableStatement {
pub(in crate::syntax::parser::statement) 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 TokenParser for VariableStatement {
type Output = VarDeclList;
fn parse(self, cursor: &mut Cursor<'_>) -> Result<Self::Output, ParseError> {
let _timer = BoaProfiler::global().start_event("VariableStatement", "Parsing");
cursor.expect(Keyword::Var, "variable statement")?;
let decl_list =
VariableDeclarationList::new(true, self.allow_yield, self.allow_await).parse(cursor)?;
cursor.expect_semicolon(false, "variable statement")?;
Ok(decl_list)
}
}
#[derive(Debug, Clone, Copy)]
pub(in crate::syntax::parser::statement) struct VariableDeclarationList {
allow_in: AllowIn,
allow_yield: AllowYield,
allow_await: AllowAwait,
}
impl VariableDeclarationList {
pub(in crate::syntax::parser::statement) 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 TokenParser for VariableDeclarationList {
type Output = VarDeclList;
fn parse(self, cursor: &mut Cursor<'_>) -> Result<Self::Output, ParseError> {
let mut list = Vec::new();
loop {
list.push(
VariableDeclaration::new(self.allow_in, self.allow_yield, self.allow_await)
.parse(cursor)?,
);
match cursor.peek_semicolon(false) {
(true, _) => break,
(false, Some(tk)) if tk.kind == TokenKind::Punctuator(Punctuator::Comma) => {
let _ = cursor.next();
}
_ => {
return Err(ParseError::expected(
vec![
TokenKind::Punctuator(Punctuator::Semicolon),
TokenKind::LineTerminator,
],
cursor.next().ok_or(ParseError::AbruptEnd)?.clone(),
"lexical declaration",
))
}
}
}
Ok(VarDeclList::from(list))
}
}
#[derive(Debug, Clone, Copy)]
struct VariableDeclaration {
allow_in: AllowIn,
allow_yield: AllowYield,
allow_await: AllowAwait,
}
impl VariableDeclaration {
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 TokenParser for VariableDeclaration {
type Output = VarDecl;
fn parse(self, cursor: &mut Cursor<'_>) -> Result<Self::Output, ParseError> {
let name = BindingIdentifier::new(self.allow_yield, self.allow_await).parse(cursor)?;
let ident =
Initializer::new(self.allow_in, self.allow_yield, self.allow_await).try_parse(cursor);
Ok(VarDecl::new(name, ident))
}
}