1use nom::{
2 branch::alt,
3 bytes::complete::{tag, take_till, take_until},
4 combinator::complete,
5 error::{ErrorKind, ParseError},
6 multi::{many0, many1},
7 sequence::delimited,
8 Err, IResult,
9};
10
11#[derive(Debug)]
12pub enum FieldParseError {
13 NomError {
14 kind: ErrorKind,
15 other: Option<Box<FieldParseError>>,
16 },
17 InvalidArraySize,
18}
19
20impl ParseError<&str> for FieldParseError {
21 fn from_error_kind(_input: &str, kind: ErrorKind) -> Self {
22 FieldParseError::NomError { kind, other: None }
23 }
24
25 fn append(_input: &str, kind: ErrorKind, other: Self) -> Self {
26 FieldParseError::NomError {
27 kind,
28 other: Some(Box::new(other)),
29 }
30 }
31}
32
33type Result<'a, T> = IResult<&'a str, T, FieldParseError>;
34
35#[derive(Debug, Clone)]
36pub enum FieldInfo {
37 Value,
38 ValueArray {
39 len: usize,
40 dimensions: Vec<usize>,
41 },
42 Pointer {
43 indirection_count: usize,
44 },
45 PointerArray {
46 indirection_count: usize,
47 len: usize,
48 dimensions: Vec<usize>,
49 },
50 FnPointer,
51}
52
53pub fn fn_pointer(input: &str) -> Result<(&str, FieldInfo)> {
54 let (input, name) = delimited(tag("(*"), take_until(")"), tag(")"))(input)?;
55
56 let (input, _) = delimited(tag("("), take_until(")"), tag(")"))(input)?;
57
58 Ok((input, (name, FieldInfo::FnPointer)))
59}
60
61fn array_dimensions(input: &str) -> Result<Vec<usize>> {
62 let (input, array_dimensions) =
63 many0(complete(delimited(tag("["), take_until("]"), tag("]"))))(input)?;
64
65 let mut dimensions_len = Vec::new();
66 for dimension_str in array_dimensions {
67 dimensions_len.push(
68 dimension_str
69 .parse::<usize>()
70 .map_err(|_| Err::Failure(FieldParseError::InvalidArraySize))?,
71 );
72 }
73
74 Ok((input, dimensions_len))
75}
76
77fn pointer(input: &str) -> Result<(&str, FieldInfo)> {
78 let (input, asterisks) = many1(tag("*"))(input)?;
79 let (input, name) = take_till(|c| c == '[')(input)?;
80
81 if !input.is_empty() {
82 let (input, dimensions) = array_dimensions(input)?;
83 let len = dimensions.iter().product();
84 Ok((
85 input,
86 (
87 name,
88 FieldInfo::PointerArray {
89 indirection_count: asterisks.len(),
90 len,
91 dimensions,
92 },
93 ),
94 ))
95 } else {
96 Ok((
97 input,
98 (
99 name,
100 FieldInfo::Pointer {
101 indirection_count: asterisks.len(),
102 },
103 ),
104 ))
105 }
106}
107
108fn value(input: &str) -> Result<(&str, FieldInfo)> {
109 let (input, name) = take_till(|c| c == '[')(input)?;
110 if !input.is_empty() {
111 let (input, dimensions) = array_dimensions(input)?;
112 let len = dimensions.iter().product();
113 Ok((
114 input,
115 (
116 name,
117 FieldInfo::ValueArray {
118 len,
119 dimensions,
120 },
121 ),
122 ))
123 } else {
124 Ok((input, (name, FieldInfo::Value)))
125 }
126}
127
128pub fn parse_field(input: &str) -> Result<(&str, FieldInfo)> {
129 alt((fn_pointer, pointer, value))(input)
130}