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 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 Group::with_title(Level::INFO.secondary_title(INFO_TEXT)),
751 ]
752 .to_vec()
753 }
754}
755
756#[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 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 ),
1217 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 ), )
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 ), ),
1426 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}