use crate::{
Rule,
ast::*,
ast_ensure, ast_expr,
error::{AstError, AstResult, ErrorCode, IntoErr, collect_recovered},
parser::listen_rule,
};
impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for Block {
type Error = AstError<'a, Self>;
fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result<Self, Self::Error> {
ast_ensure!(pair, Rule::block => {
ast_expr!(Block(collect_recovered(pair.into_inner())))
})
}
}
impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for StatementBranch {
type Error = AstError<'a, Self>;
fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result<Self, Self::Error> {
let mut inner = pair.clone().into_inner();
ast_ensure!(pair, Rule::statement_branch => {
ast_expr!(StatementBranch {
condition: inner.next().unwrap().try_into(),
body: inner.next().unwrap().try_into().map(Box::new),
})
})
}
}
impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for Statement {
type Error = AstError<'a, Self>;
fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result<Self, Self::Error> {
let rule = pair.as_rule();
let mut inner = pair.clone().into_inner();
match rule {
Rule::statement => Statement::try_from(inner.next().unwrap()),
Rule::expr_stmt => {
ast_expr!(Statement::Expression(inner.next().unwrap().try_into()))
}
Rule::block => ast_expr!(Statement::Block(pair.try_into())),
Rule::var_decl_statement => ast_expr!(Statement::VarDecl(pair.try_into())),
Rule::return_stmt => {
ast_expr!(Statement::Return(
inner.next().map(Expression::try_from).transpose()
))
}
Rule::break_stmt => Ok(Statement::Break),
Rule::continue_stmt => Ok(Statement::Continue),
Rule::if_stmt => {
ast_expr!(Statement::If {
initial: inner.next().unwrap().try_into(),
else_if: collect_recovered(inner.next().unwrap().into_inner()),
else_branch: inner
.next()
.map(Statement::try_from)
.transpose()
.map(|v| v.map(Box::new))
.get_map(|v| { Some(Box::new(v)) }),
})
}
Rule::while_stmt => ast_expr!(Statement::While(inner.next().unwrap().try_into())),
Rule::c_for_stmt => ast_expr!(Statement::CStyleFor {
init: inner.next().unwrap().try_into().map(Box::new),
condition: inner.next().unwrap().try_into(),
update: inner.next().unwrap().try_into().map(Box::new),
body: inner.next().unwrap().try_into().map(Box::new),
}),
Rule::for_stmt => ast_expr!(Statement::For {
mutable: Ok(listen_rule(&mut inner, Rule::mutable)) as AstResult<'_, bool>,
pattern: inner.next().unwrap().try_into(),
iterator: inner.next().unwrap().try_into(),
body: inner.next().unwrap().try_into().map(Box::new),
}),
Rule::assign_statement => ast_expr!(Statement::Assign {
target: inner.next().unwrap().try_into(),
compound: Ok(inner.next().unwrap().as_str().trim().to_string())
as AstResult<'_, String>,
value: inner.next().unwrap().try_into(),
}),
Rule::match_stmt => ast_expr!(Statement::Match(
inner.next().unwrap().try_into(),
inner
.map(|match_itms| {
let mut match_inner = match_itms.into_inner();
Ok((
Pattern::try_from(match_inner.next().unwrap()).get()?,
Block::try_from(match_inner.next().unwrap()).get()?,
))
})
.collect::<AstResult<'a, Vec<_>>>(),
)),
Rule::increment_statement => {
ast_expr!(Statement::Increment(inner.next().unwrap().try_into()))
}
Rule::decrement_statement => {
ast_expr!(Statement::Decrement(inner.next().unwrap().try_into()))
}
Rule::unexpected_statement => {
return Err(AstError {
span: pair.as_span(),
error_code: ErrorCode::InvalidStatement,
error_message: "Invalid Statement".to_string(),
recovered: None,
});
}
_ => AstError::bug_unimplemented(pair),
}
}
}