blend/parsers/
field.rs

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}