use core::mem::take;
use crate::ast::prelude::*;
#[test]
#[cfg(not(miri))]
fn ast_parse() {
rt::<ast::Stmt>("let x = 1;");
rt::<ast::Stmt>("#[attr] let a = f();");
rt::<ast::Stmt>("line!().bar()");
}
#[derive(Debug, TryClone, PartialEq, Eq, ToTokens, Spanned)]
#[non_exhaustive]
#[allow(clippy::large_enum_variant)]
pub enum Stmt {
Local(Box<ast::Local>),
Item(ast::Item, #[rune(iter)] Option<T![;]>),
Expr(ast::Expr),
Semi(StmtSemi),
}
impl Peek for Stmt {
fn peek(p: &mut Peeker<'_>) -> bool {
matches!(p.nth(0), K![let]) || ItemOrExpr::peek(p)
}
}
impl Parse for Stmt {
fn parse(p: &mut Parser<'_>) -> Result<Self> {
let mut attributes = p.parse()?;
let visibility = p.parse()?;
if ast::Item::peek_as_item(p.peeker()) {
let path = p.parse::<Option<ast::Path>>()?;
let item: ast::Item = ast::Item::parse_with_meta_path(p, attributes, visibility, path)?;
let semi = if item.needs_semi_colon() {
Some(p.parse()?)
} else {
p.parse()?
};
return Ok(Self::Item(item, semi));
}
if let Some(span) = visibility.option_span() {
return Err(compile::Error::unsupported(span, "visibility modifier"));
}
let stmt = if let K![let] = p.nth(0)? {
let local = Box::try_new(ast::Local::parse_with_meta(p, take(&mut attributes))?)?;
Self::Local(local)
} else {
let expr = ast::Expr::parse_with_meta(p, &mut attributes, ast::expr::CALLABLE)?;
match p.parse()? {
Some(semi) => Self::Semi(StmtSemi::new(expr, semi)),
None => Self::Expr(expr),
}
};
if let Some(span) = attributes.option_span() {
return Err(compile::Error::unsupported(span, "attributes"));
}
Ok(stmt)
}
}
#[derive(Debug, TryClone, PartialEq, Eq)]
#[non_exhaustive]
#[allow(clippy::large_enum_variant)]
pub enum ItemOrExpr {
Item(ast::Item),
Expr(ast::Expr),
}
impl Peek for ItemOrExpr {
fn peek(p: &mut Peeker<'_>) -> bool {
match p.nth(0) {
K![use] => true,
K![enum] => true,
K![struct] => true,
K![impl] => true,
K![async] => matches!(p.nth(1), K![fn]),
K![fn] => true,
K![mod] => true,
K![const] => true,
K![ident(..)] => true,
K![::] => true,
_ => ast::Expr::peek(p),
}
}
}
impl Parse for ItemOrExpr {
fn parse(p: &mut Parser<'_>) -> Result<Self> {
let mut attributes = p.parse()?;
let visibility = p.parse()?;
if ast::Item::peek_as_item(p.peeker()) {
let path = p.parse()?;
let item: ast::Item = ast::Item::parse_with_meta_path(p, attributes, visibility, path)?;
return Ok(Self::Item(item));
}
if let Some(span) = visibility.option_span() {
return Err(compile::Error::unsupported(span, "visibility modifier"));
}
let expr = ast::Expr::parse_with_meta(p, &mut attributes, ast::expr::CALLABLE)?;
if let Some(span) = attributes.option_span() {
return Err(compile::Error::unsupported(span, "attributes"));
}
Ok(Self::Expr(expr))
}
}
#[derive(Debug, TryClone, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
#[try_clone(copy)]
#[non_exhaustive]
pub enum StmtSortKey {
Use,
Item,
Other,
}
#[derive(Debug, TryClone, PartialEq, Eq, ToTokens, Spanned)]
#[non_exhaustive]
pub struct StmtSemi {
pub expr: ast::Expr,
pub semi_token: T![;],
}
impl StmtSemi {
pub(crate) fn new(expr: ast::Expr, semi_token: T![;]) -> Self {
Self { expr, semi_token }
}
pub(crate) fn needs_semi(&self) -> bool {
self.expr.needs_semi()
}
}