use crate::ast::prelude::*;
#[test]
#[cfg(not(miri))]
fn ast_parse() {
rt::<ast::ExprClosure>("async || 42");
rt::<ast::ExprClosure>("|| 42");
rt::<ast::ExprClosure>("|| { 42 }");
rt::<ast::ExprClosure>("move || { 42 }");
rt::<ast::ExprClosure>("async move || { 42 }");
let expr = rt::<ast::ExprClosure>("#[retry(n=3)] || 43");
assert_eq!(expr.attributes.len(), 1);
let expr = rt::<ast::ExprClosure>("#[retry(n=3)] async || 43");
assert_eq!(expr.attributes.len(), 1);
}
#[derive(Debug, TryClone, PartialEq, Eq, Parse, ToTokens, Spanned)]
#[rune(parse = "meta_only")]
#[non_exhaustive]
pub struct ExprClosure {
#[rune(iter, meta)]
pub attributes: Vec<ast::Attribute>,
#[rune(iter, meta)]
pub async_token: Option<T![async]>,
#[rune(iter, meta)]
pub move_token: Option<T![move]>,
pub args: ExprClosureArgs,
pub body: Box<ast::Expr>,
#[rune(skip)]
pub(crate) id: ItemId,
}
impl ExprClosure {
pub fn item_span(&self) -> Span {
if let Some(async_) = &self.async_token {
async_.span().join(self.args.span())
} else {
self.args.span()
}
}
}
expr_parse!(Closure, ExprClosure, "closure expression");
#[derive(Debug, TryClone, PartialEq, Eq, ToTokens)]
#[non_exhaustive]
pub enum ExprClosureArgs {
Empty {
token: T![||],
},
List {
open: T![|],
args: Vec<(ast::FnArg, Option<T![,]>)>,
close: T![|],
},
}
impl ExprClosureArgs {
pub(crate) fn as_slice(&self) -> &[(ast::FnArg, Option<T![,]>)] {
match self {
Self::Empty { .. } => &[],
Self::List { args, .. } => &args[..],
}
}
pub(crate) fn as_slice_mut(&mut self) -> &mut [(ast::FnArg, Option<T![,]>)] {
match self {
Self::Empty { .. } => &mut [],
Self::List { args, .. } => &mut args[..],
}
}
}
impl Parse for ExprClosureArgs {
fn parse(p: &mut Parser<'_>) -> Result<Self> {
if let Some(token) = p.parse::<Option<T![||]>>()? {
return Ok(ExprClosureArgs::Empty { token });
}
let open = p.parse()?;
let mut args = Vec::new();
while !p.peek::<T![|]>()? {
let arg = p.parse()?;
let comma = p.parse::<Option<T![,]>>()?;
let is_end = comma.is_none();
args.try_push((arg, comma))?;
if is_end {
break;
}
}
Ok(ExprClosureArgs::List {
open,
args,
close: p.parse()?,
})
}
}
impl Spanned for ExprClosureArgs {
fn span(&self) -> Span {
match self {
Self::Empty { token } => token.span(),
Self::List { open, close, .. } => open.span().join(close.span()),
}
}
}