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(); let pair = pairs.next().unwrap();
33 let name = Ident::parse(&pair);
34
35 pairs.next().unwrap(); 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(); 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(); 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}