rune/ast/
item_fn.rs
1use crate::ast::prelude::*;
2
3#[test]
4#[cfg(not(miri))]
5fn ast_parse() {
6 use crate::parse;
7 use crate::SourceId;
8
9 rt::<ast::ItemFn>("async fn hello() {}");
10 assert!(
11 parse::parse_all::<ast::ItemFn>("fn async hello() {}", SourceId::EMPTY, false).is_err()
12 );
13
14 let item = rt::<ast::ItemFn>("fn hello() {}");
15 assert_eq!(item.args.len(), 0);
16
17 let item = rt::<ast::ItemFn>("fn hello(foo, bar) {}");
18 assert_eq!(item.args.len(), 2);
19
20 rt::<ast::ItemFn>("pub fn hello(foo, bar) {}");
21 rt::<ast::ItemFn>("pub async fn hello(foo, bar) {}");
22 rt::<ast::ItemFn>("#[inline] fn hello(foo, bar) {}");
23
24 let item = rt::<ast::ItemFn>("#[inline] pub async fn hello(foo, bar) {}");
25 assert!(matches!(item.visibility, ast::Visibility::Public(..)));
26
27 assert_eq!(item.args.len(), 2);
28 assert_eq!(item.attributes.len(), 1);
29 assert!(item.async_token.is_some());
30 assert!(item.const_token.is_none());
31
32 let item = rt::<ast::ItemFn>("#[inline] pub const fn hello(foo, bar) {}");
33 assert!(matches!(item.visibility, ast::Visibility::Public(..)));
34
35 assert_eq!(item.args.len(), 2);
36 assert_eq!(item.attributes.len(), 1);
37 assert!(item.async_token.is_none());
38 assert!(item.const_token.is_some());
39
40 let item_with_type = rt::<ast::ItemFn>("pub async fn hello(foo, bar) -> Type {}");
41 assert!(item_with_type.output.is_some());
42}
43
44#[derive(Debug, TryClone, PartialEq, Eq, Parse, ToTokens, Spanned)]
46#[rune(parse = "meta_only")]
47#[non_exhaustive]
48pub struct ItemFn {
49 #[rune(iter, meta)]
51 pub attributes: Vec<ast::Attribute>,
52 #[rune(option, meta)]
54 pub visibility: ast::Visibility,
55 #[rune(iter, meta)]
57 pub const_token: Option<T![const]>,
58 #[rune(iter, meta)]
60 pub async_token: Option<T![async]>,
61 pub fn_token: T![fn],
63 pub name: ast::Ident,
65 pub args: ast::Parenthesized<ast::FnArg, T![,]>,
67 #[rune(option)]
69 pub output: Option<(T![->], ast::Type)>,
70 pub body: ast::Block,
72 #[rune(skip)]
74 pub(crate) id: ItemId,
75}
76
77impl ItemFn {
78 pub(crate) fn descriptive_span(&self) -> Span {
81 if let Some(async_token) = &self.async_token {
82 async_token.span().join(self.args.span())
83 } else {
84 self.fn_token.span().join(self.args.span())
85 }
86 }
87
88 pub(crate) fn is_instance(&self) -> bool {
90 matches!(self.args.first(), Some((ast::FnArg::SelfValue(..), _)))
91 }
92}
93
94item_parse!(Fn, ItemFn, "function item");
95
96impl Peek for ItemFn {
97 fn peek(p: &mut Peeker<'_>) -> bool {
98 match (p.nth(0), p.nth(1)) {
99 (K![fn], _) => true,
100 (K![async], K![fn]) => true,
101 (K![const], K![fn]) => true,
102 _ => false,
103 }
104 }
105}