Skip to main content

device_driver_diagnostics/
errors.rs

1#![allow(
2    unused_assignments,
3    reason = "Something going on with the diagnostics derive"
4)]
5
6use std::borrow::Cow;
7
8use annotate_snippets::{AnnotationKind, Group, Level, Patch, Snippet};
9use device_driver_common::{
10    identifier::{self, Identifier, RuntimeType},
11    span::{Span, Spanned},
12    specifiers::{BaseType, Integer, NodeType},
13};
14use itertools::Itertools;
15
16use crate::{Diagnostic, encode_ansi_url};
17
18#[derive(Debug)]
19pub struct IntegerFieldSizeTooBig {
20    pub field_address: Span,
21    pub base_type: Span,
22    pub field_set: Span,
23    pub size_bits: u64,
24}
25
26impl Diagnostic for IntegerFieldSizeTooBig {
27    fn is_error(&self) -> bool {
28        true
29    }
30
31    fn as_report<'a>(&'a self, source: &'a str, path: &'a str) -> Vec<Group<'a>> {
32        let field_message = format!("field has a size of {} bits", self.size_bits);
33
34        [
35            Level::ERROR
36                .primary_title("field size exceeds 64-bit size limit")
37                .element(
38                    Snippet::source(source)
39                        .path(path)
40                        .annotation(
41                            AnnotationKind::Primary
42                                .span(self.field_address.into())
43                                .label(field_message),
44                        )
45                        .annotation(
46                            AnnotationKind::Context
47                                .span(self.base_type.into())
48                                .label("field uses an integer as base type"),
49                        )
50                        .annotation(AnnotationKind::Visible.span(self.field_set.into())),
51                ),
52            Group::with_title(
53                Level::NOTE.secondary_title("integer base types are available up to 64-bit"),
54            ),
55            Group::with_title(Level::INFO.secondary_title(format!(
56                "if you need an array or string base type, please comment here: {}",
57                encode_ansi_url(
58                    "https://github.com/diondokter/device-driver/issues/131",
59                    "issue 131"
60                )
61            ))),
62        ]
63        .to_vec()
64    }
65}
66
67#[derive(Debug)]
68pub struct DeviceNameNotPascal {
69    pub device_name: Span,
70    pub suggestion: String,
71}
72
73impl Diagnostic for DeviceNameNotPascal {
74    fn is_error(&self) -> bool {
75        true
76    }
77
78    fn as_report<'a>(&'a self, source: &'a str, path: &'a str) -> Vec<Group<'a>> {
79        const INFO_TEXT: &str = "device names tend to be a bit weird, so the casing is not automatically changed from the input. Because of that, they need to be roughly PascalCase shaped.";
80
81        [
82            Level::ERROR.primary_title("invalid device name").element(
83                Snippet::source(source).path(path).annotation(
84                    AnnotationKind::Primary
85                        .span(self.device_name.into())
86                        .label("device name is not Pascal cased"),
87                ),
88            ),
89            Level::HELP
90                .secondary_title("device names need to be pascal-shaped")
91                .element(
92                    Snippet::source(source)
93                        .path(path)
94                        .patch(Patch::new(self.device_name.into(), &self.suggestion)),
95                ),
96            Group::with_title(Level::INFO.secondary_title(INFO_TEXT)),
97        ]
98        .to_vec()
99    }
100}
101
102#[derive(Debug)]
103pub struct DuplicateName {
104    pub original: Span,
105    pub original_value: Identifier<RuntimeType>,
106    pub duplicate: Span,
107    pub duplicate_value: Identifier<RuntimeType>,
108}
109
110impl Diagnostic for DuplicateName {
111    fn is_error(&self) -> bool {
112        true
113    }
114
115    fn as_report<'a>(&'a self, source: &'a str, path: &'a str) -> Vec<Group<'a>> {
116        const INFO_TEXT: &str =
117            "names may not collide within their namespace. There are 4 namespaces:
118- Types: a type definition
119- Operations: something you *do* with a driver
120- Fields: unique within a fieldset
121- Enum variants: unique within an enum";
122
123        [
124            Level::ERROR.primary_title("duplicate name found").element(
125                Snippet::source(source)
126                    .path(path)
127                    .annotation(
128                        AnnotationKind::Context
129                            .span(self.original.into())
130                            .label(format!(
131                                "the original: {:?}, after word split: {:?}",
132                                self.original_value.original(),
133                                self.original_value.words_display()
134                            )),
135                    )
136                    .annotation(AnnotationKind::Primary.span(self.duplicate.into()).label(
137                        format!(
138                            "the duplicate: {:?}, after word split: {:?}",
139                            self.duplicate_value.original(),
140                            self.duplicate_value.words_display()
141                        ),
142                    )),
143            ),
144            Group::with_title(Level::INFO.secondary_title(INFO_TEXT)),
145        ]
146        .to_vec()
147    }
148}
149
150#[derive(Debug)]
151pub struct EmptyEnum {
152    pub enum_node: Span,
153}
154
155impl Diagnostic for EmptyEnum {
156    fn is_error(&self) -> bool {
157        true
158    }
159
160    fn as_report<'a>(&'a self, source: &'a str, path: &'a str) -> Vec<Group<'a>> {
161        [
162            Level::ERROR.primary_title("enum has no variants").element(
163                Snippet::source(source).path(path).annotation(
164                    AnnotationKind::Primary
165                        .span(self.enum_node.into())
166                        .label("empty enum"),
167                ),
168            ),
169            Group::with_title(
170                Level::INFO.secondary_title("all enums must have at least one variant"),
171            ),
172        ]
173        .to_vec()
174    }
175}
176
177#[derive(Debug)]
178pub struct DuplicateVariantValue {
179    pub duplicates: Vec<Span>,
180    pub value: i128,
181}
182
183impl Diagnostic for DuplicateVariantValue {
184    fn is_error(&self) -> bool {
185        true
186    }
187
188    fn as_report<'a>(&'a self, source: &'a str, path: &'a str) -> Vec<Group<'a>> {
189        const INFO_TEXT: &str = "all enum variants must have a unique value";
190
191        [
192            Level::ERROR
193                .primary_title("two or more enum variants share the same value")
194                .element(Snippet::source(source).path(path).annotations(
195                    self.duplicates.iter().map(|dup| {
196                        AnnotationKind::Primary.span(dup.into()).label(format!(
197                            "variant value is: {} ({:#X})",
198                            self.value, self.value
199                        ))
200                    }),
201                )),
202            Group::with_title(Level::INFO.secondary_title(INFO_TEXT)),
203        ]
204        .to_vec()
205    }
206}
207
208#[derive(Debug)]
209pub struct EnumBadBasetype {
210    pub enum_name: Span,
211    pub base_type: Span,
212    pub info: &'static str,
213    pub context: Vec<Spanned<String>>,
214}
215
216impl Diagnostic for EnumBadBasetype {
217    fn is_error(&self) -> bool {
218        true
219    }
220
221    fn as_report<'a>(&'a self, source: &'a str, path: &'a str) -> Vec<Group<'a>> {
222        [
223            Level::ERROR
224                .primary_title("invalid base type for enum")
225                .element(
226                    Snippet::source(source)
227                        .path(path)
228                        .annotation(
229                            AnnotationKind::Primary
230                                .span(self.base_type.into())
231                                .label("invalid base type"),
232                        )
233                        .annotation(
234                            AnnotationKind::Context
235                                .span(self.enum_name.into())
236                                .label("enum using invalid base type"),
237                        )
238                        .annotations(
239                            self.context.iter().map(|c| {
240                                AnnotationKind::Context.span(c.span.into()).label(&c.value)
241                            }),
242                        ),
243                ),
244            Group::with_title(Level::INFO.secondary_title(self.info)),
245        ]
246        .to_vec()
247    }
248}
249
250#[derive(Debug)]
251pub struct EnumSizeBitsBiggerThanBaseType {
252    pub enum_name: Span,
253    pub base_type: Span,
254    pub enum_size_bits: u32,
255    pub base_type_size_bits: u32,
256}
257
258impl Diagnostic for EnumSizeBitsBiggerThanBaseType {
259    fn is_error(&self) -> bool {
260        true
261    }
262
263    fn as_report<'a>(&'a self, source: &'a str, path: &'a str) -> Vec<Group<'a>> {
264        [
265            Level::ERROR
266                .primary_title("enum doesn't fit its base type")
267                .element(
268                    Snippet::source(source)
269                        .path(path)
270                        .annotation(
271                            AnnotationKind::Primary
272                                .span(self.enum_name.into())
273                                .label(format!("enum is {} bits", self.enum_size_bits)),
274                        )
275                        .annotation(
276                            AnnotationKind::Primary
277                                .span(self.base_type.into())
278                                .label(format!("base type is {} bits", self.base_type_size_bits)),
279                        ),
280                ),
281            Group::with_title(
282                // TODO: Add patch for base type
283                Level::HELP.secondary_title("make the enum smaller or pick a bigger base type"),
284            ),
285        ]
286        .to_vec()
287    }
288}
289
290#[derive(Debug)]
291pub struct EnumNoAutoBaseTypeSelected {
292    pub enum_name: Span,
293}
294
295impl Diagnostic for EnumNoAutoBaseTypeSelected {
296    fn is_error(&self) -> bool {
297        true
298    }
299
300    fn as_report<'a>(&'a self, source: &'a str, path: &'a str) -> Vec<Group<'a>> {
301        const NOTE_TEXT: &str =
302            "a variant or the size-bits is too big to fit in any of the base types";
303
304        [
305            Level::ERROR
306                .primary_title("no valid base type found")
307                .element(
308                    Snippet::source(source).path(path).annotation(
309                        AnnotationKind::Primary
310                            .span(self.enum_name.into())
311                            .label("could not select a valid base type for this enum"),
312                    ),
313                ),
314            Group::with_title(Level::NOTE.secondary_title(NOTE_TEXT)),
315        ]
316        .to_vec()
317    }
318}
319
320#[derive(Debug)]
321pub struct VariantValuesTooHigh {
322    pub variant_names: Vec<Span>,
323    pub enum_name: Span,
324    pub max_value: i128,
325    pub size_bits: u32,
326}
327
328impl Diagnostic for VariantValuesTooHigh {
329    fn is_error(&self) -> bool {
330        true
331    }
332
333    fn as_report<'a>(&'a self, source: &'a str, path: &'a str) -> Vec<Group<'a>> {
334        [
335            Level::ERROR
336                .primary_title("enum variant value is too high")
337                .element(
338                    Snippet::source(source)
339                        .path(path)
340                        .annotation(
341                            AnnotationKind::Context
342                                .span(self.enum_name.into())
343                                .label(format!("enum is {} bits", self.size_bits)),
344                        )
345                        .annotations(self.variant_names.iter().map(|name| {
346                            AnnotationKind::Primary.span(name.into()).label(format!(
347                                "variant value exceeds the max of {} ({:#X})",
348                                self.max_value, self.max_value
349                            ))
350                        })),
351                ),
352            Group::with_title(Level::INFO.secondary_title("all variants must fit in their enum")),
353        ]
354        .to_vec()
355    }
356}
357
358#[derive(Debug)]
359pub struct VariantValuesTooLow {
360    pub variant_names: Vec<Span>,
361    pub enum_name: Span,
362    pub min_value: i128,
363    pub size_bits: u32,
364}
365
366impl Diagnostic for VariantValuesTooLow {
367    fn is_error(&self) -> bool {
368        true
369    }
370
371    fn as_report<'a>(&'a self, source: &'a str, path: &'a str) -> Vec<Group<'a>> {
372        [
373            Level::ERROR
374                .primary_title("enum variant value is too low")
375                .element(
376                    Snippet::source(source)
377                        .path(path)
378                        .annotation(
379                            AnnotationKind::Context
380                                .span(self.enum_name.into())
381                                .label(format!("enum is {} bits", self.size_bits)),
382                        )
383                        .annotations(self.variant_names.iter().map(|name| {
384                            AnnotationKind::Primary.span(name.into()).label(format!(
385                                "variant value exceeds the min of {}",
386                                self.min_value
387                            ))
388                        })),
389                ),
390            Group::with_title(Level::INFO.secondary_title("all variants must fit in their enum")),
391        ]
392        .to_vec()
393    }
394}
395
396#[derive(Debug)]
397pub struct EnumMultipleDefaults {
398    pub enum_name: Span,
399    pub variant_names: Vec<Span>,
400}
401
402impl Diagnostic for EnumMultipleDefaults {
403    fn is_error(&self) -> bool {
404        true
405    }
406
407    fn as_report<'a>(&'a self, source: &'a str, path: &'a str) -> Vec<Group<'a>> {
408        [
409            Level::ERROR
410                .primary_title("enum defines more than one default variant")
411                .element(
412                    Snippet::source(source)
413                        .path(path)
414                        .annotation(
415                            AnnotationKind::Context
416                                .span(self.enum_name.into())
417                                .label("offending enum"),
418                        )
419                        .annotations(self.variant_names.iter().enumerate().map(
420                            |(index, variant_name)| {
421                                if index == 0 {
422                                    AnnotationKind::Context
423                                        .span(variant_name.into())
424                                        .label("first default variant")
425                                } else {
426                                    AnnotationKind::Primary
427                                        .span(variant_name.into())
428                                        .label("extra default variant")
429                                }
430                            },
431                        )),
432                ),
433            Group::with_title(
434                Level::INFO.secondary_title("enums can have at most one default variant"),
435            ),
436        ]
437        .to_vec()
438    }
439}
440
441#[derive(Debug)]
442pub struct EnumMultipleCatchalls {
443    pub enum_name: Span,
444    pub variant_names: Vec<Span>,
445}
446
447impl Diagnostic for EnumMultipleCatchalls {
448    fn is_error(&self) -> bool {
449        true
450    }
451
452    fn as_report<'a>(&'a self, source: &'a str, path: &'a str) -> Vec<Group<'a>> {
453        [
454            Level::ERROR
455                .primary_title("enum defines more than one catch-all variant")
456                .element(
457                    Snippet::source(source)
458                        .path(path)
459                        .annotation(
460                            AnnotationKind::Context
461                                .span(self.enum_name.into())
462                                .label("offending enum"),
463                        )
464                        .annotations(self.variant_names.iter().enumerate().map(
465                            |(index, variant_name)| {
466                                if index == 0 {
467                                    AnnotationKind::Context
468                                        .span(variant_name.into())
469                                        .label("first catch-all variant")
470                                } else {
471                                    AnnotationKind::Primary
472                                        .span(variant_name.into())
473                                        .label("extra catch-all variant")
474                                }
475                            },
476                        )),
477                ),
478            Group::with_title(
479                Level::INFO.secondary_title("enums can have at most one catch-all variant"),
480            ),
481        ]
482        .to_vec()
483    }
484}
485
486#[derive(Debug)]
487pub struct ReferencedObjectDoesNotExist {
488    pub object_reference: Span,
489}
490
491impl Diagnostic for ReferencedObjectDoesNotExist {
492    fn is_error(&self) -> bool {
493        true
494    }
495
496    fn as_report<'a>(&'a self, source: &'a str, path: &'a str) -> Vec<Group<'a>> {
497        const INFO_TEXT: &str = "all objects must be specified in the manifest. It's possible a previous analysis step removed it due to some error. See the previous diagnostics";
498
499        [
500            Level::ERROR
501                .primary_title("referenced object does not exist")
502                .element(
503                    Snippet::source(source).path(path).annotation(
504                        AnnotationKind::Primary
505                            .span(self.object_reference.into())
506                            .label("object cannot be found"),
507                    ),
508                ),
509            Group::with_title(Level::INFO.secondary_title(INFO_TEXT)),
510        ]
511        .to_vec()
512    }
513}
514
515#[derive(Debug)]
516pub struct InvalidConversionType {
517    pub object_reference: Span,
518    pub referenced_object: Span,
519}
520
521impl Diagnostic for InvalidConversionType {
522    fn is_error(&self) -> bool {
523        true
524    }
525
526    fn as_report<'a>(&'a self, source: &'a str, path: &'a str) -> Vec<Group<'a>> {
527        const NOTE_TEXT: &str = "the referenced object has an invalid type. Only enums and externs can be used for conversions";
528
529        [
530            Level::ERROR
531                .primary_title("invalid conversion type")
532                .element(
533                    Snippet::source(source)
534                        .path(path)
535                        .annotation(
536                            AnnotationKind::Primary
537                                .span(self.object_reference.into())
538                                .label("object referenced as conversion type"),
539                        )
540                        .annotation(
541                            AnnotationKind::Context
542                                .span(self.referenced_object.into())
543                                .label("referenced object"),
544                        ),
545                ),
546            Group::with_title(Level::NOTE.secondary_title(NOTE_TEXT)),
547        ]
548        .to_vec()
549    }
550}
551
552#[derive(Debug)]
553pub struct RepeatEnumWithCatchAll {
554    pub repeat_enum: Span,
555    pub enum_name: Span,
556    pub catch_all: Span,
557}
558
559impl Diagnostic for RepeatEnumWithCatchAll {
560    fn is_error(&self) -> bool {
561        true
562    }
563
564    fn as_report<'a>(&'a self, source: &'a str, path: &'a str) -> Vec<Group<'a>> {
565        const INFO_TEXT: &str = "to be able to do all analysis passes correctly, the amount of repeats need to be statically known.
566This is not possible with an enum containing a catch-all since it can take on any value";
567
568        [
569            Level::ERROR
570                .primary_title("enum with catch-all used as repeat source")
571                .element(
572                    Snippet::source(source)
573                        .path(path)
574                        .annotation(
575                            AnnotationKind::Primary
576                                .span(self.repeat_enum.into())
577                                .label("repeat uses enum with catch-all"),
578                        )
579                        .annotation(AnnotationKind::Visible.span(self.enum_name.into()))
580                        .annotation(
581                            AnnotationKind::Context
582                                .span(self.catch_all.into())
583                                .label("catch-all specified here"),
584                        ),
585                ),
586            Group::with_title(Level::INFO.secondary_title(INFO_TEXT)),
587            Group::with_title(Level::HELP.secondary_title(
588                "remove the catch-all from the enum or don't use it as repeat source",
589            )),
590        ]
591        .to_vec()
592    }
593}
594
595#[derive(Debug)]
596pub struct RepeatMathOverflow {
597    pub repeat_span: Span,
598    pub max_value_span: Span,
599    pub max_value: i128,
600    pub stride: i128,
601}
602
603impl Diagnostic for RepeatMathOverflow {
604    fn is_error(&self) -> bool {
605        true
606    }
607
608    fn as_report<'a>(&'a self, source: &'a str, path: &'a str) -> Vec<Group<'a>> {
609        const INFO_TEXT: &str = "repeat math is done with `i32` integers to keep the runtime lean, so all calculations need to fit in a limited range";
610
611        [
612            Level::ERROR.primary_title("repeat math overflow").element(
613                Snippet::source(source)
614                    .path(path)
615                    .annotation(AnnotationKind::Primary.span(self.repeat_span.into()).label(
616                        format!(
617                            "repeat calculation overflows the allowed `i32` range at {}",
618                            self.max_value * self.stride
619                        ),
620                    ))
621                    .annotation(
622                        AnnotationKind::Context
623                            .span(self.max_value_span.into())
624                            .label(format!("biggest index of {} specified here, which gets multiplied with the stride", self.max_value)),
625                    ),
626            ),
627            Group::with_title(Level::INFO.secondary_title(INFO_TEXT)),
628        ]
629        .to_vec()
630    }
631}
632
633#[derive(Debug)]
634pub struct ExternInvalidBaseType {
635    pub extern_name: Span,
636    pub base_type: Option<Span>,
637}
638
639impl Diagnostic for ExternInvalidBaseType {
640    fn is_error(&self) -> bool {
641        true
642    }
643
644    fn as_report<'a>(&'a self, source: &'a str, path: &'a str) -> Vec<Group<'a>> {
645        const INFO_TEXT: &str = "externs must specify a fixed size integer type as their base type";
646
647        [
648            Level::ERROR
649                .primary_title("invalid base type for extern object")
650                .element(
651                    Snippet::source(source)
652                        .path(path)
653                        .annotation(
654                            if self.base_type.is_some() {
655                                AnnotationKind::Context
656                            } else {
657                                AnnotationKind::Primary
658                            }
659                            .span(self.extern_name.into())
660                            .label(if self.base_type.is_some() {
661                                "extern has an invalid base type"
662                            } else {
663                                "extern has no base type"
664                            }),
665                        )
666                        .annotations(self.base_type.map(|base_type| {
667                            AnnotationKind::Primary
668                                .span(base_type.into())
669                                .label("invalid base type")
670                        })),
671                ),
672            Group::with_title(Level::INFO.secondary_title(INFO_TEXT)),
673        ]
674        .to_vec()
675    }
676}
677
678#[derive(Debug)]
679pub struct ExternInvalidSizeBits {
680    pub extern_name: Span,
681    pub size_bits: Span,
682    pub reason: Cow<'static, str>,
683}
684
685impl Diagnostic for ExternInvalidSizeBits {
686    fn is_error(&self) -> bool {
687        true
688    }
689
690    fn as_report<'a>(&'a self, source: &'a str, path: &'a str) -> Vec<Group<'a>> {
691        [Level::ERROR
692            .primary_title("invalid size-bits value for extern object")
693            .element(
694                Snippet::source(source)
695                    .path(path)
696                    .annotation(
697                        AnnotationKind::Primary
698                            .span(self.size_bits.into())
699                            .label(&self.reason),
700                    )
701                    .annotation(AnnotationKind::Visible.span(self.extern_name.into())),
702            )]
703        .to_vec()
704    }
705}
706
707#[derive(Debug)]
708pub struct DifferentBaseTypes {
709    pub field: Span,
710    pub field_base_type: BaseType,
711    pub conversion: Span,
712    pub conversion_object: Span,
713    pub conversion_base_type: BaseType,
714}
715
716impl Diagnostic for DifferentBaseTypes {
717    fn is_error(&self) -> bool {
718        true
719    }
720
721    fn as_report<'a>(&'a self, source: &'a str, path: &'a str) -> Vec<Group<'a>> {
722        const INFO_TEXT: &str = "conversions can only happen when the same base type is shared";
723
724        [
725            Level::ERROR
726                .primary_title("field and conversion use different base types")
727                .element(
728                    Snippet::source(source)
729                        .path(path)
730                        .annotation(
731                            AnnotationKind::Context
732                                .span(self.conversion.into())
733                                .label("conversion specified here"),
734                        )
735                        .annotation(
736                            AnnotationKind::Primary
737                                .span(self.field.into())
738                                .label(format!("field uses base type: {}", self.field_base_type)),
739                        )
740                        .annotation(
741                            AnnotationKind::Primary
742                                .span(self.conversion_object.into())
743                                .label(format!(
744                                    "conversion object uses base type: {}",
745                                    self.conversion_base_type
746                                )),
747                        ),
748                ),
749            // TODO: Add help with patch
750            Group::with_title(Level::INFO.secondary_title(INFO_TEXT)),
751        ]
752        .to_vec()
753    }
754}
755
756// TODO: Split in multiple error types
757#[derive(Debug)]
758pub struct InvalidInfallibleConversion {
759    pub field: Span,
760    pub conversion: Span,
761    pub context: Vec<Spanned<Cow<'static, str>>>,
762    pub existing_type_specifier_content: String,
763}
764
765impl Diagnostic for InvalidInfallibleConversion {
766    fn is_error(&self) -> bool {
767        true
768    }
769
770    fn as_report<'a>(&'a self, source: &'a str, path: &'a str) -> Vec<Group<'a>> {
771        [
772            Level::ERROR
773                .primary_title("invalid infallible conversion")
774                .element(
775                    Snippet::source(source)
776                        .path(path)
777                        .annotation(
778                            AnnotationKind::Primary
779                                .span(self.conversion.into())
780                                .label("conversion specified here"),
781                        )
782                        .annotations(
783                            self.context.iter().map(|c| {
784                                AnnotationKind::Context.span(c.span.into()).label(&c.value)
785                            }),
786                        )
787                        .annotation(AnnotationKind::Visible.span(self.field.into())),
788                ),
789            // TODO: Add patch
790            Group::with_title(Level::HELP.secondary_title("mark the conversion fallible")),
791            Group::with_title(
792                Level::HELP
793                    .secondary_title("make the conversion type support infallible conversion"),
794            ),
795        ]
796        .to_vec()
797    }
798}
799
800#[derive(Debug)]
801pub struct ConversionTypeTooBig {
802    pub field: Span,
803    pub field_address: Span,
804    pub conversion_type: Span,
805    pub conversion: Span,
806    pub field_len: u64,
807    pub conversion_len: u64,
808}
809
810impl Diagnostic for ConversionTypeTooBig {
811    fn is_error(&self) -> bool {
812        true
813    }
814
815    fn as_report<'a>(&'a self, source: &'a str, path: &'a str) -> Vec<Group<'a>> {
816        const INFO_TEXT: &str = "a field can only convert to types of equal length or smaller";
817
818        [
819            Level::ERROR
820                .primary_title("conversion type too big for field")
821                .element(
822                    Snippet::source(source)
823                        .path(path)
824                        .annotation(AnnotationKind::Visible.span(self.field.into()))
825                        .annotation(
826                            AnnotationKind::Primary
827                                .span(self.field_address.into())
828                                .label(format!("field is {} bits", self.field_len)),
829                        )
830                        .annotation(
831                            AnnotationKind::Primary
832                                .span(self.conversion_type.into())
833                                .label(format!("target type is {} bits", self.conversion_len)),
834                        )
835                        .annotation(
836                            AnnotationKind::Context
837                                .span(self.conversion.into())
838                                .label("field specifies a conversion type here"),
839                        ),
840                ),
841            Group::with_title(Level::INFO.secondary_title(INFO_TEXT)),
842        ]
843        .to_vec()
844    }
845}
846
847#[derive(Debug)]
848pub struct UnspecifiedByteOrder {
849    pub fieldset_name: Span,
850    pub properties_span: Option<Span>,
851}
852
853impl Diagnostic for UnspecifiedByteOrder {
854    fn is_error(&self) -> bool {
855        true
856    }
857
858    fn as_report<'a>(&'a self, source: &'a str, path: &'a str) -> Vec<Group<'a>> {
859        [
860            Level::ERROR
861                .primary_title("unspecified byte order")
862                .element(
863                    Snippet::source(source).path(path).annotation(
864                        AnnotationKind::Primary
865                            .span(self.fieldset_name.into())
866                            .label("fieldset requires a byte order, but none is specified"),
867                    ),
868                ),
869            Level::HELP.secondary_title(
870                "specify the byte order on the fieldset or add a default byte order on the device",
871            )
872            .elements( self.properties_span.map(|properties_span| {
873                Snippet::source(source).path(path).patch(
874                    Patch::new(properties_span.start..properties_span.start, "byte-order: LE,\n")
875                )}
876            )),
877            Group::with_title(Level::NOTE.secondary_title(
878                "the fieldset spans multiple bytes, so it needs to have byte ordering specified",
879            )),
880            Group::with_title(Level::INFO.secondary_title(
881                "byte order is important for any multi-byte value. It has no default, so it needs to be manually specified",
882            )),
883        ]
884        .to_vec()
885    }
886}
887
888#[derive(Debug)]
889pub struct UnspecifiedAccess {
890    pub object_name: Span,
891    pub short_property: bool,
892    pub properties_span: Option<Span>,
893}
894
895impl Diagnostic for UnspecifiedAccess {
896    fn is_error(&self) -> bool {
897        true
898    }
899
900    fn as_report<'a>(&'a self, source: &'a str, path: &'a str) -> Vec<Group<'a>> {
901        [
902            Level::ERROR.primary_title("unspecified access").element(
903                Snippet::source(source).path(path).annotation(
904                    AnnotationKind::Primary
905                        .span(self.object_name.into())
906                        .label("object requires an access to be specified, but none is"),
907                ),
908            ),
909            Level::HELP
910                .secondary_title(
911                    "specify the access on the object or add a `default-access` to a parent object",
912                )
913                .elements(self.properties_span.map(|properties_span| {
914                    Snippet::source(source).path(path).patch(Patch::new(
915                        if self.short_property {
916                            properties_span.end..properties_span.end
917                        } else {
918                            properties_span.start..properties_span.start
919                        },
920                        if self.short_property {
921                            " RW"
922                        } else {
923                            "access: RW,\n"
924                        },
925                    ))
926                })),
927        ]
928        .to_vec()
929    }
930}
931
932#[derive(Debug)]
933pub struct ResetValueIntTooBig {
934    pub register_context: Span,
935    pub reset_value: Span,
936    pub reset_value_size_bytes: u32,
937    pub register_size_bytes: u32,
938}
939
940impl Diagnostic for ResetValueIntTooBig {
941    fn is_error(&self) -> bool {
942        true
943    }
944
945    fn as_report<'a>(&'a self, source: &'a str, path: &'a str) -> Vec<Group<'a>> {
946        const INFO_TEXT: &str = "reset values cannot be bigger than their fieldset";
947
948        [
949            Level::ERROR.primary_title("reset value too big").element(
950                Snippet::source(source)
951                    .path(path)
952                    .annotation(AnnotationKind::Primary.span(self.reset_value.into()).label(
953                        format!(
954                            "the reset value is specified with {} bytes, but the register only has {}",
955                            self.reset_value_size_bytes, self.register_size_bytes
956                        ),
957                    ))
958                    .annotation(AnnotationKind::Visible.span(self.register_context.into())),
959            ),
960            Group::with_title(Level::INFO.secondary_title(INFO_TEXT)),
961        ]
962        .to_vec()
963    }
964}
965
966#[derive(Debug)]
967pub struct ResetValueArrayWrongSize {
968    pub register_context: Span,
969    pub reset_value: Span,
970    pub reset_value_size_bytes: u32,
971    pub register_size_bytes: u32,
972}
973
974impl Diagnostic for ResetValueArrayWrongSize {
975    fn is_error(&self) -> bool {
976        true
977    }
978
979    fn as_report<'a>(&'a self, source: &'a str, path: &'a str) -> Vec<Group<'a>> {
980        const INFO_TEXT: &str = "reset values must have the same size as their associated register";
981
982        [
983            Level::ERROR
984                .primary_title("reset value wrong size")
985                .element(
986                Snippet::source(source)
987                    .path(path)
988                    .annotation(AnnotationKind::Primary.span(self.reset_value.into()).label(
989                        format!(
990                            "the reset value is specified with {} bytes while the register has {}",
991                            self.reset_value_size_bytes, self.register_size_bytes
992                        ),
993                    ))
994                    .annotation(AnnotationKind::Visible.span(self.register_context.into())),
995            ),
996            Group::with_title(Level::INFO.secondary_title(INFO_TEXT)),
997        ]
998        .to_vec()
999    }
1000}
1001
1002#[derive(Debug)]
1003pub struct BoolFieldTooLarge {
1004    pub base_type: Option<Span>,
1005    pub address: Span,
1006    pub address_bits: u32,
1007    pub address_start: u32,
1008    pub field_set_context: Span,
1009}
1010
1011impl Diagnostic for BoolFieldTooLarge {
1012    fn is_error(&self) -> bool {
1013        true
1014    }
1015
1016    fn as_report<'a>(&'a self, source: &'a str, path: &'a str) -> Vec<Group<'a>> {
1017        [
1018            Level::ERROR.primary_title("bool field too large").element(
1019                Snippet::source(source).path(path).annotations(
1020                    [
1021                        Some(
1022                            AnnotationKind::Primary
1023                                .span(self.address.into())
1024                                .label(format!("address is {} bits", self.address_bits)),
1025                        ),
1026                        self.base_type.map(|base_type| {
1027                            AnnotationKind::Context
1028                                .span(base_type.into())
1029                                .label("bool base type set here")
1030                        }),
1031                        Some(AnnotationKind::Visible.span(self.field_set_context.into())),
1032                    ]
1033                    .into_iter()
1034                    .flatten(),
1035                ),
1036            ),
1037            Level::HELP
1038                .secondary_title("a field with a `bool` base type can only be 1 bit large")
1039                .element(Snippet::source(source).path(path).patch(Patch::new(
1040                    self.address.into(),
1041                    format!("{}:{}", self.address_start, self.address_start),
1042                )))
1043                .element(Snippet::source(source).path(path).patch(Patch::new(
1044                    self.address.into(),
1045                    format!("{}", self.address_start),
1046                ))),
1047        ]
1048        .to_vec()
1049    }
1050}
1051
1052#[derive(Debug)]
1053pub struct FieldAddressExceedsFieldsetSize {
1054    pub address: Span,
1055    pub max_field_end: i128,
1056    pub repeat_offset: Option<i128>,
1057    pub fieldset_size_span: Span,
1058    pub fieldset_size_bits: u32,
1059}
1060
1061impl FieldAddressExceedsFieldsetSize {
1062    fn get_repeat_message(&self) -> String {
1063        match self.repeat_offset {
1064            Some(repeat_offset) => format!(" with a repeat offset of {repeat_offset}"),
1065            None => String::new(),
1066        }
1067    }
1068}
1069
1070impl Diagnostic for FieldAddressExceedsFieldsetSize {
1071    fn is_error(&self) -> bool {
1072        true
1073    }
1074
1075    fn as_report<'a>(&'a self, source: &'a str, path: &'a str) -> Vec<Group<'a>> {
1076        [
1077            Level::ERROR
1078                .primary_title("field address exceeds fieldset size")
1079                .element(
1080                    Snippet::source(source)
1081                        .path(path)
1082                        .annotation(AnnotationKind::Primary.span(self.address.into()).label(
1083                            format!(
1084                                "address goes up to {}{}",
1085                                self.max_field_end,
1086                                self.get_repeat_message()
1087                            ),
1088                        ))
1089                        .annotation(
1090                            AnnotationKind::Context
1091                                .span(self.fieldset_size_span.into())
1092                                .label(format!(
1093                                    "The fieldset is only {} bits",
1094                                    self.fieldset_size_bits
1095                                )),
1096                        ),
1097                ),
1098            Group::with_title(Level::INFO.secondary_title(
1099                "fields, including all repeats, must be fully contained in a fieldset",
1100            )),
1101        ]
1102        .to_vec()
1103    }
1104}
1105
1106#[derive(Debug)]
1107pub struct FieldAddressNegative {
1108    pub address: Span,
1109    pub min_field_start: i128,
1110    pub repeat_offset: Option<i128>,
1111    pub field_set_context: Span,
1112}
1113
1114impl FieldAddressNegative {
1115    fn get_repeat_message(&self) -> Cow<'static, str> {
1116        match self.repeat_offset {
1117            Some(repeat_offset) => format!(" with a repeat offset of {repeat_offset}").into(),
1118            None => "".into(),
1119        }
1120    }
1121}
1122
1123impl Diagnostic for FieldAddressNegative {
1124    fn is_error(&self) -> bool {
1125        true
1126    }
1127
1128    fn as_report<'a>(&'a self, source: &'a str, path: &'a str) -> Vec<Group<'a>> {
1129        [
1130            Level::ERROR
1131                .primary_title("field address is negative")
1132                .element(
1133                    Snippet::source(source)
1134                        .path(path)
1135                        .annotation(AnnotationKind::Primary.span(self.address.into()).label(
1136                            format!(
1137                                "address goes down to {}{}",
1138                                self.min_field_start,
1139                                self.get_repeat_message()
1140                            ),
1141                        ))
1142                        .annotation(AnnotationKind::Visible.span(self.field_set_context.into())),
1143                ),
1144            Group::with_title(Level::INFO.secondary_title(
1145                "fields, including all repeats, must be fully contained in a fieldset",
1146            )),
1147        ]
1148        .to_vec()
1149    }
1150}
1151
1152#[derive(Debug)]
1153pub struct OverlappingFields {
1154    pub field_address_1: Span,
1155    pub repeat_offset_1: Option<i128>,
1156    pub field_address_start_1: i128,
1157    pub field_address_end_1: i128,
1158    pub field_address_2: Span,
1159    pub repeat_offset_2: Option<i128>,
1160    pub field_address_start_2: i128,
1161    pub field_address_end_2: i128,
1162
1163    pub field_set_context: Span,
1164}
1165
1166impl OverlappingFields {
1167    fn get_repeat_message_1(&self) -> Cow<'static, str> {
1168        match self.repeat_offset_1 {
1169            Some(repeat_offset) => format!(" with a repeat offset of {repeat_offset}").into(),
1170            None => "".into(),
1171        }
1172    }
1173    fn get_repeat_message_2(&self) -> Cow<'static, str> {
1174        match self.repeat_offset_2 {
1175            Some(repeat_offset) => format!(" with a repeat offset of {repeat_offset}").into(),
1176            None => "".into(),
1177        }
1178    }
1179}
1180
1181impl Diagnostic for OverlappingFields {
1182    fn is_error(&self) -> bool {
1183        false
1184    }
1185
1186    fn as_report<'a>(&'a self, source: &'a str, path: &'a str) -> Vec<Group<'a>> {
1187        const HELP_TEXT: &str = "if overlap is intended, the warning can be suppressed by allowing overlap on both fields";
1188        const INFO_TEXT: &str = "overlapping fields are usually the result of a copy paste mistake. This warning exists to alert to that possibility";
1189
1190        [
1191            Level::WARNING.primary_title("overlapping fields").element(
1192                Snippet::source(source)
1193                    .path(path)
1194                    .annotation(
1195                        AnnotationKind::Primary
1196                            .span(self.field_address_1.into())
1197                            .label(format!(
1198                                "Field sits at address range @{}:{}{}",
1199                                self.field_address_end_1 - 1,
1200                                self.field_address_start_1,
1201                                self.get_repeat_message_1()
1202                            )),
1203                    )
1204                    .annotation(
1205                        AnnotationKind::Primary
1206                            .span(self.field_address_2.into())
1207                            .label(format!(
1208                                "Field sits at address range @{}:{}{}",
1209                                self.field_address_end_2 - 1,
1210                                self.field_address_start_2,
1211                                self.get_repeat_message_2()
1212                            )),
1213                    )
1214                    .annotation(AnnotationKind::Visible.span(self.field_set_context.into())),
1215                // TODO: Add context annotation for where the repeats are defined
1216            ),
1217            // TODO: Add patch
1218            Group::with_title(Level::HELP.secondary_title(HELP_TEXT)),
1219            Group::with_title(Level::NOTE.secondary_title(INFO_TEXT)),
1220        ]
1221        .to_vec()
1222    }
1223}
1224
1225#[derive(Debug)]
1226pub struct AddressTypeUndefined {
1227    pub object_name: Span,
1228    pub device: Span,
1229    pub properties_span: Option<Span>,
1230    pub object_type: &'static str,
1231}
1232
1233impl Diagnostic for AddressTypeUndefined {
1234    fn is_error(&self) -> bool {
1235        true
1236    }
1237
1238    fn as_report<'a>(&'a self, source: &'a str, path: &'a str) -> Vec<Group<'a>> {
1239        vec![
1240            Level::ERROR
1241            .primary_title(format!("{} address type not defined", self.object_type))
1242            .element(
1243                Snippet::source(source)
1244                    .path(path)
1245                    .annotation(
1246                        AnnotationKind::Primary
1247                            .span(self.device.into())
1248                            .label(format!(
1249                                "this device doesn't define a {}-address-type",
1250                                self.object_type
1251                            )),
1252                    )
1253                    .annotation(
1254                        AnnotationKind::Context
1255                            .span(self.object_name.into())
1256                            .label(format!("{} object defined here", self.object_type)),
1257                    ),
1258            ),
1259            Level::HELP.secondary_title(
1260                "add the address type as a global default or as config on the device the object is defined in"
1261            ).elements(
1262                self.properties_span.map(|properties_span| {
1263                    Snippet::source(source).path(path).patch(
1264                        Patch::new(properties_span.start..properties_span.start, format!("{}-address-type: u16\n", self.object_type))
1265                    )
1266                })
1267            ),
1268            Group::with_title(
1269                Level::INFO.secondary_title("device-driver is agnostic to the address types being used. As such, it must be manually specified")
1270            ),
1271        ]
1272    }
1273}
1274
1275#[derive(Debug)]
1276pub struct AddressOutOfRange {
1277    pub object: Span,
1278    pub address: Span,
1279    pub address_value_min: i128,
1280    pub address_value_max: i128,
1281    pub address_type_config: Span,
1282    pub address_type: Integer,
1283}
1284
1285impl Diagnostic for AddressOutOfRange {
1286    fn is_error(&self) -> bool {
1287        true
1288    }
1289
1290    fn as_report<'a>(&'a self, source: &'a str, path: &'a str) -> Vec<Group<'a>> {
1291        vec![
1292            Level::ERROR
1293                .primary_title("address out of range")
1294                .element(
1295                    Snippet::source(source)
1296                        .path(path)
1297                        .annotation(AnnotationKind::Primary.span(self.address.into()).label(
1298                            if self.address_value_min == self.address_value_max {
1299                                format!("address has value: {}", self.address_value_max,)
1300                            } else {
1301                                format!(
1302                                    "address ranges from {} to {}",
1303                                    self.address_value_min, self.address_value_max,
1304                                )
1305                            },
1306                        ))
1307                        .annotation(AnnotationKind::Visible.span(self.object.into())),
1308                )
1309                .element(
1310                    Snippet::source(source).path(path).annotation(
1311                        AnnotationKind::Context
1312                            .span(self.address_type_config.into())
1313                            .label(format!(
1314                                "address type supports a range of {} to {}",
1315                                self.address_type.min_value(),
1316                                self.address_type.max_value()
1317                            )),
1318                    ),
1319                ),
1320            if let Some(fitting_integer) =
1321                Integer::find_smallest(self.address_value_min, self.address_value_max, 0)
1322            {
1323                Level::HELP
1324                    .secondary_title("use an address type that fits the whole range being used")
1325                    .element(Snippet::source(source).path(path).patch(Patch::new(
1326                        self.address_type_config.into(),
1327                        fitting_integer.to_string(),
1328                    )))
1329            } else {
1330                Group::with_title(
1331                    Level::HELP
1332                        .secondary_title("address is too big to fit any possible address type"),
1333                )
1334            },
1335        ]
1336    }
1337}
1338
1339#[derive(Debug)]
1340pub struct AddressOverlap {
1341    pub address: i128,
1342    pub object_1: Span,
1343    pub object_1_address: Span,
1344    pub object_1_size: Span,
1345    pub repeat_offset_1: Option<i128>,
1346    pub object_2: Span,
1347    pub object_2_address: Span,
1348    pub object_2_size: Span,
1349    pub repeat_offset_2: Option<i128>,
1350}
1351
1352impl Diagnostic for AddressOverlap {
1353    fn is_error(&self) -> bool {
1354        false
1355    }
1356
1357    fn as_report<'a>(&'a self, source: &'a str, path: &'a str) -> Vec<Group<'a>> {
1358        let object_1_message = format!(
1359            "object 1 overlaps with other object 2{}",
1360            if let Some(repeat_offset) = self.repeat_offset_1 {
1361                format!(" at repeat offset {repeat_offset}")
1362            } else {
1363                String::new()
1364            }
1365        );
1366        let object_2_message = format!(
1367            "object 2 overlaps with other object 1{}",
1368            if let Some(repeat_offset) = self.repeat_offset_2 {
1369                format!(" at repeat offset {repeat_offset}")
1370            } else {
1371                String::new()
1372            }
1373        );
1374
1375        const HELP_TEXT: &str = "if overlap is intended, the warning can be suppressed by allowing overlap on both objects";
1376        const INFO_TEXT: &str = "overlapping objects are usually the result of a copy paste mistake. This warning exists to alert to that possibility";
1377
1378        [
1379            Level::WARNING
1380                .primary_title(format!(
1381                    "address overlap at {} ({:#X})",
1382                    self.address, self.address
1383                ))
1384                .element(
1385                    Snippet::source(source)
1386                        .path(path)
1387                        .annotation(
1388                            AnnotationKind::Primary
1389                                .span(self.object_1.into())
1390                                .label(object_1_message),
1391                        )
1392                        .annotation(
1393                            AnnotationKind::Context
1394                                .span(self.object_1_address.into())
1395                                .label("address 1 set here"),
1396                        )
1397                        .annotations(
1398                            (!self.object_1_size.is_empty()).then_some(
1399                                AnnotationKind::Context
1400                                    .span(self.object_1_size.into())
1401                                    .label("size 1 set here"),
1402                            ),
1403                        ), // TODO: Add context annotation for where the repeat is defined
1404                )
1405                .element(
1406                    Snippet::source(source)
1407                        .path(path)
1408                        .annotation(
1409                            AnnotationKind::Primary
1410                                .span(self.object_2.into())
1411                                .label(object_2_message),
1412                        )
1413                        .annotation(
1414                            AnnotationKind::Context
1415                                .span(self.object_2_address.into())
1416                                .label("address 2 set here"),
1417                        )
1418                        .annotations(
1419                            (!self.object_2_size.is_empty()).then_some(
1420                                AnnotationKind::Context
1421                                    .span(self.object_2_size.into())
1422                                    .label("size 2 set here"),
1423                            ),
1424                        ), // TODO: Add context annotation for where the repeat is defined
1425                ),
1426            // TODO: Add patch
1427            Group::with_title(Level::HELP.secondary_title(HELP_TEXT)),
1428            Group::with_title(Level::NOTE.secondary_title(INFO_TEXT)),
1429        ]
1430        .to_vec()
1431    }
1432}
1433
1434#[derive(Debug)]
1435pub struct InvalidIdentifier {
1436    pub error: identifier::Error,
1437    pub identifier: Span,
1438}
1439
1440impl InvalidIdentifier {
1441    pub fn new(error: identifier::Error, identifier: Span) -> Self {
1442        Self { error, identifier }
1443    }
1444}
1445
1446impl Diagnostic for InvalidIdentifier {
1447    fn is_error(&self) -> bool {
1448        true
1449    }
1450
1451    fn as_report<'a>(&'a self, source: &'a str, path: &'a str) -> Vec<Group<'a>> {
1452        const INFO_TEXT: &str = "identifiers are split into words using the 'word-boundaries'.\n\
1453After the split the first character of the first word must be a unicode XID start character.\n\
1454All other characters must be a unicode XID continue character.\n\
1455\n\
1456Identifiers must also be able to be converted to different casings. That means the split words must not contain `-` or `_`,\n\
1457which in practice means the word-boundaries should always include those characters.";
1458
1459        let annotation = match &self.error {
1460            identifier::Error::Empty => AnnotationKind::Primary
1461                .span(self.identifier.into())
1462                .label("identifier is empty"),
1463            identifier::Error::EmptyAfterSplits => AnnotationKind::Primary
1464                .span(self.identifier.into())
1465                .label("identifier is empty after word split"),
1466            identifier::Error::InvalidCharacter {
1467                byte_offset: offset,
1468                invalid_char: character,
1469            } if !self.identifier.is_empty() => AnnotationKind::Primary
1470                .span(
1471                    self.identifier.start + offset
1472                        ..self.identifier.start + offset + character.len_utf8(),
1473                )
1474                .label(format!(
1475                    "`{character}` (or `{}`) is not a valid character",
1476                    character.escape_unicode()
1477                )),
1478            identifier::Error::InvalidCharacter {
1479                byte_offset: _,
1480                invalid_char: character,
1481            } => AnnotationKind::Primary
1482                .span(self.identifier.into())
1483                .label(format!(
1484                    "`{character}` (or `{}`) is not a valid character",
1485                    character.escape_unicode()
1486                )),
1487            e @ identifier::Error::CannotConvert { .. } => AnnotationKind::Primary
1488                .span(self.identifier.into())
1489                .label(e.to_string()),
1490        };
1491
1492        [
1493            Level::ERROR
1494                .primary_title("invalid identifier")
1495                .element(Snippet::source(source).path(path).annotation(annotation)),
1496            Group::with_title(Level::INFO.secondary_title(INFO_TEXT)),
1497        ]
1498        .to_vec()
1499    }
1500}
1501
1502#[derive(Debug)]
1503pub struct InvalidAutoIdentifier {
1504    pub auto_identifier: Span,
1505}
1506
1507impl Diagnostic for InvalidAutoIdentifier {
1508    fn is_error(&self) -> bool {
1509        true
1510    }
1511
1512    fn as_report<'a>(&'a self, source: &'a str, path: &'a str) -> Vec<Group<'a>> {
1513        const INFO_TEXT: &str = "auto identifiers can only be used in places where there's a parent node of which the name can be taken";
1514
1515        [
1516            Level::ERROR.primary_title("invalid identifier").element(
1517                Snippet::source(source).path(path).annotation(
1518                    AnnotationKind::Primary
1519                        .span(self.auto_identifier.into())
1520                        .label("auto identifier can't be used here"),
1521                ),
1522            ),
1523            Group::with_title(Level::INFO.secondary_title(INFO_TEXT)),
1524        ]
1525        .to_vec()
1526    }
1527}
1528
1529#[derive(Debug)]
1530pub struct ParsingError {
1531    pub reason: String,
1532    pub span: Span,
1533}
1534
1535impl Diagnostic for ParsingError {
1536    fn is_error(&self) -> bool {
1537        true
1538    }
1539
1540    fn as_report<'a>(&'a self, source: &'a str, path: &'a str) -> Vec<Group<'a>> {
1541        [Level::ERROR.primary_title("parsing error").element(
1542            Snippet::source(source).path(path).annotation(
1543                AnnotationKind::Primary
1544                    .span(self.span.into())
1545                    .label(&self.reason),
1546            ),
1547        )]
1548        .to_vec()
1549    }
1550}
1551
1552#[derive(Debug)]
1553pub struct UnknownNodeType {
1554    pub node_type: Span,
1555    pub allowed_node_types: Vec<NodeType>,
1556}
1557
1558impl Diagnostic for UnknownNodeType {
1559    fn is_error(&self) -> bool {
1560        true
1561    }
1562
1563    fn as_report<'a>(&'a self, source: &'a str, path: &'a str) -> Vec<Group<'a>> {
1564        [Level::ERROR.primary_title("Unknown node type").element(
1565            Snippet::source(source).path(path).annotation(
1566                AnnotationKind::Primary
1567                    .span(self.node_type.into())
1568                    .label(format!(
1569                        "expected one of: {}",
1570                        self.allowed_node_types.iter().join(", ")
1571                    )),
1572            ),
1573        )]
1574        .to_vec()
1575    }
1576}
1577
1578#[derive(Debug)]
1579pub struct InvalidPropertyName {
1580    pub property: Span,
1581    pub node_type: Spanned<NodeType>,
1582    pub expected_names: Vec<&'static str>,
1583}
1584
1585impl Diagnostic for InvalidPropertyName {
1586    fn is_error(&self) -> bool {
1587        true
1588    }
1589
1590    fn as_report<'a>(&'a self, source: &'a str, path: &'a str) -> Vec<Group<'a>> {
1591        [Level::ERROR
1592            .primary_title(format!(
1593                "invalid property name for `{}` nodes",
1594                self.node_type
1595            ))
1596            .element(Snippet::source(source).path(path).annotation(
1597                AnnotationKind::Primary.span(self.property.into()).label(
1598                    if self.expected_names.is_empty() {
1599                        "no named properties are expected".into()
1600                    } else {
1601                        format!("expected one of: {}", self.expected_names.join(", "))
1602                    },
1603                ),
1604            ))]
1605        .to_vec()
1606    }
1607}
1608
1609#[derive(Debug)]
1610pub struct InvalidExpressionType {
1611    pub expression: Spanned<String>,
1612    pub node_type: Spanned<NodeType>,
1613    pub valid_expression_types: Vec<String>,
1614    pub valid_expression_values: Vec<Cow<'static, str>>,
1615}
1616
1617impl Diagnostic for InvalidExpressionType {
1618    fn is_error(&self) -> bool {
1619        true
1620    }
1621
1622    fn as_report<'a>(&'a self, source: &'a str, path: &'a str) -> Vec<Group<'a>> {
1623        let mut report = [Level::ERROR
1624            .primary_title(format!(
1625                "invalid expression type for this property in {} nodes",
1626                self.node_type
1627            ))
1628            .element(
1629                Snippet::source(source).path(path).annotation(
1630                    AnnotationKind::Primary
1631                        .span(self.expression.span.into())
1632                        .label(format!(
1633                            "got {}, expected one of: {}",
1634                            self.expression,
1635                            self.valid_expression_types.join(", ")
1636                        )),
1637                ),
1638            )]
1639        .to_vec();
1640
1641        for (name, value) in self
1642            .valid_expression_types
1643            .iter()
1644            .zip(&self.valid_expression_values)
1645        {
1646            report.push(
1647                Level::HELP
1648                    .secondary_title(format!("change to a {name} expression"))
1649                    .element(
1650                        Snippet::source(source)
1651                            .path(path)
1652                            .patch(Patch::new(self.expression.span.into(), &**value)),
1653                    ),
1654            );
1655        }
1656
1657        report
1658    }
1659}
1660
1661#[derive(Debug)]
1662pub struct DuplicateProperty {
1663    pub original: Span,
1664    pub duplicate: Span,
1665}
1666
1667impl Diagnostic for DuplicateProperty {
1668    fn is_error(&self) -> bool {
1669        true
1670    }
1671
1672    fn as_report<'a>(&'a self, source: &'a str, path: &'a str) -> Vec<Group<'a>> {
1673        [Level::ERROR.primary_title("duplicate property").element(
1674            Snippet::source(source)
1675                .path(path)
1676                .annotation(
1677                    AnnotationKind::Context
1678                        .span(self.original.into())
1679                        .label("first occurrence"),
1680                )
1681                .annotation(
1682                    AnnotationKind::Primary
1683                        .span(self.duplicate.into())
1684                        .label("duplicate"),
1685                ),
1686        )]
1687        .to_vec()
1688    }
1689}
1690
1691#[derive(Debug)]
1692pub struct InvalidNodeType {
1693    pub node_type: Span,
1694    pub parent_node_type: Option<Spanned<NodeType>>,
1695    pub allowed_node_types: Vec<NodeType>,
1696}
1697
1698impl Diagnostic for InvalidNodeType {
1699    fn is_error(&self) -> bool {
1700        true
1701    }
1702
1703    fn as_report<'a>(&'a self, source: &'a str, path: &'a str) -> Vec<Group<'a>> {
1704        [
1705            Level::ERROR.primary_title("invalid node type").element(
1706                Snippet::source(source)
1707                    .path(path)
1708                    .annotation(
1709                        AnnotationKind::Primary.span(self.node_type.into()).label(
1710                            if let Some(parent_node_type) = self.parent_node_type {
1711                                format!(
1712                                    "node type can't be used as a sub-node of a {parent_node_type}",
1713                                )
1714                            } else {
1715                                "node type can't be used as the root".into()
1716                            },
1717                        ),
1718                    )
1719                    .annotations(self.parent_node_type.map(|pnt| {
1720                        AnnotationKind::Context
1721                            .span(pnt.span.into())
1722                            .label("in this node")
1723                    })),
1724            ),
1725            Group::with_title(Level::NOTE.secondary_title(format!(
1726                "valid node types are: {}",
1727                self.allowed_node_types.iter().join(", ")
1728            ))),
1729        ]
1730        .to_vec()
1731    }
1732}
1733
1734#[derive(Debug)]
1735pub struct MissingRequiredProperty {
1736    pub node_type: Spanned<NodeType>,
1737    pub property_name: String,
1738    pub short: bool,
1739    pub allowed_property_types: Vec<String>,
1740    pub example_values: Vec<Cow<'static, str>>,
1741    pub properties_span: Option<Span>,
1742}
1743
1744impl Diagnostic for MissingRequiredProperty {
1745    fn is_error(&self) -> bool {
1746        true
1747    }
1748
1749    fn as_report<'a>(&'a self, source: &'a str, path: &'a str) -> Vec<Group<'a>> {
1750        let label = if self.short {
1751            format!(
1752                "missing short property for `{}`, with one of these expression types: {}",
1753                self.property_name,
1754                self.allowed_property_types.join(", ")
1755            )
1756        } else {
1757            format!(
1758                "missing property `{}`, with one of these expression types: {}",
1759                self.property_name,
1760                self.allowed_property_types.join(", ")
1761            )
1762        };
1763
1764        [Level::ERROR
1765            .primary_title(format!(
1766                "{} node is missing a required property",
1767                self.node_type
1768            ))
1769            .element(
1770                Snippet::source(source).path(path).annotation(
1771                    AnnotationKind::Primary
1772                        .span(self.node_type.span.into())
1773                        .label(label),
1774                ),
1775            )
1776            .elements(self.example_values.iter().flat_map(|example_value| {
1777                self.properties_span.map(|properties_span| {
1778                    Snippet::source(source).path(path).patch(Patch::new(
1779                        if self.short {
1780                            properties_span.end..properties_span.end
1781                        } else {
1782                            properties_span.start..properties_span.start
1783                        },
1784                        if self.short {
1785                            format!(" {example_value}")
1786                        } else {
1787                            format!("{}: {example_value},\n", self.property_name)
1788                        },
1789                    ))
1790                })
1791            }))]
1792        .to_vec()
1793    }
1794}
1795
1796#[derive(Debug)]
1797pub struct InvalidSubnode {
1798    pub node_type: Spanned<NodeType>,
1799    pub subnode: Span,
1800}
1801
1802impl Diagnostic for InvalidSubnode {
1803    fn is_error(&self) -> bool {
1804        true
1805    }
1806
1807    fn as_report<'a>(&'a self, source: &'a str, path: &'a str) -> Vec<Group<'a>> {
1808        [Level::ERROR.primary_title("invalid subnode").element(
1809            Snippet::source(source)
1810                .path(path)
1811                .annotation(
1812                    AnnotationKind::Primary
1813                        .span(self.subnode.into())
1814                        .label("subnode not supported in this location"),
1815                )
1816                .annotation(
1817                    AnnotationKind::Context
1818                        .span(self.node_type.span.into())
1819                        .label(format!("{} nodes don't support subnodes", self.node_type)),
1820                ),
1821        )]
1822        .to_vec()
1823    }
1824}
1825
1826#[derive(Debug)]
1827pub struct SizeBytesTooLarge {
1828    pub value: Span,
1829    pub field_set: Span,
1830}
1831
1832impl Diagnostic for SizeBytesTooLarge {
1833    fn is_error(&self) -> bool {
1834        true
1835    }
1836
1837    fn as_report<'a>(&'a self, source: &'a str, path: &'a str) -> Vec<Group<'a>> {
1838        [
1839            Level::ERROR.primary_title("size-bytes too large").element(
1840                Snippet::source(source)
1841                    .path(path)
1842                    .annotation(AnnotationKind::Context.span(self.field_set.into()))
1843                    .annotation(
1844                        AnnotationKind::Primary
1845                            .span(self.value.into())
1846                            .label("value too large"),
1847                    ),
1848            ),
1849            Level::HELP
1850                .secondary_title(
1851                    "the maximum value of size-bytes is 0x10_0000 (or 1MB). Keep the value below the limit",
1852                )
1853                .element(
1854                    Snippet::source(source)
1855                        .path(path)
1856                        .patch(Patch::new(self.value.into(), "0xFFFF_FFFF")),
1857                ),
1858        ]
1859        .to_vec()
1860    }
1861}
1862
1863#[derive(Debug)]
1864pub struct FieldAddressOutOfRange {
1865    pub field_address: Span,
1866}
1867
1868impl Diagnostic for FieldAddressOutOfRange {
1869    fn is_error(&self) -> bool {
1870        true
1871    }
1872
1873    fn as_report<'a>(&'a self, source: &'a str, path: &'a str) -> Vec<Group<'a>> {
1874        [Level::ERROR
1875            .primary_title("field address exceeds the allowed limits")
1876            .element(
1877                Snippet::source(source).path(path).annotation(
1878                    AnnotationKind::Primary
1879                        .span(self.field_address.into())
1880                        .label("address must be non-negative and lower than 2^32"),
1881                ),
1882            )]
1883        .to_vec()
1884    }
1885}
1886
1887#[derive(Debug)]
1888pub struct ResetValueNegative {
1889    pub reset_value: Span,
1890}
1891
1892impl Diagnostic for ResetValueNegative {
1893    fn is_error(&self) -> bool {
1894        true
1895    }
1896
1897    fn as_report<'a>(&'a self, source: &'a str, path: &'a str) -> Vec<Group<'a>> {
1898        [Level::ERROR
1899            .primary_title("reset value is negative")
1900            .element(
1901                Snippet::source(source).path(path).annotation(
1902                    AnnotationKind::Primary
1903                        .span(self.reset_value.into())
1904                        .label("value may not be negative"),
1905                ),
1906            )]
1907        .to_vec()
1908    }
1909}
1910
1911#[derive(Debug)]
1912pub struct InvalidShortProperty {
1913    pub property: Span,
1914    pub node_type: Spanned<NodeType>,
1915    pub got: String,
1916    pub expected: Vec<(String, String)>,
1917}
1918
1919impl Diagnostic for InvalidShortProperty {
1920    fn is_error(&self) -> bool {
1921        true
1922    }
1923
1924    fn as_report<'a>(&'a self, source: &'a str, path: &'a str) -> Vec<Group<'a>> {
1925        [Level::ERROR
1926            .primary_title(format!(
1927                "invalid short property for `{}` nodes",
1928                self.node_type
1929            ))
1930            .element(
1931                Snippet::source(source)
1932                    .path(path)
1933                    .annotation(AnnotationKind::Primary.span(self.property.into()).label(
1934                        if self.expected.is_empty() {
1935                            "no short properties are expected".into()
1936                        } else {
1937                            format!(
1938                                "expected one of: {}",
1939                                self.expected
1940                                    .iter()
1941                                    .map(|(expression, purpose)| format!(
1942                                        "`{expression}` as {purpose}"
1943                                    ))
1944                                    .join(", ")
1945                            )
1946                        },
1947                    ))
1948                    .annotation(
1949                        AnnotationKind::Context
1950                            .span(self.property.into())
1951                            .label(format!("got: `{}`", self.got,)),
1952                    ),
1953            )]
1954        .to_vec()
1955    }
1956}
1957
1958#[derive(Debug)]
1959pub struct FieldAddressWrongOrder {
1960    pub address: Span,
1961    pub end: i128,
1962    pub start: i128,
1963}
1964
1965impl Diagnostic for FieldAddressWrongOrder {
1966    fn is_error(&self) -> bool {
1967        true
1968    }
1969
1970    fn as_report<'a>(&'a self, source: &'a str, path: &'a str) -> Vec<Group<'a>> {
1971        const NOTE_TEXT: &str = "the ordering is `high:low` because that mirrors the format commonly used in datasheets and HDLs";
1972        [
1973            Level::ERROR
1974                .primary_title("field address specified in wrong order")
1975                .element(
1976                    Snippet::source(source).path(path).annotation(
1977                        AnnotationKind::Primary
1978                            .span(self.address.into())
1979                            .label("address must be specified as `high:low`"),
1980                    ),
1981                ),
1982            Level::HELP
1983                .secondary_title("try switching around the numbers")
1984                .element(Snippet::source(source).path(path).patch(Patch::new(
1985                    self.address.into(),
1986                    format!("{}:{}", self.start, self.end),
1987                ))),
1988            Group::with_title(Level::NOTE.secondary_title(NOTE_TEXT)),
1989        ]
1990        .into()
1991    }
1992}
1993
1994#[derive(Debug)]
1995pub struct IgnoredDocCommentOnProperty {
1996    pub doc_comments: Span,
1997    pub property: Span,
1998}
1999
2000impl Diagnostic for IgnoredDocCommentOnProperty {
2001    fn is_error(&self) -> bool {
2002        false
2003    }
2004
2005    fn as_report<'a>(&'a self, source: &'a str, path: &'a str) -> Vec<Group<'a>> {
2006        [Level::WARNING
2007            .primary_title("doc comments placed on property that doesn't use them")
2008            .element(
2009                Snippet::source(source)
2010                    .path(path)
2011                    .annotation(
2012                        AnnotationKind::Primary
2013                            .span(self.doc_comments.into())
2014                            .label("these doc comments are ignored"),
2015                    )
2016                    .annotation(AnnotationKind::Visible.span(self.property.into())),
2017            )]
2018        .into()
2019    }
2020}
2021
2022#[derive(Debug)]
2023pub struct InvalidTypeSpecifier {
2024    pub node_type: Spanned<NodeType>,
2025    pub type_specifier: Span,
2026}
2027
2028impl Diagnostic for InvalidTypeSpecifier {
2029    fn is_error(&self) -> bool {
2030        true
2031    }
2032
2033    fn as_report<'a>(&'a self, source: &'a str, path: &'a str) -> Vec<Group<'a>> {
2034        [
2035            Level::ERROR
2036                .primary_title(format!(
2037                    "invalid type specifier for `{}` nodes",
2038                    self.node_type
2039                ))
2040                .element(
2041                    Snippet::source(source)
2042                        .path(path)
2043                        .annotation(AnnotationKind::Visible.span(self.node_type.span.into()))
2044                        .annotation(
2045                            AnnotationKind::Primary
2046                                .span(self.type_specifier.into())
2047                                .label("no type specifier is allowed on this node"),
2048                        ),
2049                ),
2050            Level::HELP
2051                .secondary_title("remove the type specifier")
2052                .element(
2053                    Snippet::source(source)
2054                        .path(path)
2055                        .patch(Patch::new(self.type_specifier.into(), "")),
2056                ),
2057        ]
2058        .to_vec()
2059    }
2060}
2061
2062#[derive(Debug)]
2063pub struct InvalidTypeConversion {
2064    pub node_type: Spanned<NodeType>,
2065    pub type_conversion: Span,
2066}
2067
2068impl Diagnostic for InvalidTypeConversion {
2069    fn is_error(&self) -> bool {
2070        true
2071    }
2072
2073    fn as_report<'a>(&'a self, source: &'a str, path: &'a str) -> Vec<Group<'a>> {
2074        [
2075            Level::ERROR
2076                .primary_title(format!(
2077                    "invalid type conversion for `{}` nodes",
2078                    self.node_type
2079                ))
2080                .element(
2081                    Snippet::source(source)
2082                        .path(path)
2083                        .annotation(AnnotationKind::Visible.span(self.node_type.span.into()))
2084                        .annotation(
2085                            AnnotationKind::Primary
2086                                .span(self.type_conversion.into())
2087                                .label("no type conversion is allowed on this node"),
2088                        ),
2089                ),
2090            Level::HELP
2091                .secondary_title("remove the type conversion")
2092                .element(
2093                    Snippet::source(source)
2094                        .path(path)
2095                        .patch(Patch::new(self.type_conversion.into(), "")),
2096                ),
2097        ]
2098        .to_vec()
2099    }
2100}
2101
2102#[derive(Debug)]
2103pub struct InvalidFieldsetRef {
2104    pub reference: Span,
2105    pub pointee: Option<Span>,
2106}
2107
2108impl Diagnostic for InvalidFieldsetRef {
2109    fn is_error(&self) -> bool {
2110        true
2111    }
2112
2113    fn as_report<'a>(&'a self, source: &'a str, path: &'a str) -> Vec<Group<'a>> {
2114        [Level::ERROR
2115            .primary_title("invalid fieldset reference")
2116            .element(
2117                Snippet::source(source)
2118                    .path(path)
2119                    .annotation(
2120                        AnnotationKind::Primary
2121                            .span(self.reference.into())
2122                            .label("no fieldset found with this name"),
2123                    )
2124                    .annotations(self.pointee.map(|pointee| {
2125                        AnnotationKind::Context
2126                            .span(pointee.into())
2127                            .label("reference points to this non-fieldset object instead")
2128                    })),
2129            )]
2130        .to_vec()
2131    }
2132}
2133
2134#[derive(Debug)]
2135pub struct InvalidRepeat {
2136    pub repeat: Span,
2137    pub node_type: Spanned<NodeType>,
2138}
2139
2140impl Diagnostic for InvalidRepeat {
2141    fn is_error(&self) -> bool {
2142        true
2143    }
2144
2145    fn as_report<'a>(&'a self, source: &'a str, path: &'a str) -> Vec<Group<'a>> {
2146        [
2147            Level::ERROR.primary_title("invalid repeat").element(
2148                Snippet::source(source)
2149                    .path(path)
2150                    .annotation(
2151                        AnnotationKind::Primary
2152                            .span(self.repeat.into())
2153                            .label(format!(
2154                                "repeats can't be applied on {} nodes",
2155                                self.node_type
2156                            )),
2157                    )
2158                    .annotation(AnnotationKind::Visible.span(self.node_type.span.into())),
2159            ),
2160            Level::HELP.secondary_title("remove the repeat").element(
2161                Snippet::source(source)
2162                    .path(path)
2163                    .patch(Patch::new(self.repeat.into(), "")),
2164            ),
2165        ]
2166        .to_vec()
2167    }
2168}
2169
2170#[derive(Debug)]
2171pub struct ZeroStrideRepeat {
2172    pub stride: Span,
2173}
2174
2175impl Diagnostic for ZeroStrideRepeat {
2176    fn is_error(&self) -> bool {
2177        true
2178    }
2179
2180    fn as_report<'a>(&'a self, source: &'a str, path: &'a str) -> Vec<Group<'a>> {
2181        const INFO_TEXT: &str = "a stride of 0 means the address doesn't change. So the repeat is useless and thus rejected";
2182
2183        [
2184            Level::ERROR
2185                .primary_title("repeat stride cannot be 0")
2186                .element(
2187                    Snippet::source(source).path(path).annotation(
2188                        AnnotationKind::Primary
2189                            .span(self.stride.into())
2190                            .label("stride is 0"),
2191                    ),
2192                ),
2193            Level::HELP
2194                .secondary_title("change to a non-zero value")
2195                .element(
2196                    Snippet::source(source)
2197                        .path(path)
2198                        .patch(Patch::new(self.stride.into(), "1")),
2199                ),
2200            Group::with_title(Level::INFO.secondary_title(INFO_TEXT)),
2201        ]
2202        .to_vec()
2203    }
2204}
2205
2206#[derive(Debug)]
2207pub struct ReservedOperationNameUsed {
2208    pub name: Span,
2209    pub operation_name: String,
2210    pub reserved_names: &'static [&'static str],
2211}
2212
2213impl Diagnostic for ReservedOperationNameUsed {
2214    fn is_error(&self) -> bool {
2215        true
2216    }
2217
2218    fn as_report<'a>(&'a self, source: &'a str, path: &'a str) -> Vec<Group<'a>> {
2219        let info_text: String = format!(
2220            "reserved names are: {}",
2221            self.reserved_names
2222                .iter()
2223                .map(|name| format!("`{name}`"))
2224                .join(", ")
2225        );
2226
2227        [
2228            Level::ERROR
2229                .primary_title("reserved operation name used")
2230                .element(
2231                Snippet::source(source).path(path).annotation(
2232                    AnnotationKind::Primary
2233                        .span(self.name.into())
2234                        .label(format!(
2235                            "`{}` is a reserved name for operations. Change it to something else",
2236                            self.operation_name
2237                        )),
2238                ),
2239            ),
2240            Group::with_title(Level::INFO.secondary_title(info_text)),
2241        ]
2242        .to_vec()
2243    }
2244}
2245
2246#[derive(Debug)]
2247pub struct FieldSetterNameCollision {
2248    pub field: Span,
2249    pub setter_name: String,
2250    pub collision_field: Span,
2251}
2252
2253impl Diagnostic for FieldSetterNameCollision {
2254    fn is_error(&self) -> bool {
2255        true
2256    }
2257
2258    fn as_report<'a>(&'a self, source: &'a str, path: &'a str) -> Vec<Group<'a>> {
2259        const HELP_TEXT: &str = "writable fields generate setter functions that have the word `set` prepended. This can collide with other field names.\nAvoid this by changing the name of one of the fields or by making the field read only so it doesn't generate a setter";
2260
2261        [
2262            Level::ERROR
2263                .primary_title("field setter name collision")
2264                .element(
2265                Snippet::source(source)
2266                    .path(path)
2267                    .annotation(
2268                        AnnotationKind::Primary
2269                            .span(self.field.into())
2270                            .label(format!(
2271                                "this field is writable and generates a setter with a name that collides with another field: `{}`",
2272                                self.setter_name
2273                            )),
2274                    )
2275                    .annotation(
2276                        AnnotationKind::Context
2277                            .span(self.collision_field.into())
2278                            .label("collides with this field"),
2279                    ),
2280            ),
2281            Group::with_title(Level::HELP.secondary_title(HELP_TEXT)),
2282        ]
2283        .to_vec()
2284    }
2285}