Skip to main content

aldrin_parser/ast/
service_def.rs

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(); // Skip keyword.
36
37        let pair = pairs.next().unwrap();
38        let name = Ident::parse(&pair);
39
40        pairs.next().unwrap(); // Skip {.
41
42        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(); // Skip keyword.
94        pairs.next().unwrap(); // Skip =.
95
96        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(); // Skip keyword.
107        pairs.next().unwrap(); // Skip =.
108
109        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(); // Skip keyword.
267
268        let pair = pairs.next().unwrap();
269        let name = Ident::parse(&pair);
270
271        pairs.next().unwrap(); // Skip @.
272
273        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(); // Skip keyword.
375                pairs.next().unwrap(); // Skip =.
376
377                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(); // Skip keyword.
428
429        let pair = pairs.next().unwrap();
430        let name = Ident::parse(&pair);
431
432        pairs.next().unwrap(); // Skip @.
433
434        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(); // Skip keyword.
514
515        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(); // Skip keyword.
566
567        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}