paramdex_rs/deserialize/
field_def_parse.rs

1use std::str::FromStr;
2use pest_derive::Parser;
3
4#[derive(Parser)]
5#[grammar = "deserialize/fielddef.pest"]
6struct DefParser;
7
8use pest::iterators::Pairs;
9use pest::{Parser, Span};
10use crate::{ParamFieldDef, ParamFieldType};
11
12fn tokenize(input: &str) -> Result<Pairs<Rule>, DefParseError> {
13    DefParser::parse(Rule::def, input.as_ref()).map_err(|a| a.into())
14}
15
16#[derive(Debug)]
17pub struct ErrSpan {
18    pub start: usize,
19    pub end: usize,
20}
21
22#[derive(Error, Debug)]
23pub enum DefParseError {
24    #[error("Failed to parse def line")]
25    ParseError(#[from] pest::error::Error<Rule>),
26
27    #[error("Bit size not supported on this type")]
28    BitSizeUnsupported(ErrSpan),
29}
30
31use thiserror::Error;
32
33pub fn parse_param_field_def<S: AsRef<str>>(input_str: S) -> Result<ParamFieldDef, DefParseError> {
34    let tokenized = tokenize(input_str.as_ref())?.next().expect("First pair");
35    if let Rule::def = tokenized.as_rule() {
36        let inner = tokenized.into_inner().next().expect("def type pair");
37        match inner.as_rule() {
38            Rule::def_simple => {
39                let mut inner = inner.into_inner();
40                let simple_field_type = inner.next().expect("getting simple field type");
41
42                let field_type = match simple_field_type.as_str() {
43                    "s8" => ParamFieldType::s8,
44                    "u8" => ParamFieldType::u8 { bit_size: None },
45                    "s16" => ParamFieldType::s16,
46                    "u16" => ParamFieldType::u16 { bit_size: None },
47                    "s32" => ParamFieldType::s32,
48                    "u32" => ParamFieldType::u32 { bit_size: None },
49                    "f32" => ParamFieldType::f32,
50                    "f64" => ParamFieldType::f64,
51                    "a32" | "angle32" => ParamFieldType::a32,
52                    "b32" => ParamFieldType::b32,
53                    _ => unreachable!()
54                };
55
56                let field_name = {
57                    let inner = inner.next().expect("getting field name");
58                    inner.as_str().to_owned()
59                };
60                let mut compiled_field_def = ParamFieldDef {
61                    field_type,
62                    name: field_name,
63                    default_value: None,
64                };
65
66                for suffix in inner {
67                    match suffix.as_rule() {
68                        Rule::suffix_bitsize => {
69                            let span = suffix.as_span();
70                            let number = suffix.into_inner().next().expect("number");
71                            let bit_size = u8::from_str(number.as_str()).expect("number_str to u8");
72                            if compiled_field_def.field_type.supports_bit_size() {
73                                compiled_field_def.field_type.set_bit_size(bit_size);
74                            } else {
75                                return Err(DefParseError::BitSizeUnsupported(span.into()).into());
76                            }
77                        }
78                        Rule::def_default_suffix => {
79                            let default_inner = suffix.into_inner().next().expect("default inner");
80                            let default_val = f64::from_str(default_inner.as_str()).expect("default str to f64");
81                            compiled_field_def.default_value.replace(default_val);
82                        }
83                        _ => unreachable!()
84                    }
85                }
86                Ok(compiled_field_def)
87            }
88            Rule::def_dummy => {
89                unimplemented!()
90            }
91            _ => {
92                unimplemented!()
93            }
94        }
95    } else {
96        unreachable!()
97    }
98}
99
100impl<'i> From<Span<'i>> for ErrSpan {
101    fn from(span: Span<'i>) -> Self {
102        ErrSpan { start: span.start(), end: span.end() }
103    }
104}
105
106#[cfg(test)]
107mod tests {
108    use std::collections::HashMap;
109    use std::fs::{File};
110    use std::io::{BufReader, Read};
111    use crate::{ParamFieldDef, ParamFieldType};
112    use crate::deserialize::field_def_parse::parse_param_field_def;
113
114    impl PartialEq for ParamFieldDef {
115        fn eq(&self, other: &Self) -> bool {
116            self.field_type == other.field_type && self.default_value == other.default_value && self.name == other.name
117        }
118    }
119
120    #[test]
121    fn simple() {
122        assert_eq!(
123            parse_param_field_def("u32 testingVar").expect("parses"),
124            ParamFieldDef {
125                name: "testingVar".to_string(),
126                default_value: None,
127                field_type: ParamFieldType::u32 { bit_size: None },
128            }
129        )
130    }
131
132    #[test]
133    fn simple_s() {
134        assert_eq!(
135            parse_param_field_def("s32 testingVar2").expect("parses"),
136            ParamFieldDef {
137                name: "testingVar2".to_string(),
138                default_value: None,
139                field_type: ParamFieldType::s32,
140            }
141        )
142    }
143
144    #[test]
145    fn simple_f() {
146        assert_eq!(
147            parse_param_field_def("f32 gradFactor").expect("parses"),
148            ParamFieldDef {
149                name: "gradFactor".to_string(),
150                default_value: None,
151                field_type: ParamFieldType::f32,
152            }
153        )
154    }
155
156    #[test]
157    fn simple_bitsize() {
158        assert_eq!(
159            parse_param_field_def("u32 testingVar:3").expect("parses"),
160            ParamFieldDef {
161                name: "testingVar".to_string(),
162                default_value: None,
163                field_type: ParamFieldType::u32 { bit_size: Some(3) },
164            }
165        )
166    }
167
168    #[test]
169    #[should_panic]
170    fn simple_bitsize_s() {
171        parse_param_field_def("s32 testingVar:3").expect("parses");
172    }
173
174    #[test]
175    fn simple_default() {
176        assert_eq!(
177            parse_param_field_def("u32 testingVar = -3.0").expect("parses"),
178            ParamFieldDef {
179                name: "testingVar".to_string(),
180                default_value: Some(-3.0),
181                field_type: ParamFieldType::u32 { bit_size: None },
182            }
183        )
184    }
185
186    #[test]
187    fn simple_default_s() {
188        assert_eq!(
189            parse_param_field_def("s32 testingVar3 = -3.0").expect("parses"),
190            ParamFieldDef {
191                name: "testingVar3".to_string(),
192                default_value: Some(-3.0),
193                field_type: ParamFieldType::s32,
194            }
195        )
196    }
197
198    #[test]
199    fn simple_default_bitsize() {
200        assert_eq!(
201            parse_param_field_def("u32 testingVar:3 = 0").expect("parses"),
202            ParamFieldDef {
203                name: "testingVar".to_string(),
204                default_value: Some(0.0),
205                field_type: ParamFieldType::u32 { bit_size: Some(3) },
206            }
207        )
208    }
209
210    #[test]
211    #[should_panic]
212    fn simple_default_bitsize_s() {
213        parse_param_field_def("s32 testingVar:3 = 0").expect("parses");
214    }
215
216    #[test]
217    fn test_all_xmls() {
218        let mut errors = HashMap::new();
219        let walkdir = walkdir::WalkDir::new("Paramdex/ER")
220            .into_iter()
221            .filter_map(|a| a.ok())
222            .filter(|a| a.file_type().is_file())
223            .map(|a| a.into_path())
224            .filter(|a| a.extension().map(|a| a == "xml").unwrap_or(false));
225        for a in walkdir {
226            let path = a.to_str().expect("tostr");
227            let string =
228                {
229                    let mut string = String::with_capacity(25000);
230                    BufReader::new(File::open(&a).expect("opening file"))
231                        .read_to_string(&mut string).expect("reading file");
232                    string
233                };
234            let doc = roxmltree::Document::parse(string.as_str()).expect("parsing xml");
235            for def_str in doc.descendants().filter(|a| a.has_tag_name("Field")).map(|a| a.attribute("Def").expect("def")) {
236                if !(def_str.contains("fixstr") || def_str.contains("dummy")) {
237                    match parse_param_field_def(def_str) {
238                        Err(_err) => {
239                            if !errors.contains_key(path) {
240                                errors.insert(path.to_owned(), Vec::new());
241                            }
242                            errors.get_mut(path).expect("wewe").push(def_str.to_owned());
243                        },
244                        _ => {}
245                    }
246
247                } else if def_str.contains("fixstrW") {
248                    // println!("{}", path);
249                }
250            }
251        }
252
253        for (k,v) in errors {
254            println!("{}", k);
255            for def in v {
256                println!("\t{}", def);
257            }
258        }
259
260    }
261}