requestty_macro/
lib.rs

1//! This crate is the declaration of the [`questions!`] macro. It should not be used directly. Use
2//! [`requestty`] instead.
3//!
4//! [`requestty`]: https://crates.io/crates/requestty
5
6extern crate proc_macro;
7use proc_macro::TokenStream;
8
9#[rustversion::since(1.51)]
10macro_rules! iter {
11    ($span:expr => $($tt:tt)*) => {
12        quote::quote_spanned! { $span => [ $($tt)* ] }
13    };
14}
15#[rustversion::before(1.51)]
16macro_rules! iter {
17    ($span:expr => $($tt:tt)*) => {
18        quote::quote_spanned! { $span => ::std::vec![ $($tt)* ] }
19    };
20}
21
22mod helpers;
23mod question;
24
25use question::*;
26use syn::{parse::Parse, parse_macro_input, Token};
27
28#[proc_macro]
29pub fn questions(item: TokenStream) -> TokenStream {
30    let p = parse_macro_input!(item as Questions);
31
32    let questions = p.questions.into_iter();
33
34    if p.inline {
35        iter! { proc_macro2::Span::call_site() => #(#questions),* }
36    } else {
37        quote::quote! { ::std::vec![ #(#questions),* ] }
38    }
39    .into()
40}
41
42struct Questions {
43    inline: bool,
44    questions: syn::punctuated::Punctuated<Question, Token![,]>,
45}
46
47impl Parse for Questions {
48    fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
49        let inline = input
50            .step(|c| match c.ident() {
51                Some((ident, c)) if ident == "inline" => Ok(((), c)),
52                _ => Err(c.error("no inline")),
53            })
54            .is_ok();
55
56        Ok(Self {
57            inline,
58            questions: input.parse_terminated(Question::parse, Token![,])?,
59        })
60    }
61}