1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
use nom::{
    branch::alt,
    bytes::complete::{tag, take_till, take_until},
    combinator::complete,
    error::{ErrorKind, ParseError},
    multi::{many0, many1},
    sequence::delimited,
    Err, IResult,
};

#[derive(Debug)]
pub enum FieldParseError {
    NomError {
        kind: ErrorKind,
        other: Option<Box<FieldParseError>>,
    },
    InvalidArraySize,
}

impl ParseError<&str> for FieldParseError {
    fn from_error_kind(_input: &str, kind: ErrorKind) -> Self {
        FieldParseError::NomError { kind, other: None }
    }

    fn append(_input: &str, kind: ErrorKind, other: Self) -> Self {
        FieldParseError::NomError {
            kind,
            other: Some(Box::new(other)),
        }
    }
}

type Result<'a, T> = IResult<&'a str, T, FieldParseError>;

#[derive(Debug, Clone)]
pub enum FieldInfo {
    Value,
    ValueArray {
        len: usize,
        dimensions: Vec<usize>,
    },
    Pointer {
        indirection_count: usize,
    },
    PointerArray {
        indirection_count: usize,
        len: usize,
        dimensions: Vec<usize>,
    },
    FnPointer,
}

pub fn fn_pointer(input: &str) -> Result<(&str, FieldInfo)> {
    let (input, name) = delimited(tag("(*"), take_until(")"), tag(")"))(input)?;

    let (input, _) = delimited(tag("("), take_until(")"), tag(")"))(input)?;

    Ok((input, (name, FieldInfo::FnPointer)))
}

fn array_dimensions(input: &str) -> Result<Vec<usize>> {
    let (input, array_dimensions) =
        many0(complete(delimited(tag("["), take_until("]"), tag("]"))))(input)?;

    let mut dimensions_len = Vec::new();
    for dimension_str in array_dimensions {
        dimensions_len.push(
            dimension_str
                .parse::<usize>()
                .map_err(|_| Err::Failure(FieldParseError::InvalidArraySize))?,
        );
    }

    Ok((input, dimensions_len))
}

fn pointer(input: &str) -> Result<(&str, FieldInfo)> {
    let (input, asterisks) = many1(tag("*"))(input)?;
    let (input, name) = take_till(|c| c == '[')(input)?;

    if !input.is_empty() {
        let (input, dimensions) = array_dimensions(input)?;
        let len = dimensions.iter().product();
        Ok((
            input,
            (
                name,
                FieldInfo::PointerArray {
                    indirection_count: asterisks.len(),
                    len,
                    dimensions,
                },
            ),
        ))
    } else {
        Ok((
            input,
            (
                name,
                FieldInfo::Pointer {
                    indirection_count: asterisks.len(),
                },
            ),
        ))
    }
}

fn value(input: &str) -> Result<(&str, FieldInfo)> {
    let (input, name) = take_till(|c| c == '[')(input)?;
    if !input.is_empty() {
        let (input, dimensions) = array_dimensions(input)?;
        let len = dimensions.iter().product();
        Ok((
            input,
            (
                name,
                FieldInfo::ValueArray {
                    len,
                    dimensions,
                },
            ),
        ))
    } else {
        Ok((input, (name, FieldInfo::Value)))
    }
}

pub fn parse_field(input: &str) -> Result<(&str, FieldInfo)> {
    alt((fn_pointer, pointer, value))(input)
}