use super::{PResult, Parser};
use crate::ast::{BinOp, Block, Stmt};
use crate::source::token::{Punct, Tok};
use crate::words::{ALL, Role};
const ASSIGN: &[(Punct, Option<BinOp>)] = &[
(Punct::Eq, None),
(Punct::PlusEq, Some(BinOp::Add)),
(Punct::MinusEq, Some(BinOp::Sub)),
(Punct::StarEq, Some(BinOp::Mul)),
(Punct::SlashEq, Some(BinOp::Div)),
(Punct::PercentEq, Some(BinOp::Rem)),
(Punct::NullAssign, Some(BinOp::Coalesce)),
];
impl Parser<'_, '_, '_> {
pub(crate) fn block(&mut self) -> PResult<Block> {
let start = self.need(Punct::LBrace)?;
let stmts = self.braces(Self::stmts)?;
Ok(Block {
stmts,
span: start.to(self.prev()),
})
}
pub(crate) fn stmts(&mut self) -> PResult<Vec<Stmt>> {
let mut stmts = Vec::new();
loop {
self.skip_newlines();
self.eat(Punct::Semi);
if self.eat(Punct::RBrace) {
return Ok(stmts);
}
if *self.tok() == Tok::Eof {
return Err(self.expected("`}`"));
}
match self.stmt().and_then(|s| self.end_stmt().map(|()| s)) {
Ok(s) => stmts.push(s),
Err(_) => self.recover(),
}
}
}
pub(crate) fn stmt(&mut self) -> PResult<Stmt> {
let word = ALL.iter().find_map(|w| {
w.role(|r| match *r {
Role::Stmt { parse } if self.at_word(w) => Some(parse),
_ => None,
})
});
if let Some(parse) = word {
return parse(self);
}
let expr = self.expr()?;
let assign = ASSIGN.iter().find(|(p, _)| self.at(*p));
let Some(&(_, op)) = assign else {
return Ok(Stmt::Expr(expr));
};
self.bump();
let value = self.expr()?;
Ok(Stmt::Assign {
place: expr,
op,
value,
})
}
pub(crate) fn optional_value(&mut self) -> PResult<Option<crate::ast::Expr>> {
if self.at_stmt_end() {
Ok(None)
} else {
self.expr().map(Some)
}
}
}