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
15impl 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}