mod loop_stmt;
mod ts_try_stmt;
use super::expr::errors::{ParseError, ParseErrorKind, ParseResult};
use super::*;
impl Parser {
pub(super) fn parse_stmt(&mut self) -> ParseResult<IrNode> {
let start_byte = self.current_byte_offset();
let kind = self
.current_kind()
.ok_or_else(|| ParseError::unexpected_eof(self.current_byte_offset(), "statement"))?;
match kind {
SyntaxKind::Semicolon => {
let token = self.consume().unwrap();
Ok(IrNode::empty_stmt(&token))
}
SyntaxKind::ReturnKw => self.parse_return_stmt(),
SyntaxKind::ThrowKw => self.parse_throw_stmt(),
SyntaxKind::IfKw => self.parse_ts_if_stmt(),
SyntaxKind::ForKw | SyntaxKind::WhileKw => self.parse_ts_loop_stmt(),
SyntaxKind::TryKw => self.parse_ts_try_stmt(),
SyntaxKind::ConstKw | SyntaxKind::LetKw | SyntaxKind::VarKw => {
self.parse_var_decl(false)
}
SyntaxKind::At => self
.parse_interpolation()
.map_err(|e| e.with_context("statement placeholder")),
SyntaxKind::LBrace => self.parse_block_stmt(),
_ => {
let expr = self
.parse_ts_expr_until(&[SyntaxKind::Semicolon])
.map_err(|e| e.with_context("expression statement"))?;
if self.at(SyntaxKind::Semicolon) {
self.consume();
}
Ok(IrNode::ExprStmt {
span: IrSpan::new(start_byte, self.current_byte_offset()),
expr: Box::new(expr),
})
}
}
}
pub(super) fn parse_return_stmt(&mut self) -> ParseResult<IrNode> {
let start_byte = self.current_byte_offset();
#[cfg(debug_assertions)]
let debug_parser = std::env::var("MF_DEBUG_PARSER").is_ok();
self.consume().ok_or_else(|| {
ParseError::unexpected_eof(self.current_byte_offset(), "return keyword")
})?; self.skip_whitespace();
#[cfg(debug_assertions)]
if debug_parser {
eprintln!(
"[MF_DEBUG_PARSER] parse_return_stmt: current token = {:?}",
self.current()
);
}
if self.at(SyntaxKind::Semicolon) || self.at(SyntaxKind::RBrace) {
#[cfg(debug_assertions)]
if debug_parser {
eprintln!(
"[MF_DEBUG_PARSER] parse_return_stmt: at semicolon or rbrace, returning None arg"
);
}
if self.at(SyntaxKind::Semicolon) {
self.consume();
}
return Ok(IrNode::ReturnStmt {
span: IrSpan::new(start_byte, self.current_byte_offset()),
arg: None,
});
}
let arg = self
.parse_ts_expr_until(&[SyntaxKind::Semicolon])
.map_err(|e| e.with_context("parsing return statement"))?;
#[cfg(debug_assertions)]
if debug_parser {
eprintln!("[MF_DEBUG_PARSER] parse_return_stmt: arg = {:?}", arg);
}
if self.at(SyntaxKind::Semicolon) {
self.consume();
}
Ok(IrNode::ReturnStmt {
span: IrSpan::new(start_byte, self.current_byte_offset()),
arg: Some(Box::new(arg)),
})
}
pub(super) fn parse_throw_stmt(&mut self) -> ParseResult<IrNode> {
let start_byte = self.current_byte_offset();
self.consume().ok_or_else(|| {
ParseError::unexpected_eof(self.current_byte_offset(), "throw keyword")
})?; self.skip_whitespace();
let arg = self
.parse_ts_expr_until(&[SyntaxKind::Semicolon])
.map_err(|e| e.with_context("parsing throw statement"))?;
if self.at(SyntaxKind::Semicolon) {
self.consume();
}
Ok(IrNode::ThrowStmt {
span: IrSpan::new(start_byte, self.current_byte_offset()),
arg: Box::new(arg),
})
}
pub(super) fn parse_ts_if_stmt(&mut self) -> ParseResult<IrNode> {
let start_byte = self.current_byte_offset();
#[cfg(debug_assertions)]
let debug_parser = std::env::var("MF_DEBUG_PARSER").is_ok();
self.consume()
.ok_or_else(|| ParseError::unexpected_eof(self.current_byte_offset(), "if keyword"))?; self.skip_whitespace();
self.expect(SyntaxKind::LParen).ok_or_else(|| {
ParseError::new(ParseErrorKind::UnexpectedToken, self.current_byte_offset())
.with_context("parsing if statement condition")
.with_expected(&["("])
})?;
let test = self
.parse_ts_expr_until(&[SyntaxKind::RParen])
.map_err(|e| e.with_context("parsing if statement condition"))?;
#[cfg(debug_assertions)]
if debug_parser {
eprintln!("[MF_DEBUG_PARSER] parse_ts_if_stmt: test = {:?}", test);
}
self.expect(SyntaxKind::RParen).ok_or_else(|| {
ParseError::new(
ParseErrorKind::MissingClosingParen,
self.current_byte_offset(),
)
.with_context("parsing if statement condition")
})?;
self.skip_whitespace();
#[cfg(debug_assertions)]
if debug_parser {
eprintln!(
"[MF_DEBUG_PARSER] parse_ts_if_stmt: after ), current = {:?}",
self.current()
);
}
let cons = if self.at(SyntaxKind::LBrace) {
self.parse_block_stmt()
.map_err(|e| e.with_context("parsing if statement consequent block"))?
} else {
self.parse_stmt()
.map_err(|e| e.with_context("parsing if statement consequent"))?
};
#[cfg(debug_assertions)]
if debug_parser {
eprintln!("[MF_DEBUG_PARSER] parse_ts_if_stmt: cons = {:?}", cons);
}
self.skip_whitespace();
let alt = if self.at(SyntaxKind::ElseKw) {
self.consume();
self.skip_whitespace();
if self.at(SyntaxKind::LBrace) {
Some(Box::new(
self.parse_block_stmt()
.map_err(|e| e.with_context("parsing else block"))?,
))
} else if self.at(SyntaxKind::IfKw) {
Some(Box::new(
self.parse_ts_if_stmt()
.map_err(|e| e.with_context("parsing else-if statement"))?,
))
} else {
Some(Box::new(self.parse_stmt().map_err(|e| {
e.with_context("parsing else statement body")
})?))
}
} else {
None
};
Ok(IrNode::TsIfStmt {
span: IrSpan::new(start_byte, self.current_byte_offset()),
test: Box::new(test),
cons: Box::new(cons),
alt,
})
}
fn parse_stmt_list(&mut self) -> super::ParseResult<Vec<IrNode>> {
let mut stmts = Vec::new();
while !self.at_eof() && !self.at(SyntaxKind::RBrace) {
self.skip_whitespace();
if self.at(SyntaxKind::RBrace) {
break;
}
if self.at_brace_hash_open() {
let kind = self.current_kind().unwrap();
stmts.push(self.parse_control_block(kind)?);
continue;
}
if self.at(SyntaxKind::DollarOpen) {
if let Some(node) = self.parse_directive() {
stmts.push(node);
}
continue;
}
match self.parse_stmt() {
Ok(stmt) => stmts.push(stmt),
Err(e) => return Err(e.with_context("parsing statement in block")),
}
}
Ok(Self::merge_adjacent_text(stmts))
}
}