molecule_codegen/parser/
mod.rs

1use std::path::Path;
2
3use crate::{ast, utils::ParserUtils as _};
4
5mod inner;
6pub(crate) use inner::{Parser as InnerParser, Rule};
7
8pub struct Parser;
9
10impl Parser {
11    pub fn parse<P: AsRef<Path>>(path: &P) -> ast::Ast {
12        let ast_raw = Self::preprocess(path).unwrap();
13        ast::Ast::complete(ast_raw)
14    }
15}
16
17#[cfg(test)]
18mod tests {
19    use crate::ast::{HasName, TopDecl};
20    use crate::*;
21    use std::io::Write;
22
23    #[test]
24    fn test_parse_custom_union_id() {
25        let mut schema_file = tempfile::NamedTempFile::new().unwrap();
26        schema_file
27            .write_all(
28                b"
29array a0  [byte;1];
30array a1  [byte;1];
31array a2  [byte;1];
32array a3  [byte;1];
33array a4  [byte;1];
34
35union UnionWithoutCustomId {
36    a0,
37    a1,
38    a2,
39    a3,
40}
41
42union UninoWithFullContinuousCustomIdFrom0 {
43    a0 : 0,
44    a1 : 1,
45    a2 : 2,
46    a3 : 3,
47}
48
49union UninoWithFullContinuousCustomIdFrom5 {
50    a0 : 5,
51    a1 : 6,
52    a2 : 7,
53    a3 : 8,
54}
55
56union UninoWithFullDiscontinuousCustomId {
57    a0 : 2,
58    a1 : 3,
59    a2 : 7,
60    a3 : 8,
61}
62
63union UninoWithPartialCustomId_0 {
64    a0 : 3,
65    a1,
66    a2,
67    a3,
68}
69
70union UninoWithPartialCustomId_1 {
71    a0,
72    a1 : 3,
73    a2,
74    a3,
75}
76
77union UninoWithPartialCustomId_2 {
78    a0 : 3,
79    a1,
80    a2 : 5,
81    a3,
82}
83
84union UninoWithPartialCustomId_Reverse {
85    a0 : 5,
86    a1,
87    a2 : 3,
88    a3,
89}
90
91
92",
93            )
94            .unwrap();
95        schema_file.flush().unwrap();
96
97        let ast = Parser::parse(&schema_file.into_temp_path());
98        ast.decls().iter().for_each(|decl| {
99            if let TopDecl::Union(union) = decl.as_ref() {
100                match union.name() {
101                    "UnionWithoutCustomId" => {
102                        assert_eq!(union.items().len(), 4);
103                        for union_item_decl in union.items() {
104                            match union_item_decl.typ().name() {
105                                "a0" => assert_eq!(union_item_decl.id(), 0),
106                                "a1" => assert_eq!(union_item_decl.id(), 1),
107                                "a2" => assert_eq!(union_item_decl.id(), 2),
108                                "a3" => assert_eq!(union_item_decl.id(), 3),
109                                _ => unreachable!(),
110                            }
111                        }
112                    }
113                    "UninoWithFullContinuousCustomIdFrom0" => {
114                        assert_eq!(union.items().len(), 4);
115                        for union_item_decl in union.items() {
116                            match union_item_decl.typ().name() {
117                                "a0" => assert_eq!(union_item_decl.id(), 0),
118                                "a1" => assert_eq!(union_item_decl.id(), 1),
119                                "a2" => assert_eq!(union_item_decl.id(), 2),
120                                "a3" => assert_eq!(union_item_decl.id(), 3),
121                                _ => unreachable!(),
122                            }
123                        }
124                    }
125                    "UninoWithFullContinuousCustomIdFrom5" => {
126                        assert_eq!(union.items().len(), 4);
127                        for union_item_decl in union.items() {
128                            match union_item_decl.typ().name() {
129                                "a0" => assert_eq!(union_item_decl.id(), 5),
130                                "a1" => assert_eq!(union_item_decl.id(), 6),
131                                "a2" => assert_eq!(union_item_decl.id(), 7),
132                                "a3" => assert_eq!(union_item_decl.id(), 8),
133                                _ => unreachable!(),
134                            }
135                        }
136                    }
137                    "UninoWithFullDiscontinuousCustomId" => {
138                        assert_eq!(union.items().len(), 4);
139                        for union_item_decl in union.items() {
140                            match union_item_decl.typ().name() {
141                                "a0" => assert_eq!(union_item_decl.id(), 2),
142                                "a1" => assert_eq!(union_item_decl.id(), 3),
143                                "a2" => assert_eq!(union_item_decl.id(), 7),
144                                "a3" => assert_eq!(union_item_decl.id(), 8),
145                                _ => unreachable!(),
146                            }
147                        }
148                    }
149                    "UninoWithPartialCustomId_0" => {
150                        assert_eq!(union.items().len(), 4);
151                        for union_item_decl in union.items() {
152                            match union_item_decl.typ().name() {
153                                "a0" => assert_eq!(union_item_decl.id(), 3),
154                                "a1" => assert_eq!(union_item_decl.id(), 4),
155                                "a2" => assert_eq!(union_item_decl.id(), 5),
156                                "a3" => assert_eq!(union_item_decl.id(), 6),
157                                _ => unreachable!(),
158                            }
159                        }
160                    }
161                    "UninoWithPartialCustomId_1" => {
162                        assert_eq!(union.items().len(), 4);
163                        for union_item_decl in union.items() {
164                            match union_item_decl.typ().name() {
165                                "a0" => assert_eq!(union_item_decl.id(), 0),
166                                "a1" => assert_eq!(union_item_decl.id(), 3),
167                                "a2" => assert_eq!(union_item_decl.id(), 4),
168                                "a3" => assert_eq!(union_item_decl.id(), 5),
169                                _ => unreachable!(),
170                            }
171                        }
172                    }
173                    "UninoWithPartialCustomId_2" => {
174                        assert_eq!(union.items().len(), 4);
175                        for union_item_decl in union.items() {
176                            match union_item_decl.typ().name() {
177                                "a0" => assert_eq!(union_item_decl.id(), 3),
178                                "a1" => assert_eq!(union_item_decl.id(), 4),
179                                "a2" => assert_eq!(union_item_decl.id(), 5),
180                                "a3" => assert_eq!(union_item_decl.id(), 6),
181                                _ => unreachable!(),
182                            }
183                        }
184                    }
185                    "UninoWithPartialCustomId_Reverse" => {
186                        assert_eq!(union.items().len(), 4);
187                        for union_item_decl in union.items() {
188                            match union_item_decl.typ().name() {
189                                "a0" => assert_eq!(union_item_decl.id(), 5),
190                                "a1" => assert_eq!(union_item_decl.id(), 6),
191                                "a2" => assert_eq!(union_item_decl.id(), 3),
192                                "a3" => assert_eq!(union_item_decl.id(), 4),
193                                _ => unreachable!(),
194                            }
195                        }
196                    }
197
198                    _ => unreachable!(),
199                }
200            }
201        });
202    }
203
204    #[test]
205    fn test_union_items_should_ordered_by_custom_id() {
206        let mut schema_file0 = tempfile::NamedTempFile::new().unwrap();
207        schema_file0
208            .write_all(
209                b"
210array a0  [byte;1];
211array a1  [byte;2];
212array a2  [byte;3];
213array a3  [byte;4];
214union Foo {
215    a0 : 1,
216    a1,
217    a2 : 10,
218    a3,
219}
220",
221            )
222            .unwrap();
223
224        schema_file0.flush().unwrap();
225
226        let mut schema_file1 = tempfile::NamedTempFile::new().unwrap();
227        schema_file1
228            .write_all(
229                b"
230array a0  [byte;1];
231array a1  [byte;2];
232array a2  [byte;3];
233array a3  [byte;4];
234union Foo {
235    a2 : 10,
236    a3,
237    a0 : 1,
238    a1,
239}
240",
241            )
242            .unwrap();
243
244        schema_file1.flush().unwrap();
245
246        let ast0 = Parser::parse(&schema_file0.into_temp_path());
247        let ast1 = Parser::parse(&schema_file1.into_temp_path());
248
249        for ast in [ast0, ast1] {
250            // get union items
251            if let TopDecl::Union(union) = ast
252                .decls()
253                .iter()
254                .find(|decl| decl.name() == "Foo")
255                .unwrap()
256                .as_ref()
257            {
258                let custom_ids: Vec<usize> = union.items().iter().map(|item| item.id()).collect();
259                assert_eq!(custom_ids, vec![1, 2, 10, 11]);
260            }
261        }
262    }
263
264    #[should_panic]
265    #[test]
266    fn test_bad_explicit_duplicate_union_schema() {
267        let mut schema_file = tempfile::NamedTempFile::new().unwrap();
268        schema_file
269            .write_all(
270                b"
271array a0  [byte;1];
272array a1  [byte;1];
273array a2  [byte;1];
274array a3  [byte;1];
275union UninoWithPartialDuplicateCustomId {
276    a0,
277    a1 : 3,
278    a2 : 3,
279    a3,
280}
281",
282            )
283            .unwrap();
284
285        schema_file.flush().unwrap();
286
287        let _should_panic = Parser::parse(&schema_file.into_temp_path());
288    }
289
290    #[should_panic]
291    #[test]
292    fn test_bad_implicit_duplicate_union_schema() {
293        let mut schema_file = tempfile::NamedTempFile::new().unwrap();
294        schema_file
295            .write_all(
296                b"
297array a0  [byte;1];
298array a1  [byte;1];
299array a2  [byte;1];
300array a3  [byte;1];
301array a4  [byte;1];
302
303union UninoWithPartialDuplicateCustomIdInReverseOrder {
304    a0 : 10,
305    a1,
306    a2,
307    a3 : 11,
308    a4,
309}
310",
311            )
312            .unwrap();
313
314        schema_file.flush().unwrap();
315
316        let _should_panic = Parser::parse(&schema_file.into_temp_path());
317    }
318}