1use super::{Comment, DocString, Ident, LitInt, LitUuid, Prelude, TypeNameOrInline};
2use crate::Span;
3use crate::error::{
4 DuplicateEventId, DuplicateFunctionId, DuplicateServiceItem, InvalidEventId, InvalidFunctionId,
5 InvalidServiceVersion,
6};
7use crate::grammar::Rule;
8use crate::validate::Validate;
9use crate::warning::{BrokenDocLink, NonCamelCaseService, NonSnakeCaseEvent, NonSnakeCaseFunction};
10use pest::iterators::Pair;
11
12#[derive(Debug, Clone)]
13pub struct ServiceDef {
14 span: Span,
15 comment: Vec<Comment>,
16 doc: Vec<DocString>,
17 name: Ident,
18 uuid_comment: Vec<Comment>,
19 uuid: LitUuid,
20 ver_comment: Vec<Comment>,
21 ver: LitInt,
22 items: Vec<ServiceItem>,
23 fn_fallback: Option<FunctionFallback>,
24 ev_fallback: Option<EventFallback>,
25}
26
27impl ServiceDef {
28 pub(crate) fn parse(pair: Pair<Rule>) -> Self {
29 assert_eq!(pair.as_rule(), Rule::service_def);
30
31 let span = Span::from_pair(&pair);
32 let mut pairs = pair.into_inner();
33 let mut prelude = Prelude::regular(&mut pairs);
34
35 pairs.next().unwrap(); let pair = pairs.next().unwrap();
38 let name = Ident::parse(&pair);
39
40 pairs.next().unwrap(); let pair = pairs.next().unwrap();
43 let (uuid_comment, uuid) = Self::parse_uuid(pair);
44
45 let pair = pairs.next().unwrap();
46 let (ver_comment, ver) = Self::parse_version(pair);
47
48 let mut items = Vec::new();
49 let mut fn_fallback = None;
50 let mut ev_fallback = None;
51
52 for pair in pairs {
53 #[expect(clippy::wildcard_enum_match_arm)]
54 match pair.as_rule() {
55 Rule::service_item => items.push(ServiceItem::parse(pair)),
56
57 Rule::service_fallback => {
58 for pair in pair.into_inner() {
59 match pair.as_rule() {
60 Rule::fn_fallback => fn_fallback = Some(FunctionFallback::parse(pair)),
61 Rule::event_fallback => ev_fallback = Some(EventFallback::parse(pair)),
62 _ => unreachable!(),
63 }
64 }
65 }
66
67 Rule::tok_cur_close => break,
68 _ => unreachable!(),
69 }
70 }
71
72 Self {
73 span,
74 comment: prelude.take_comment(),
75 doc: prelude.take_doc(),
76 name,
77 uuid_comment,
78 uuid,
79 ver_comment,
80 ver,
81 items,
82 fn_fallback,
83 ev_fallback,
84 }
85 }
86
87 fn parse_uuid(pair: Pair<Rule>) -> (Vec<Comment>, LitUuid) {
88 assert_eq!(pair.as_rule(), Rule::service_uuid);
89
90 let mut pairs = pair.into_inner();
91 let mut prelude = Prelude::regular(&mut pairs);
92
93 pairs.next().unwrap(); pairs.next().unwrap(); let pair = pairs.next().unwrap();
97 (prelude.take_comment(), LitUuid::parse(&pair))
98 }
99
100 fn parse_version(pair: Pair<Rule>) -> (Vec<Comment>, LitInt) {
101 assert_eq!(pair.as_rule(), Rule::service_version);
102
103 let mut pairs = pair.into_inner();
104 let mut prelude = Prelude::regular(&mut pairs);
105
106 pairs.next().unwrap(); pairs.next().unwrap(); let pair = pairs.next().unwrap();
110 (prelude.take_comment(), LitInt::parse(&pair))
111 }
112
113 pub(crate) fn validate(&self, validate: &mut Validate) {
114 BrokenDocLink::validate(&self.doc, validate);
115 InvalidServiceVersion::validate(self, validate);
116 DuplicateServiceItem::validate(self, validate);
117 DuplicateFunctionId::validate(self, validate);
118 DuplicateEventId::validate(self, validate);
119 NonCamelCaseService::validate(self, validate);
120
121 self.name.validate(true, validate);
122
123 for item in &self.items {
124 item.validate(validate);
125 }
126
127 if let Some(ref fn_fallback) = self.fn_fallback {
128 fn_fallback.validate(validate);
129 }
130
131 if let Some(ref ev_fallback) = self.ev_fallback {
132 ev_fallback.validate(validate);
133 }
134 }
135
136 pub fn span(&self) -> Span {
137 self.span
138 }
139
140 pub fn comment(&self) -> &[Comment] {
141 &self.comment
142 }
143
144 pub fn doc(&self) -> &[DocString] {
145 &self.doc
146 }
147
148 pub fn name(&self) -> &Ident {
149 &self.name
150 }
151
152 pub fn uuid_comment(&self) -> &[Comment] {
153 &self.uuid_comment
154 }
155
156 pub fn uuid(&self) -> &LitUuid {
157 &self.uuid
158 }
159
160 pub fn version_comment(&self) -> &[Comment] {
161 &self.ver_comment
162 }
163
164 pub fn version(&self) -> &LitInt {
165 &self.ver
166 }
167
168 pub fn items(&self) -> &[ServiceItem] {
169 &self.items
170 }
171
172 pub fn function_fallback(&self) -> Option<&FunctionFallback> {
173 self.fn_fallback.as_ref()
174 }
175
176 pub fn event_fallback(&self) -> Option<&EventFallback> {
177 self.ev_fallback.as_ref()
178 }
179}
180
181#[derive(Debug, Clone)]
182#[expect(clippy::large_enum_variant)]
183pub enum ServiceItem {
184 Function(FunctionDef),
185 Event(EventDef),
186}
187
188impl ServiceItem {
189 fn parse(pair: Pair<Rule>) -> Self {
190 assert_eq!(pair.as_rule(), Rule::service_item);
191
192 let mut pairs = pair.into_inner();
193 let pair = pairs.next().unwrap();
194
195 #[expect(clippy::wildcard_enum_match_arm)]
196 match pair.as_rule() {
197 Rule::fn_def => Self::Function(FunctionDef::parse(pair)),
198 Rule::event_def => Self::Event(EventDef::parse(pair)),
199 _ => unreachable!(),
200 }
201 }
202
203 fn validate(&self, validate: &mut Validate) {
204 match self {
205 Self::Function(i) => i.validate(validate),
206 Self::Event(i) => i.validate(validate),
207 }
208 }
209
210 pub fn span(&self) -> Span {
211 match self {
212 Self::Function(i) => i.span(),
213 Self::Event(i) => i.span(),
214 }
215 }
216
217 pub fn doc(&self) -> &[DocString] {
218 match self {
219 Self::Function(i) => i.doc(),
220 Self::Event(i) => i.doc(),
221 }
222 }
223
224 pub fn name(&self) -> &Ident {
225 match self {
226 Self::Function(i) => i.name(),
227 Self::Event(i) => i.name(),
228 }
229 }
230
231 pub fn as_function(&self) -> Option<&FunctionDef> {
232 match self {
233 Self::Function(i) => Some(i),
234 Self::Event(_) => None,
235 }
236 }
237
238 pub fn as_event(&self) -> Option<&EventDef> {
239 match self {
240 Self::Function(_) => None,
241 Self::Event(i) => Some(i),
242 }
243 }
244}
245
246#[derive(Debug, Clone)]
247pub struct FunctionDef {
248 span: Span,
249 comment: Vec<Comment>,
250 doc: Vec<DocString>,
251 name: Ident,
252 id: LitInt,
253 args: Option<FunctionPart>,
254 ok: Option<FunctionPart>,
255 err: Option<FunctionPart>,
256}
257
258impl FunctionDef {
259 fn parse(pair: Pair<Rule>) -> Self {
260 assert_eq!(pair.as_rule(), Rule::fn_def);
261
262 let span = Span::from_pair(&pair);
263 let mut pairs = pair.into_inner();
264 let mut prelude = Prelude::regular(&mut pairs);
265
266 pairs.next().unwrap(); let pair = pairs.next().unwrap();
269 let name = Ident::parse(&pair);
270
271 pairs.next().unwrap(); let pair = pairs.next().unwrap();
274 let id = LitInt::parse(&pair);
275
276 let mut args = None;
277 let mut ok = None;
278 let mut err = None;
279
280 for pair in pairs {
281 #[expect(clippy::wildcard_enum_match_arm)]
282 match pair.as_rule() {
283 Rule::fn_args => args = Some(FunctionPart::parse(pair)),
284 Rule::fn_ok | Rule::type_name_or_inline => ok = Some(FunctionPart::parse(pair)),
285 Rule::fn_err => err = Some(FunctionPart::parse(pair)),
286
287 Rule::tok_cur_open | Rule::tok_cur_close | Rule::tok_eq | Rule::tok_term => {}
288 _ => unreachable!(),
289 }
290 }
291
292 Self {
293 span,
294 comment: prelude.take_comment(),
295 doc: prelude.take_doc(),
296 name,
297 id,
298 args,
299 ok,
300 err,
301 }
302 }
303
304 fn validate(&self, validate: &mut Validate) {
305 BrokenDocLink::validate(&self.doc, validate);
306 NonSnakeCaseFunction::validate(self, validate);
307 InvalidFunctionId::validate(self, validate);
308
309 self.name.validate(true, validate);
310
311 if let Some(ref args) = self.args {
312 args.validate(validate);
313 }
314
315 if let Some(ref ok) = self.ok {
316 ok.validate(validate);
317 }
318
319 if let Some(ref err) = self.err {
320 err.validate(validate);
321 }
322 }
323
324 pub fn span(&self) -> Span {
325 self.span
326 }
327
328 pub fn comment(&self) -> &[Comment] {
329 &self.comment
330 }
331
332 pub fn doc(&self) -> &[DocString] {
333 &self.doc
334 }
335
336 pub fn name(&self) -> &Ident {
337 &self.name
338 }
339
340 pub fn id(&self) -> &LitInt {
341 &self.id
342 }
343
344 pub fn args(&self) -> Option<&FunctionPart> {
345 self.args.as_ref()
346 }
347
348 pub fn ok(&self) -> Option<&FunctionPart> {
349 self.ok.as_ref()
350 }
351
352 pub fn err(&self) -> Option<&FunctionPart> {
353 self.err.as_ref()
354 }
355}
356
357#[derive(Debug, Clone)]
358pub struct FunctionPart {
359 span: Span,
360 comment: Vec<Comment>,
361 part_type: TypeNameOrInline,
362}
363
364impl FunctionPart {
365 fn parse(pair: Pair<Rule>) -> Self {
366 let span = Span::from_pair(&pair);
367
368 #[expect(clippy::wildcard_enum_match_arm)]
369 let (comment, part_type) = match pair.as_rule() {
370 Rule::fn_args | Rule::fn_ok | Rule::fn_err => {
371 let mut pairs = pair.into_inner();
372 let mut prelude = Prelude::regular(&mut pairs);
373
374 pairs.next().unwrap(); pairs.next().unwrap(); let pair = pairs.next().unwrap();
378 (prelude.take_comment(), TypeNameOrInline::parse(pair))
379 }
380
381 Rule::type_name_or_inline => (Vec::new(), TypeNameOrInline::parse(pair)),
382 _ => unreachable!(),
383 };
384
385 Self {
386 span,
387 comment,
388 part_type,
389 }
390 }
391
392 fn validate(&self, validate: &mut Validate) {
393 self.part_type.validate(validate);
394 }
395
396 pub fn span(&self) -> Span {
397 self.span
398 }
399
400 pub fn comment(&self) -> &[Comment] {
401 &self.comment
402 }
403
404 pub fn part_type(&self) -> &TypeNameOrInline {
405 &self.part_type
406 }
407}
408
409#[derive(Debug, Clone)]
410pub struct EventDef {
411 span: Span,
412 comment: Vec<Comment>,
413 doc: Vec<DocString>,
414 name: Ident,
415 id: LitInt,
416 event_type: Option<TypeNameOrInline>,
417}
418
419impl EventDef {
420 fn parse(pair: Pair<Rule>) -> Self {
421 assert_eq!(pair.as_rule(), Rule::event_def);
422
423 let span = Span::from_pair(&pair);
424 let mut pairs = pair.into_inner();
425 let mut prelude = Prelude::regular(&mut pairs);
426
427 pairs.next().unwrap(); let pair = pairs.next().unwrap();
430 let name = Ident::parse(&pair);
431
432 pairs.next().unwrap(); let pair = pairs.next().unwrap();
435 let id = LitInt::parse(&pair);
436
437 let pair = pairs.next().unwrap();
438
439 #[expect(clippy::wildcard_enum_match_arm)]
440 let event_type = match pair.as_rule() {
441 Rule::tok_eq => {
442 let pair = pairs.next().unwrap();
443 Some(TypeNameOrInline::parse(pair))
444 }
445
446 Rule::tok_term => None,
447 _ => unreachable!(),
448 };
449
450 Self {
451 span,
452 comment: prelude.take_comment(),
453 doc: prelude.take_doc(),
454 name,
455 id,
456 event_type,
457 }
458 }
459
460 fn validate(&self, validate: &mut Validate) {
461 BrokenDocLink::validate(&self.doc, validate);
462 NonSnakeCaseEvent::validate(self, validate);
463 InvalidEventId::validate(self, validate);
464
465 self.name.validate(true, validate);
466
467 if let Some(ref event_type) = self.event_type {
468 event_type.validate(validate);
469 }
470 }
471
472 pub fn span(&self) -> Span {
473 self.span
474 }
475
476 pub fn comment(&self) -> &[Comment] {
477 &self.comment
478 }
479
480 pub fn doc(&self) -> &[DocString] {
481 &self.doc
482 }
483
484 pub fn name(&self) -> &Ident {
485 &self.name
486 }
487
488 pub fn id(&self) -> &LitInt {
489 &self.id
490 }
491
492 pub fn event_type(&self) -> Option<&TypeNameOrInline> {
493 self.event_type.as_ref()
494 }
495}
496
497#[derive(Debug, Clone)]
498pub struct FunctionFallback {
499 span: Span,
500 comment: Vec<Comment>,
501 doc: Vec<DocString>,
502 name: Ident,
503}
504
505impl FunctionFallback {
506 fn parse(pair: Pair<Rule>) -> Self {
507 assert_eq!(pair.as_rule(), Rule::fn_fallback);
508
509 let span = Span::from_pair(&pair);
510 let mut pairs = pair.into_inner();
511 let mut prelude = Prelude::regular(&mut pairs);
512
513 pairs.next().unwrap(); let pair = pairs.next().unwrap();
516 let name = Ident::parse(&pair);
517
518 Self {
519 span,
520 comment: prelude.take_comment(),
521 doc: prelude.take_doc(),
522 name,
523 }
524 }
525
526 fn validate(&self, validate: &mut Validate) {
527 self.name.validate(true, validate);
528
529 BrokenDocLink::validate(&self.doc, validate);
530 }
531
532 pub fn span(&self) -> Span {
533 self.span
534 }
535
536 pub fn comment(&self) -> &[Comment] {
537 &self.comment
538 }
539
540 pub fn doc(&self) -> &[DocString] {
541 &self.doc
542 }
543
544 pub fn name(&self) -> &Ident {
545 &self.name
546 }
547}
548
549#[derive(Debug, Clone)]
550pub struct EventFallback {
551 span: Span,
552 comment: Vec<Comment>,
553 doc: Vec<DocString>,
554 name: Ident,
555}
556
557impl EventFallback {
558 fn parse(pair: Pair<Rule>) -> Self {
559 assert_eq!(pair.as_rule(), Rule::event_fallback);
560
561 let span = Span::from_pair(&pair);
562 let mut pairs = pair.into_inner();
563 let mut prelude = Prelude::regular(&mut pairs);
564
565 pairs.next().unwrap(); let pair = pairs.next().unwrap();
568 let name = Ident::parse(&pair);
569
570 Self {
571 span,
572 comment: prelude.take_comment(),
573 doc: prelude.take_doc(),
574 name,
575 }
576 }
577
578 fn validate(&self, validate: &mut Validate) {
579 self.name.validate(true, validate);
580
581 BrokenDocLink::validate(&self.doc, validate);
582 }
583
584 pub fn span(&self) -> Span {
585 self.span
586 }
587
588 pub fn comment(&self) -> &[Comment] {
589 &self.comment
590 }
591
592 pub fn doc(&self) -> &[DocString] {
593 &self.doc
594 }
595
596 pub fn name(&self) -> &Ident {
597 &self.name
598 }
599}