Skip to main content

aldrin_parser/ast/
enum_def.rs

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