as_derive_utils/
parse_utils.rs

1use crate::utils::SynErrorExt;
2
3use syn::parse::{Parse, ParseBuffer, Peek};
4
5#[doc(hidden)]
6#[macro_export]
7macro_rules! ret_err_on_peek {
8    ($input:ident, $peeked:expr, $expected:expr, $found_msg:expr $(,)*) => {
9        if $input.peek($peeked) {
10            return Err($input.error(concat!("expected ", $expected, ", found ", $found_msg)));
11        }
12    };
13}
14
15#[doc(hidden)]
16#[macro_export]
17macro_rules! ret_err_on {
18    ($cond:expr, $span:expr, $expected:expr, $found_msg:expr $(,)*) => {
19        if $cond {
20            return Err(syn::Error::new(
21                $span,
22                concat!("expected ", $expected, ", found ", $found_msg),
23            ));
24        }
25    };
26}
27
28pub use crate::{ret_err_on, ret_err_on_peek};
29
30fn parse_with_prefix_err<T>(input: &ParseBuffer<'_>, prefix: &str) -> Result<T, syn::Error>
31where
32    T: Parse,
33{
34    input
35        .parse::<T>()
36        .map_err(|e| e.prepend_msg(format!("{}: ", prefix)))
37}
38
39pub trait ParseBufferExt {
40    fn as_pb(&self) -> &ParseBuffer<'_>;
41
42    fn peek_parse<F, X, P>(&self, f: F) -> Result<Option<P>, syn::Error>
43    where
44        F: FnOnce(X) -> P + Peek,
45        P: Parse,
46    {
47        let this = self.as_pb();
48        if this.peek(f) {
49            this.parse::<P>().map(Some)
50        } else {
51            Ok(None)
52        }
53    }
54
55    /// Alternate method for parsing a type, with a better (?) error message.
56    fn parse_type(&self) -> Result<syn::Type, syn::Error> {
57        let input = self.as_pb();
58
59        if input.peek(syn::Lit) {
60            Err(input.error("expected type, found literal"))
61        } else {
62            parse_with_prefix_err(input, "while parsing type")
63        }
64    }
65
66    /// Alternate method for parsing an expression, with a better (?) error message.
67    fn parse_expr(&self) -> Result<syn::Expr, syn::Error> {
68        parse_with_prefix_err(self.as_pb(), "while parsing expression")
69    }
70
71    /// skips a token tree.
72    fn skip_tt(&self) {
73        let _ = self.as_pb().parse::<proc_macro2::TokenTree>();
74    }
75
76    /// Ignores the rest of the parse input
77    fn ignore_rest(&self) {
78        let _ = self.as_pb().parse::<proc_macro2::TokenStream>();
79    }
80
81    /// Checks that a token is parsable, advancing the parse buffer if it is.
82    ///
83    /// This returns:
84    /// - Ok(true): if the token was the passed in one, advancing the parser.
85    /// - Ok(false): if the token was not passed in one, keeping the token unparsed.
86    /// - Err: if there was an error parsing the token
87    fn check_parse<F, X, P>(&self, f: F) -> Result<bool, syn::Error>
88    where
89        F: FnOnce(X) -> P + Peek,
90        P: Parse,
91    {
92        let this = self.as_pb();
93        if this.peek(f) {
94            match this.parse::<P>() {
95                Ok(_) => Ok(true),
96                Err(e) => Err(e),
97            }
98        } else {
99            Ok(false)
100        }
101    }
102
103    fn parse_paren_buffer(&self) -> Result<ParseBuffer, syn::Error> {
104        let content;
105        let _ = syn::parenthesized!(content in self.as_pb());
106        Ok(content)
107    }
108
109    fn parse_paren_as<T>(&self) -> Result<T, syn::Error>
110    where
111        T: Parse,
112    {
113        self.as_pb().parse_paren_with(|x| x.parse::<T>())
114    }
115
116    fn parse_paren_with<T, F>(&self, f: F) -> Result<T, syn::Error>
117    where
118        F: FnOnce(&ParseBuffer<'_>) -> Result<T, syn::Error>,
119    {
120        let content;
121        let _ = syn::parenthesized!(content in self.as_pb());
122        f(&content)
123    }
124
125    fn parse_int<N>(&self) -> Result<N, syn::Error>
126    where
127        N: std::str::FromStr,
128        N::Err: std::fmt::Display,
129    {
130        self.as_pb().parse::<syn::LitInt>()?.base10_parse::<N>()
131    }
132
133    fn for_each_separated<F, G, P>(&self, _sep: G, mut func: F) -> Result<(), syn::Error>
134    where
135        F: FnMut(&ParseBuffer<'_>) -> Result<(), syn::Error>,
136        G: Fn(proc_macro2::Span) -> P + Copy,
137        P: Parse,
138    {
139        let this = self.as_pb();
140
141        if this.is_empty() {
142            return Ok(());
143        }
144
145        loop {
146            func(this)?;
147
148            if !this.is_empty() {
149                let _ = this.parse::<P>()?;
150            }
151            if this.is_empty() {
152                break Ok(());
153            }
154        }
155    }
156}
157
158impl ParseBufferExt for ParseBuffer<'_> {
159    #[inline(always)]
160    fn as_pb(&self) -> &ParseBuffer<'_> {
161        self
162    }
163}