q_num/
parse.rs

1use proc_macro2::Span;
2use syn::parse;
3use syn::parse::{Parse, ParseStream};
4use syn::{Ident, LitInt, Token, Visibility};
5
6pub struct Input {
7    #[allow(dead_code)]
8    pub visibility: Option<Visibility>,
9    pub name: Ident,
10    pub signed: bool,
11    pub int_bits: u8,
12    pub frac_bits: u8,
13}
14
15/// Parses, for example:
16/// - `define_q_num!(MyNum, Q10.4)'
17/// - `define_q_num!(pub MyNum, UQ10.4)'
18///
19/// "UQ" -> signed = false
20/// "Q" -> signed = true
21impl Parse for Input {
22    fn parse(input: ParseStream) -> parse::Result<Self> {
23        let visibility = if input.peek(Token![pub]) {
24            Some(input.parse()?)
25        } else {
26            None
27        };
28        let name: Ident = input.parse()?;
29        input.parse::<Token![,]>()?;
30        let next_token = input.parse::<Ident>()?.to_string();
31        let (signed, int_bits) = if next_token.starts_with("UQ") {
32            let rest = next_token.strip_prefix("UQ").unwrap();
33            (false, parse_int_bits(rest)?)
34        } else if next_token.starts_with('Q') {
35            let rest = next_token.strip_prefix('Q').unwrap();
36            (true, parse_int_bits(rest)?)
37        } else {
38            return Err(parse::Error::new(Span::call_site(), "Expected UQ or Q"));
39        };
40        input.parse::<Token![.]>()?;
41        let frac_bits = input.parse::<LitInt>()?.base10_parse()?;
42        Ok(Input {
43            visibility,
44            name,
45            signed,
46            int_bits,
47            frac_bits,
48        })
49    }
50}
51
52fn parse_int_bits(input: &str) -> Result<u8, parse::Error> {
53    match input.parse() {
54        Ok(x) => Ok(x),
55        Err(_) => Err(parse::Error::new(Span::call_site(), "Expected integer")),
56    }
57}
58
59#[cfg(test)]
60mod tests {
61    use super::parse_int_bits;
62
63    #[test]
64    fn test_parse_int_bits_1() {
65        let x = parse_int_bits("10");
66        assert!(x.is_ok());
67    }
68
69    #[test]
70    fn test_parse_int_bits_2() {
71        let x = parse_int_bits("31x");
72        assert!(x.is_err());
73    }
74}