rune/ast/
expr_closure.rs
1use crate::ast::prelude::*;
2
3#[test]
4#[cfg(not(miri))]
5fn ast_parse() {
6 rt::<ast::ExprClosure>("async || 42");
7 rt::<ast::ExprClosure>("|| 42");
8 rt::<ast::ExprClosure>("|| { 42 }");
9 rt::<ast::ExprClosure>("move || { 42 }");
10 rt::<ast::ExprClosure>("async move || { 42 }");
11
12 let expr = rt::<ast::ExprClosure>("#[retry(n=3)] || 43");
13 assert_eq!(expr.attributes.len(), 1);
14
15 let expr = rt::<ast::ExprClosure>("#[retry(n=3)] async || 43");
16 assert_eq!(expr.attributes.len(), 1);
17}
18
19#[derive(Debug, TryClone, PartialEq, Eq, Parse, ToTokens, Spanned)]
24#[rune(parse = "meta_only")]
25#[non_exhaustive]
26pub struct ExprClosure {
27 #[rune(iter, meta)]
29 pub attributes: Vec<ast::Attribute>,
30 #[rune(iter, meta)]
32 pub async_token: Option<T![async]>,
33 #[rune(iter, meta)]
35 pub move_token: Option<T![move]>,
36 pub args: ExprClosureArgs,
38 pub body: Box<ast::Expr>,
40 #[rune(skip)]
42 pub(crate) id: ItemId,
43}
44
45impl ExprClosure {
46 pub fn item_span(&self) -> Span {
48 if let Some(async_) = &self.async_token {
49 async_.span().join(self.args.span())
50 } else {
51 self.args.span()
52 }
53 }
54}
55
56expr_parse!(Closure, ExprClosure, "closure expression");
57
58#[derive(Debug, TryClone, PartialEq, Eq, ToTokens)]
60#[non_exhaustive]
61pub enum ExprClosureArgs {
62 Empty {
64 token: T![||],
66 },
67 List {
69 open: T![|],
71 args: Vec<(ast::FnArg, Option<T![,]>)>,
73 close: T![|],
75 },
76}
77
78impl ExprClosureArgs {
79 pub(crate) fn as_slice(&self) -> &[(ast::FnArg, Option<T![,]>)] {
81 match self {
82 Self::Empty { .. } => &[],
83 Self::List { args, .. } => &args[..],
84 }
85 }
86
87 pub(crate) fn as_slice_mut(&mut self) -> &mut [(ast::FnArg, Option<T![,]>)] {
89 match self {
90 Self::Empty { .. } => &mut [],
91 Self::List { args, .. } => &mut args[..],
92 }
93 }
94}
95
96impl Parse for ExprClosureArgs {
97 fn parse(p: &mut Parser<'_>) -> Result<Self> {
98 if let Some(token) = p.parse::<Option<T![||]>>()? {
99 return Ok(ExprClosureArgs::Empty { token });
100 }
101
102 let open = p.parse()?;
103 let mut args = Vec::new();
104
105 while !p.peek::<T![|]>()? {
106 let arg = p.parse()?;
107
108 let comma = p.parse::<Option<T![,]>>()?;
109 let is_end = comma.is_none();
110 args.try_push((arg, comma))?;
111
112 if is_end {
113 break;
114 }
115 }
116
117 Ok(ExprClosureArgs::List {
118 open,
119 args,
120 close: p.parse()?,
121 })
122 }
123}
124
125impl Spanned for ExprClosureArgs {
126 fn span(&self) -> Span {
127 match self {
128 Self::Empty { token } => token.span(),
129 Self::List { open, close, .. } => open.span().join(close.span()),
130 }
131 }
132}