Skip to main content

aldrin_parser/ast/
struct_def.rs

1use super::{Attribute, Comment, DocString, Ident, LitInt, Prelude, TypeName};
2use crate::Span;
3use crate::error::{
4    DuplicateStructField, DuplicateStructFieldId, InvalidStructFieldId, RecursiveStruct,
5};
6use crate::grammar::Rule;
7use crate::validate::Validate;
8use crate::warning::{BrokenDocLink, NonCamelCaseStruct, NonSnakeCaseStructField};
9use pest::iterators::Pair;
10
11#[derive(Debug, Clone)]
12pub struct StructDef {
13    span: Span,
14    comment: Vec<Comment>,
15    doc: Vec<DocString>,
16    attrs: Vec<Attribute>,
17    name: Ident,
18    fields: Vec<StructField>,
19    fallback: Option<StructFallback>,
20}
21
22impl StructDef {
23    pub(crate) fn parse(pair: Pair<Rule>) -> Self {
24        assert_eq!(pair.as_rule(), Rule::struct_def);
25
26        let span = Span::from_pair(&pair);
27        let mut pairs = pair.into_inner();
28        let mut prelude = Prelude::regular(&mut pairs);
29
30        pairs.next().unwrap(); // Skip keyword.
31
32        let pair = pairs.next().unwrap();
33        let name = Ident::parse(&pair);
34
35        pairs.next().unwrap(); // Skip {.
36
37        let mut fields = Vec::new();
38        let mut fallback = None;
39
40        for pair in pairs {
41            #[expect(clippy::wildcard_enum_match_arm)]
42            match pair.as_rule() {
43                Rule::struct_field => fields.push(StructField::parse(pair)),
44                Rule::struct_fallback => fallback = Some(StructFallback::parse(pair)),
45                Rule::tok_cur_close => break,
46                _ => unreachable!(),
47            }
48        }
49
50        Self {
51            span,
52            comment: prelude.take_comment(),
53            doc: prelude.take_doc(),
54            attrs: prelude.take_attrs(),
55            name,
56            fields,
57            fallback,
58        }
59    }
60
61    pub(crate) fn validate(&self, validate: &mut Validate) {
62        DuplicateStructField::validate(
63            &self.fields,
64            self.fallback.as_ref(),
65            Some(&self.name),
66            validate,
67        );
68
69        BrokenDocLink::validate(&self.doc, validate);
70        DuplicateStructFieldId::validate(&self.fields, Some(&self.name), validate);
71        NonCamelCaseStruct::validate(self, validate);
72        RecursiveStruct::validate(self, validate);
73
74        self.name.validate(true, validate);
75
76        for field in &self.fields {
77            field.validate(validate);
78        }
79
80        if let Some(ref fallback) = self.fallback {
81            fallback.validate(validate);
82        }
83    }
84
85    pub fn span(&self) -> Span {
86        self.span
87    }
88
89    pub fn comment(&self) -> &[Comment] {
90        &self.comment
91    }
92
93    pub fn doc(&self) -> &[DocString] {
94        &self.doc
95    }
96
97    pub fn attributes(&self) -> &[Attribute] {
98        &self.attrs
99    }
100
101    pub fn name(&self) -> &Ident {
102        &self.name
103    }
104
105    pub fn fields(&self) -> &[StructField] {
106        &self.fields
107    }
108
109    pub fn fallback(&self) -> Option<&StructFallback> {
110        self.fallback.as_ref()
111    }
112}
113
114#[derive(Debug, Clone)]
115pub struct InlineStruct {
116    span: Span,
117    kw_span: Span,
118    doc: Vec<DocString>,
119    attrs: Vec<Attribute>,
120    fields: Vec<StructField>,
121    fallback: Option<StructFallback>,
122}
123
124impl InlineStruct {
125    pub(crate) fn parse(pair: Pair<Rule>) -> Self {
126        assert_eq!(pair.as_rule(), Rule::struct_inline);
127
128        let span = Span::from_pair(&pair);
129        let mut pairs = pair.into_inner();
130
131        let pair = pairs.next().unwrap();
132        let kw_span = Span::from_pair(&pair);
133
134        pairs.next().unwrap(); // Skip {.
135
136        let mut prelude = Prelude::inline(&mut pairs);
137        let mut fields = Vec::new();
138        let mut fallback = None;
139
140        for pair in pairs {
141            #[expect(clippy::wildcard_enum_match_arm)]
142            match pair.as_rule() {
143                Rule::struct_field => fields.push(StructField::parse(pair)),
144                Rule::struct_fallback => fallback = Some(StructFallback::parse(pair)),
145                Rule::tok_cur_close => break,
146                _ => unreachable!(),
147            }
148        }
149
150        Self {
151            span,
152            kw_span,
153            doc: prelude.take_doc(),
154            attrs: prelude.take_attrs(),
155            fields,
156            fallback,
157        }
158    }
159
160    pub(crate) fn validate(&self, validate: &mut Validate) {
161        BrokenDocLink::validate(&self.doc, validate);
162        DuplicateStructField::validate(&self.fields, self.fallback.as_ref(), None, validate);
163        DuplicateStructFieldId::validate(&self.fields, None, validate);
164
165        for field in &self.fields {
166            field.validate(validate);
167        }
168
169        if let Some(ref fallback) = self.fallback {
170            fallback.validate(validate);
171        }
172    }
173
174    pub fn span(&self) -> Span {
175        self.span
176    }
177
178    pub fn keyword_span(&self) -> Span {
179        self.kw_span
180    }
181
182    pub fn doc(&self) -> &[DocString] {
183        &self.doc
184    }
185
186    pub fn attributes(&self) -> &[Attribute] {
187        &self.attrs
188    }
189
190    pub fn fields(&self) -> &[StructField] {
191        &self.fields
192    }
193
194    pub fn fallback(&self) -> Option<&StructFallback> {
195        self.fallback.as_ref()
196    }
197}
198
199#[derive(Debug, Clone)]
200pub struct StructField {
201    span: Span,
202    comment: Vec<Comment>,
203    doc: Vec<DocString>,
204    req: bool,
205    name: Ident,
206    id: LitInt,
207    field_type: TypeName,
208}
209
210impl StructField {
211    fn parse(pair: Pair<Rule>) -> Self {
212        assert_eq!(pair.as_rule(), Rule::struct_field);
213
214        let span = Span::from_pair(&pair);
215        let mut pairs = pair.into_inner();
216        let mut prelude = Prelude::regular(&mut pairs);
217
218        let (req, name) = match pairs.next().map(|pair| (pair.as_rule(), pair)).unwrap() {
219            (Rule::kw_required, _) => (true, Ident::parse(&pairs.next().unwrap())),
220            (Rule::ident, pair) => (false, Ident::parse(&pair)),
221            _ => unreachable!(),
222        };
223
224        pairs.next().unwrap(); // Skip @.
225
226        let pair = pairs.next().unwrap();
227        let id = LitInt::parse(&pair);
228
229        pairs.next().unwrap(); // Skip =.
230
231        let pair = pairs.next().unwrap();
232        let field_type = TypeName::parse(pair);
233
234        Self {
235            span,
236            comment: prelude.take_comment(),
237            doc: prelude.take_doc(),
238            req,
239            name,
240            id,
241            field_type,
242        }
243    }
244
245    fn validate(&self, validate: &mut Validate) {
246        BrokenDocLink::validate(&self.doc, validate);
247        InvalidStructFieldId::validate(self, validate);
248        NonSnakeCaseStructField::validate(&self.name, validate);
249
250        self.name.validate(true, validate);
251        self.field_type.validate(false, validate);
252    }
253
254    pub fn span(&self) -> Span {
255        self.span
256    }
257
258    pub fn comment(&self) -> &[Comment] {
259        &self.comment
260    }
261
262    pub fn doc(&self) -> &[DocString] {
263        &self.doc
264    }
265
266    pub fn required(&self) -> bool {
267        self.req
268    }
269
270    pub fn name(&self) -> &Ident {
271        &self.name
272    }
273
274    pub fn id(&self) -> &LitInt {
275        &self.id
276    }
277
278    pub fn field_type(&self) -> &TypeName {
279        &self.field_type
280    }
281}
282
283#[derive(Debug, Clone)]
284pub struct StructFallback {
285    span: Span,
286    comment: Vec<Comment>,
287    doc: Vec<DocString>,
288    name: Ident,
289}
290
291impl StructFallback {
292    pub(crate) fn parse(pair: Pair<Rule>) -> Self {
293        assert_eq!(pair.as_rule(), Rule::struct_fallback);
294
295        let span = Span::from_pair(&pair);
296        let mut pairs = pair.into_inner();
297        let mut prelude = Prelude::regular(&mut pairs);
298
299        Self {
300            span,
301            comment: prelude.take_comment(),
302            doc: prelude.take_doc(),
303            name: Ident::parse(&pairs.next().unwrap()),
304        }
305    }
306
307    pub(crate) fn validate(&self, validate: &mut Validate) {
308        BrokenDocLink::validate(&self.doc, validate);
309        NonSnakeCaseStructField::validate(&self.name, validate);
310
311        self.name.validate(true, validate);
312    }
313
314    pub fn span(&self) -> Span {
315        self.span
316    }
317
318    pub fn comment(&self) -> &[Comment] {
319        &self.comment
320    }
321
322    pub fn doc(&self) -> &[DocString] {
323        &self.doc
324    }
325
326    pub fn name(&self) -> &Ident {
327        &self.name
328    }
329}