1use codespan_reporting::diagnostic::Diagnostic;
16use codespan_reporting::files;
17use codespan_reporting::term;
18use codespan_reporting::term::termcolor;
19use std::collections::HashMap;
20
21use crate::ast::*;
22
23#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
25#[allow(unused)]
26pub enum Size {
27 Static(usize),
29 Dynamic,
32 Unknown,
35}
36
37#[allow(clippy::derivable_impls)]
39impl Default for Size {
40 fn default() -> Size {
41 Size::Unknown
42 }
43}
44
45impl std::ops::Add for Size {
46 type Output = Size;
47 fn add(self, rhs: Size) -> Self::Output {
48 match (self, rhs) {
49 (Size::Unknown, _) | (_, Size::Unknown) => Size::Unknown,
50 (Size::Dynamic, _) | (_, Size::Dynamic) => Size::Dynamic,
51 (Size::Static(lhs), Size::Static(rhs)) => Size::Static(lhs + rhs),
52 }
53 }
54}
55
56impl std::ops::Mul for Size {
57 type Output = Size;
58 fn mul(self, rhs: Size) -> Self::Output {
59 match (self, rhs) {
60 (Size::Unknown, _) | (_, Size::Unknown) => Size::Unknown,
61 (Size::Dynamic, _) | (_, Size::Dynamic) => Size::Dynamic,
62 (Size::Static(lhs), Size::Static(rhs)) => Size::Static(lhs * rhs),
63 }
64 }
65}
66
67impl std::ops::Mul<usize> for Size {
68 type Output = Size;
69 fn mul(self, rhs: usize) -> Self::Output {
70 match self {
71 Size::Unknown => Size::Unknown,
72 Size::Dynamic => Size::Dynamic,
73 Size::Static(lhs) => Size::Static(lhs * rhs),
74 }
75 }
76}
77
78impl Size {
79 pub fn static_(&self) -> Option<usize> {
81 match self {
82 Size::Static(size) => Some(*size),
83 Size::Dynamic | Size::Unknown => None,
84 }
85 }
86}
87
88#[repr(u16)]
90pub enum ErrorCode {
91 DuplicateDeclIdentifier = 1,
92 RecursiveDecl = 2,
93 UndeclaredGroupIdentifier = 3,
94 InvalidGroupIdentifier = 4,
95 UndeclaredTypeIdentifier = 5,
96 InvalidTypeIdentifier = 6,
97 UndeclaredParentIdentifier = 7,
98 InvalidParentIdentifier = 8,
99 UndeclaredTestIdentifier = 9,
100 InvalidTestIdentifier = 10,
101 DuplicateFieldIdentifier = 11,
102 DuplicateTagIdentifier = 12,
103 DuplicateTagValue = 13,
104 InvalidTagValue = 14,
105 UndeclaredConstraintIdentifier = 15,
106 InvalidConstraintIdentifier = 16,
107 E17 = 17,
108 ConstraintValueOutOfRange = 18,
109 E19 = 19,
110 E20 = 20,
111 E21 = 21,
112 DuplicateConstraintIdentifier = 22,
113 DuplicateSizeField = 23,
114 UndeclaredSizeIdentifier = 24,
115 InvalidSizeIdentifier = 25,
116 DuplicateCountField = 26,
117 UndeclaredCountIdentifier = 27,
118 InvalidCountIdentifier = 28,
119 DuplicateElementSizeField = 29,
120 UndeclaredElementSizeIdentifier = 30,
121 InvalidElementSizeIdentifier = 31,
122 FixedValueOutOfRange = 32,
123 E33 = 33,
124 E34 = 34,
125 E35 = 35,
126 DuplicatePayloadField = 36,
127 MissingPayloadField = 37,
128 RedundantArraySize = 38,
129 InvalidPaddingField = 39,
130 InvalidTagRange = 40,
131 DuplicateTagRange = 41,
132 E42 = 42,
133 E43 = 43,
134 DuplicateDefaultTag = 44,
135 InvalidOptionalField = 45,
136 UndeclaredConditionIdentifier = 46,
137 InvalidConditionIdentifier = 47,
138 InvalidConditionValue = 48,
139 E49 = 49,
140 InvalidFieldOffset = 51,
141 InvalidFieldSize = 52,
142 InvalidPacketSize = 53,
143}
144
145impl From<ErrorCode> for String {
146 fn from(code: ErrorCode) -> Self {
147 format!("E{}", code as u16)
148 }
149}
150
151#[derive(Debug, Default)]
153pub struct Diagnostics {
154 pub diagnostics: Vec<Diagnostic<FileId>>,
155}
156
157#[derive(Debug)]
159pub struct Scope<'d> {
160 pub file: &'d File,
162 pub typedef: HashMap<String, &'d Decl>,
165}
166
167#[derive(Debug)]
169pub struct Schema {
170 decl_size: HashMap<DeclKey, Size>,
171 parent_size: HashMap<DeclKey, Size>,
172 field_size: HashMap<FieldKey, Size>,
173 padded_size: HashMap<FieldKey, Option<usize>>,
174 payload_size: HashMap<DeclKey, Size>,
175}
176
177impl Diagnostics {
178 fn is_empty(&self) -> bool {
179 self.diagnostics.is_empty()
180 }
181
182 fn push(&mut self, diagnostic: Diagnostic<FileId>) {
183 self.diagnostics.push(diagnostic)
184 }
185
186 fn err_or<T>(self, value: T) -> Result<T, Diagnostics> {
187 if self.is_empty() {
188 Ok(value)
189 } else {
190 Err(self)
191 }
192 }
193
194 pub fn emit(
195 &self,
196 sources: &SourceDatabase,
197 writer: &mut dyn termcolor::WriteColor,
198 ) -> Result<(), files::Error> {
199 let config = term::Config::default();
200 for d in self.diagnostics.iter() {
201 term::emit(writer, &config, sources, d)?;
202 }
203 Ok(())
204 }
205}
206
207impl<'d> Scope<'d> {
208 pub fn new(file: &'d File) -> Result<Scope<'d>, Diagnostics> {
209 let mut scope: Scope = Scope { file, typedef: Default::default() };
211 let mut diagnostics: Diagnostics = Default::default();
212 for decl in &file.declarations {
213 if let Some(id) = decl.id() {
214 if let Some(prev) = scope.typedef.insert(id.to_string(), decl) {
215 diagnostics.push(
216 Diagnostic::error()
217 .with_code(ErrorCode::DuplicateDeclIdentifier)
218 .with_message(format!(
219 "redeclaration of {} identifier `{}`",
220 decl.kind(),
221 id
222 ))
223 .with_labels(vec![
224 decl.loc.primary(),
225 prev.loc
226 .secondary()
227 .with_message(format!("`{id}` is first declared here")),
228 ]),
229 )
230 }
231 }
232 }
233
234 if diagnostics.is_empty() {
236 Ok(scope)
237 } else {
238 Err(diagnostics)
239 }
240 }
241
242 pub fn iter_children<'s>(&'s self, decl: &'d Decl) -> impl Iterator<Item = &'d Decl> + 's {
244 self.file.iter_children(decl)
245 }
246
247 pub fn get_parent(&self, decl: &Decl) -> Option<&'d Decl> {
250 decl.parent_id().and_then(|parent_id| self.typedef.get(parent_id).cloned())
251 }
252
253 pub fn iter_parents<'s>(&'s self, decl: &'d Decl) -> impl Iterator<Item = &'d Decl> + 's {
255 std::iter::successors(self.get_parent(decl), |decl| self.get_parent(decl))
256 }
257
258 pub fn iter_parents_and_self<'s>(
261 &'s self,
262 decl: &'d Decl,
263 ) -> impl Iterator<Item = &'d Decl> + 's {
264 std::iter::successors(Some(decl), |decl| self.get_parent(decl))
265 }
266
267 pub fn iter_fields<'s>(&'s self, decl: &'d Decl) -> impl Iterator<Item = &'d Field> + 's {
269 std::iter::successors(Some(decl), |decl| self.get_parent(decl)).flat_map(Decl::fields)
270 }
271
272 pub fn iter_parent_fields<'s>(
274 &'s self,
275 decl: &'d Decl,
276 ) -> impl Iterator<Item = &'d Field> + 's {
277 std::iter::successors(self.get_parent(decl), |decl| self.get_parent(decl))
278 .flat_map(Decl::fields)
279 }
280
281 pub fn iter_constraints<'s>(
283 &'s self,
284 decl: &'d Decl,
285 ) -> impl Iterator<Item = &'d Constraint> + 's {
286 std::iter::successors(Some(decl), |decl| self.get_parent(decl)).flat_map(Decl::constraints)
287 }
288
289 pub fn get_type_declaration(&self, field: &Field) -> Option<&'d Decl> {
291 match &field.desc {
292 FieldDesc::Checksum { .. }
293 | FieldDesc::Padding { .. }
294 | FieldDesc::Size { .. }
295 | FieldDesc::Count { .. }
296 | FieldDesc::ElementSize { .. }
297 | FieldDesc::Body
298 | FieldDesc::Payload { .. }
299 | FieldDesc::FixedScalar { .. }
300 | FieldDesc::Reserved { .. }
301 | FieldDesc::Group { .. }
302 | FieldDesc::Flag { .. }
303 | FieldDesc::Scalar { .. }
304 | FieldDesc::Array { type_id: None, .. } => None,
305 FieldDesc::FixedEnum { enum_id: type_id, .. }
306 | FieldDesc::Array { type_id: Some(type_id), .. }
307 | FieldDesc::Typedef { type_id, .. } => self.typedef.get(type_id).cloned(),
308 }
309 }
310
311 pub fn is_bitfield(&self, field: &Field) -> bool {
313 match &field.desc {
314 FieldDesc::Size { .. }
315 | FieldDesc::Count { .. }
316 | FieldDesc::ElementSize { .. }
317 | FieldDesc::FixedScalar { .. }
318 | FieldDesc::FixedEnum { .. }
319 | FieldDesc::Reserved { .. }
320 | FieldDesc::Flag { .. }
321 | FieldDesc::Scalar { .. } => true,
322 FieldDesc::Typedef { type_id, .. } => {
323 let field = self.typedef.get(type_id.as_str());
324 matches!(field, Some(Decl { desc: DeclDesc::Enum { .. }, .. }))
325 }
326 _ => false,
327 }
328 }
329}
330
331impl Schema {
332 pub fn new(file: &File) -> Schema {
335 fn annotate_decl(schema: &mut Schema, scope: &HashMap<String, DeclKey>, decl: &Decl) {
336 let mut padding = None;
338 for field in decl.fields().rev() {
339 schema.padded_size.insert(field.key, padding);
340 padding = match &field.desc {
341 FieldDesc::Padding { size } => Some(8 * *size),
342 _ => None,
343 };
344 }
345
346 let parent_size = decl
347 .parent_id()
348 .and_then(|parent_id| scope.get(parent_id))
349 .map(|key| schema.decl_size(*key) + schema.parent_size(*key))
350 .unwrap_or(Size::Static(0));
351 let mut decl_size = Size::Static(0);
352 let mut payload_size = Size::Static(0);
353
354 for field in decl.fields() {
355 let field_size = annotate_field(schema, scope, decl, field);
357
358 match &field.desc {
361 FieldDesc::Payload { .. } | FieldDesc::Body => payload_size = field_size,
362 _ => {
363 decl_size = decl_size
364 + match schema.padded_size.get(&field.key).unwrap() {
365 Some(padding) => Size::Static(*padding),
366 None => field_size,
367 }
368 }
369 }
370 }
371
372 let (decl_size, payload_size) = match &decl.desc {
374 DeclDesc::Packet { .. } | DeclDesc::Struct { .. } | DeclDesc::Group { .. } => {
375 (decl_size, payload_size)
376 }
377 DeclDesc::Enum { width, .. }
378 | DeclDesc::Checksum { width, .. }
379 | DeclDesc::CustomField { width: Some(width), .. } => {
380 (Size::Static(*width), Size::Static(0))
381 }
382 DeclDesc::CustomField { width: None, .. } => (Size::Dynamic, Size::Static(0)),
383 DeclDesc::Test { .. } => (Size::Static(0), Size::Static(0)),
384 };
385
386 schema.parent_size.insert(decl.key, parent_size);
387 schema.decl_size.insert(decl.key, decl_size);
388 schema.payload_size.insert(decl.key, payload_size);
389 }
390
391 fn annotate_field(
392 schema: &mut Schema,
393 scope: &HashMap<String, DeclKey>,
394 decl: &Decl,
395 field: &Field,
396 ) -> Size {
397 let size = match &field.desc {
398 _ if field.cond.is_some() => Size::Dynamic,
399 FieldDesc::Checksum { .. } | FieldDesc::Padding { .. } => Size::Static(0),
400 FieldDesc::Size { width, .. }
401 | FieldDesc::Count { width, .. }
402 | FieldDesc::ElementSize { width, .. }
403 | FieldDesc::FixedScalar { width, .. }
404 | FieldDesc::Reserved { width }
405 | FieldDesc::Scalar { width, .. } => Size::Static(*width),
406 FieldDesc::Flag { .. } => Size::Static(1),
407 FieldDesc::Body | FieldDesc::Payload { .. } => {
408 let has_payload_size = decl.fields().any(|field| match &field.desc {
409 FieldDesc::Size { field_id, .. } => {
410 field_id == "_body_" || field_id == "_payload_"
411 }
412 _ => false,
413 });
414 if has_payload_size {
415 Size::Dynamic
416 } else {
417 Size::Unknown
418 }
419 }
420 FieldDesc::Typedef { type_id, .. }
421 | FieldDesc::FixedEnum { enum_id: type_id, .. }
422 | FieldDesc::Group { group_id: type_id, .. } => {
423 let type_key = scope.get(type_id).unwrap();
424 schema.total_size(*type_key)
425 }
426 FieldDesc::Array { width: Some(width), size: Some(size), .. } => {
427 Size::Static(*size * *width)
428 }
429 FieldDesc::Array {
430 width: None, size: Some(size), type_id: Some(type_id), ..
431 } => {
432 let type_key = scope.get(type_id).unwrap();
433 schema.total_size(*type_key) * *size
434 }
435 FieldDesc::Array { id, size: None, .. } => {
436 let has_array_size = decl.fields().any(|field| match &field.desc {
440 FieldDesc::Size { field_id, .. } | FieldDesc::Count { field_id, .. } => {
441 field_id == id
442 }
443 _ => false,
444 });
445 if has_array_size {
446 Size::Dynamic
447 } else {
448 Size::Unknown
449 }
450 }
451 FieldDesc::Array { .. } => unreachable!(),
452 };
453
454 schema.field_size.insert(field.key, size);
455 size
456 }
457
458 let mut scope = HashMap::new();
459 for decl in &file.declarations {
460 if let Some(id) = decl.id() {
461 scope.insert(id.to_owned(), decl.key);
462 }
463 }
464
465 let mut schema = Schema {
466 field_size: Default::default(),
467 decl_size: Default::default(),
468 padded_size: Default::default(),
469 payload_size: Default::default(),
470 parent_size: Default::default(),
471 };
472
473 for decl in &file.declarations {
474 annotate_decl(&mut schema, &scope, decl);
475 }
476
477 schema
478 }
479
480 pub fn field_size(&self, key: FieldKey) -> Size {
481 self.field_size[&key]
482 }
483
484 pub fn decl_size(&self, key: DeclKey) -> Size {
485 self.decl_size[&key]
486 }
487
488 pub fn parent_size(&self, key: DeclKey) -> Size {
489 self.parent_size[&key]
490 }
491
492 pub fn padded_size(&self, key: FieldKey) -> Option<usize> {
493 self.padded_size[&key]
494 }
495
496 pub fn payload_size(&self, key: DeclKey) -> Size {
497 self.payload_size[&key]
498 }
499
500 pub fn total_size(&self, key: DeclKey) -> Size {
501 self.decl_size(key) + self.parent_size(key) + self.payload_size(key)
502 }
503}
504
505fn bit_width(value: usize) -> usize {
507 usize::BITS as usize - value.leading_zeros() as usize
508}
509
510fn scalar_max(width: usize) -> usize {
512 if width >= usize::BITS as usize {
513 usize::MAX
514 } else {
515 (1 << width) - 1
516 }
517}
518
519fn check_decl_identifiers(file: &File, scope: &Scope) -> Result<(), Diagnostics> {
531 enum Mark {
532 Temporary,
533 Permanent,
534 }
535 #[derive(Default)]
536 struct Context<'d> {
537 visited: HashMap<&'d str, Mark>,
538 }
539
540 fn bfs<'d>(
541 decl: &'d Decl,
542 context: &mut Context<'d>,
543 scope: &Scope<'d>,
544 diagnostics: &mut Diagnostics,
545 ) {
546 let decl_id = decl.id().unwrap();
547 match context.visited.get(decl_id) {
548 Some(Mark::Permanent) => return,
549 Some(Mark::Temporary) => {
550 diagnostics.push(
551 Diagnostic::error()
552 .with_code(ErrorCode::RecursiveDecl)
553 .with_message(format!(
554 "recursive declaration of {} `{}`",
555 decl.kind(),
556 decl_id
557 ))
558 .with_labels(vec![decl.loc.primary()]),
559 );
560 return;
561 }
562 _ => (),
563 }
564
565 context.visited.insert(decl_id, Mark::Temporary);
567
568 for field in decl.fields() {
570 match &field.desc {
571 FieldDesc::Group { group_id, .. } => match scope.typedef.get(group_id) {
574 None => diagnostics.push(
575 Diagnostic::error()
576 .with_code(ErrorCode::UndeclaredGroupIdentifier)
577 .with_message(format!("undeclared group identifier `{group_id}`"))
578 .with_labels(vec![field.loc.primary()])
579 .with_notes(vec!["hint: expected group identifier".to_owned()]),
580 ),
581 Some(group_decl @ Decl { desc: DeclDesc::Group { .. }, .. }) => {
582 bfs(group_decl, context, scope, diagnostics)
583 }
584 Some(_) => diagnostics.push(
585 Diagnostic::error()
586 .with_code(ErrorCode::InvalidGroupIdentifier)
587 .with_message(format!("invalid group identifier `{group_id}`"))
588 .with_labels(vec![field.loc.primary()])
589 .with_notes(vec!["hint: expected group identifier".to_owned()]),
590 ),
591 },
592 FieldDesc::Typedef { type_id, .. }
596 | FieldDesc::Array { type_id: Some(type_id), .. } => {
597 match scope.typedef.get(type_id) {
598 None => diagnostics.push(
599 Diagnostic::error().with_code(ErrorCode::UndeclaredTypeIdentifier)
600 .with_message(format!(
601 "undeclared {} identifier `{}`",
602 field.kind(),
603 type_id
604 ))
605 .with_labels(vec![field.loc.primary()])
606 .with_notes(vec!["hint: expected enum, struct, custom_field, or checksum identifier".to_owned()]),
607 ),
608 Some(Decl { desc: DeclDesc::Packet { .. }, .. }) => diagnostics.push(
609 Diagnostic::error().with_code(ErrorCode::InvalidTypeIdentifier)
610 .with_message(format!(
611 "invalid {} identifier `{}`",
612 field.kind(),
613 type_id
614 ))
615 .with_labels(vec![field.loc.primary()])
616 .with_notes(vec!["hint: expected enum, struct, custom_field, or checksum identifier".to_owned()]),
617 ),
618 Some(typedef_decl) =>
619 if matches!(&field.desc, FieldDesc::Typedef { .. }) ||
622 matches!(&field.desc, FieldDesc::Array { size: Some(_), .. }) {
623 bfs(typedef_decl, context, scope, diagnostics)
624 }
625 }
626 }
627 _ => (),
629 }
630 }
631
632 if let Some(parent_id) = decl.parent_id() {
634 let parent_decl = scope.typedef.get(parent_id);
635 match (&decl.desc, parent_decl) {
636 (DeclDesc::Packet { .. }, None) | (DeclDesc::Struct { .. }, None) => diagnostics
637 .push(
638 Diagnostic::error()
639 .with_code(ErrorCode::UndeclaredParentIdentifier)
640 .with_message(format!("undeclared parent identifier `{parent_id}`"))
641 .with_labels(vec![decl.loc.primary()])
642 .with_notes(vec![format!("hint: expected {} identifier", decl.kind())]),
643 ),
644 (
645 DeclDesc::Packet { .. },
646 Some(parent_decl @ Decl { desc: DeclDesc::Packet { .. }, .. }),
647 )
648 | (
649 DeclDesc::Struct { .. },
650 Some(parent_decl @ Decl { desc: DeclDesc::Struct { .. }, .. }),
651 ) => bfs(parent_decl, context, scope, diagnostics),
652 (_, Some(_)) => diagnostics.push(
653 Diagnostic::error()
654 .with_code(ErrorCode::InvalidParentIdentifier)
655 .with_message(format!("invalid parent identifier `{parent_id}`"))
656 .with_labels(vec![decl.loc.primary()])
657 .with_notes(vec![format!("hint: expected {} identifier", decl.kind())]),
658 ),
659 _ => unreachable!(),
660 }
661 }
662
663 context.visited.insert(decl_id, Mark::Permanent);
665 }
666
667 let mut diagnostics = Default::default();
669 let mut context = Default::default();
670 for decl in &file.declarations {
671 match &decl.desc {
672 DeclDesc::Checksum { .. } | DeclDesc::CustomField { .. } | DeclDesc::Enum { .. } => (),
673 DeclDesc::Packet { .. } | DeclDesc::Struct { .. } | DeclDesc::Group { .. } => {
674 bfs(decl, &mut context, scope, &mut diagnostics)
675 }
676 DeclDesc::Test { type_id, .. } => match scope.typedef.get(type_id) {
677 None => diagnostics.push(
678 Diagnostic::error()
679 .with_code(ErrorCode::UndeclaredTestIdentifier)
680 .with_message(format!("undeclared test identifier `{type_id}`"))
681 .with_labels(vec![decl.loc.primary()])
682 .with_notes(vec!["hint: expected packet identifier".to_owned()]),
683 ),
684 Some(Decl { desc: DeclDesc::Packet { .. }, .. }) => (),
685 Some(_) => diagnostics.push(
686 Diagnostic::error()
687 .with_code(ErrorCode::InvalidTestIdentifier)
688 .with_message(format!("invalid test identifier `{type_id}`"))
689 .with_labels(vec![decl.loc.primary()])
690 .with_notes(vec!["hint: expected packet identifier".to_owned()]),
691 ),
692 },
693 }
694 }
695
696 diagnostics.err_or(())
697}
698
699fn check_field_identifiers(file: &File) -> Result<(), Diagnostics> {
703 let mut diagnostics: Diagnostics = Default::default();
704 for decl in &file.declarations {
705 let mut local_scope = HashMap::new();
706 for field in decl.fields() {
707 if let Some(id) = field.id() {
708 if let Some(prev) = local_scope.insert(id.to_string(), field) {
709 diagnostics.push(
710 Diagnostic::error()
711 .with_code(ErrorCode::DuplicateFieldIdentifier)
712 .with_message(format!(
713 "redeclaration of {} field identifier `{}`",
714 field.kind(),
715 id
716 ))
717 .with_labels(vec![
718 field.loc.primary(),
719 prev.loc
720 .secondary()
721 .with_message(format!("`{id}` is first declared here")),
722 ]),
723 )
724 }
725 }
726 }
727 }
728
729 diagnostics.err_or(())
730}
731
732fn check_enum_declarations(file: &File) -> Result<(), Diagnostics> {
737 fn ordered_range(range: &std::ops::RangeInclusive<usize>) -> std::ops::RangeInclusive<usize> {
741 *std::cmp::min(range.start(), range.end())..=*std::cmp::max(range.start(), range.end())
742 }
743
744 fn check_tag_value<'a>(
745 tag: &'a TagValue,
746 range: std::ops::RangeInclusive<usize>,
747 reserved_ranges: impl Iterator<Item = &'a TagRange>,
748 tags_by_id: &mut HashMap<&'a str, SourceRange>,
749 tags_by_value: &mut HashMap<usize, SourceRange>,
750 diagnostics: &mut Diagnostics,
751 ) {
752 if let Some(prev) = tags_by_id.insert(&tag.id, tag.loc) {
753 diagnostics.push(
754 Diagnostic::error()
755 .with_code(ErrorCode::DuplicateTagIdentifier)
756 .with_message(format!("duplicate tag identifier `{}`", tag.id))
757 .with_labels(vec![
758 tag.loc.primary(),
759 prev.secondary()
760 .with_message(format!("`{}` is first declared here", tag.id)),
761 ]),
762 )
763 }
764 if let Some(prev) = tags_by_value.insert(tag.value, tag.loc) {
765 diagnostics.push(
766 Diagnostic::error()
767 .with_code(ErrorCode::DuplicateTagValue)
768 .with_message(format!("duplicate tag value `{}`", tag.value))
769 .with_labels(vec![
770 tag.loc.primary(),
771 prev.secondary()
772 .with_message(format!("`{}` is first declared here", tag.value)),
773 ]),
774 )
775 }
776 if !range.contains(&tag.value) {
777 diagnostics.push(
778 Diagnostic::error()
779 .with_code(ErrorCode::InvalidTagValue)
780 .with_message(format!(
781 "tag value `{}` is outside the range of valid values `{}..{}`",
782 tag.value,
783 range.start(),
784 range.end()
785 ))
786 .with_labels(vec![tag.loc.primary()]),
787 )
788 }
789 for reserved_range in reserved_ranges {
790 if ordered_range(&reserved_range.range).contains(&tag.value) {
791 diagnostics.push(
792 Diagnostic::error()
793 .with_code(ErrorCode::E43)
794 .with_message(format!(
795 "tag value `{}` is declared inside the reserved range `{} = {}..{}`",
796 tag.value,
797 reserved_range.id,
798 reserved_range.range.start(),
799 reserved_range.range.end()
800 ))
801 .with_labels(vec![tag.loc.primary()]),
802 )
803 }
804 }
805 }
806
807 fn check_tag_range<'a>(
808 tag: &'a TagRange,
809 range: std::ops::RangeInclusive<usize>,
810 tags_by_id: &mut HashMap<&'a str, SourceRange>,
811 tags_by_value: &mut HashMap<usize, SourceRange>,
812 diagnostics: &mut Diagnostics,
813 ) {
814 if let Some(prev) = tags_by_id.insert(&tag.id, tag.loc) {
815 diagnostics.push(
816 Diagnostic::error()
817 .with_code(ErrorCode::DuplicateTagIdentifier)
818 .with_message(format!("duplicate tag identifier `{}`", tag.id))
819 .with_labels(vec![
820 tag.loc.primary(),
821 prev.secondary()
822 .with_message(format!("`{}` is first declared here", tag.id)),
823 ]),
824 )
825 }
826 if !range.contains(tag.range.start()) || !range.contains(tag.range.end()) {
827 diagnostics.push(
828 Diagnostic::error()
829 .with_code(ErrorCode::InvalidTagRange)
830 .with_message(format!(
831 "tag range `{}..{}` has bounds outside the range of valid values `{}..{}`",
832 tag.range.start(),
833 tag.range.end(),
834 range.start(),
835 range.end(),
836 ))
837 .with_labels(vec![tag.loc.primary()]),
838 )
839 }
840 if tag.range.start() >= tag.range.end() {
841 diagnostics.push(
842 Diagnostic::error()
843 .with_code(ErrorCode::InvalidTagRange)
844 .with_message(format!(
845 "tag start value `{}` is greater than or equal to the end value `{}`",
846 tag.range.start(),
847 tag.range.end()
848 ))
849 .with_labels(vec![tag.loc.primary()]),
850 )
851 }
852
853 let range = ordered_range(&tag.range);
854 for tag in tag.tags.iter() {
855 check_tag_value(tag, range.clone(), [].iter(), tags_by_id, tags_by_value, diagnostics)
856 }
857 }
858
859 fn check_tag_other<'a>(
860 tag: &'a TagOther,
861 tags_by_id: &mut HashMap<&'a str, SourceRange>,
862 tag_other: &mut Option<SourceRange>,
863 diagnostics: &mut Diagnostics,
864 ) {
865 if let Some(prev) = tags_by_id.insert(&tag.id, tag.loc) {
866 diagnostics.push(
867 Diagnostic::error()
868 .with_code(ErrorCode::DuplicateTagIdentifier)
869 .with_message(format!("duplicate tag identifier `{}`", tag.id))
870 .with_labels(vec![
871 tag.loc.primary(),
872 prev.secondary()
873 .with_message(format!("`{}` is first declared here", tag.id)),
874 ]),
875 )
876 }
877 if let Some(prev) = tag_other {
878 diagnostics.push(
879 Diagnostic::error()
880 .with_code(ErrorCode::DuplicateDefaultTag)
881 .with_message("duplicate default tag".to_owned())
882 .with_labels(vec![
883 tag.loc.primary(),
884 prev.secondary()
885 .with_message("the default tag is first declared here".to_owned()),
886 ]),
887 )
888 }
889 *tag_other = Some(tag.loc)
890 }
891
892 let mut diagnostics: Diagnostics = Default::default();
893 for decl in &file.declarations {
894 if let DeclDesc::Enum { tags, width, .. } = &decl.desc {
895 let mut tags_by_id = HashMap::new();
896 let mut tags_by_value = HashMap::new();
897 let mut tags_by_range = tags
898 .iter()
899 .filter_map(|tag| match tag {
900 Tag::Range(tag) => Some(tag),
901 _ => None,
902 })
903 .collect::<Vec<_>>();
904 let mut tag_other = None;
905
906 for tag in tags {
907 match tag {
908 Tag::Value(value) => check_tag_value(
909 value,
910 0..=scalar_max(*width),
911 tags_by_range.iter().copied(),
912 &mut tags_by_id,
913 &mut tags_by_value,
914 &mut diagnostics,
915 ),
916 Tag::Range(range) => check_tag_range(
917 range,
918 0..=scalar_max(*width),
919 &mut tags_by_id,
920 &mut tags_by_value,
921 &mut diagnostics,
922 ),
923 Tag::Other(other) => {
924 check_tag_other(other, &mut tags_by_id, &mut tag_other, &mut diagnostics)
925 }
926 }
927 }
928
929 tags_by_range.sort_by(|lhs, rhs| {
931 ordered_range(&lhs.range).into_inner().cmp(&ordered_range(&rhs.range).into_inner())
932 });
933
934 for tag in tags_by_range.windows(2) {
938 let left_tag = tag[0];
939 let right_tag = tag[1];
940 let left = ordered_range(&left_tag.range);
941 let right = ordered_range(&right_tag.range);
942 if !(left.end() < right.start() || right.end() < left.start()) {
943 diagnostics.push(
944 Diagnostic::error()
945 .with_code(ErrorCode::DuplicateTagRange)
946 .with_message(format!(
947 "overlapping tag range `{}..{}`",
948 right.start(),
949 right.end()
950 ))
951 .with_labels(vec![
952 right_tag.loc.primary(),
953 left_tag.loc.secondary().with_message(format!(
954 "`{}..{}` is first declared here",
955 left.start(),
956 left.end()
957 )),
958 ]),
959 )
960 }
961 }
962 }
963 }
964
965 diagnostics.err_or(())
966}
967
968fn check_constraint(
970 constraint: &Constraint,
971 decl: &Decl,
972 scope: &Scope,
973 diagnostics: &mut Diagnostics,
974) {
975 match scope.iter_fields(decl).find(|field| field.id() == Some(&constraint.id)) {
976 None => diagnostics.push(
977 Diagnostic::error()
978 .with_code(ErrorCode::UndeclaredConstraintIdentifier)
979 .with_message(format!("undeclared constraint identifier `{}`", constraint.id))
980 .with_labels(vec![constraint.loc.primary()])
981 .with_notes(vec!["hint: expected scalar or typedef identifier".to_owned()]),
982 ),
983 Some(field @ Field { desc: FieldDesc::Array { .. }, .. }) => diagnostics.push(
984 Diagnostic::error()
985 .with_code(ErrorCode::InvalidConstraintIdentifier)
986 .with_message(format!("invalid constraint identifier `{}`", constraint.id))
987 .with_labels(vec![
988 constraint.loc.primary(),
989 field.loc.secondary().with_message(format!(
990 "`{}` is declared here as array field",
991 constraint.id
992 )),
993 ])
994 .with_notes(vec!["hint: expected scalar or typedef identifier".to_owned()]),
995 ),
996 Some(field @ Field { desc: FieldDesc::Scalar { width, .. }, .. }) => {
997 match constraint.value {
998 None => diagnostics.push(
999 Diagnostic::error()
1000 .with_code(ErrorCode::E17)
1001 .with_message(format!(
1002 "invalid constraint value `{}`",
1003 constraint.tag_id.as_ref().unwrap()
1004 ))
1005 .with_labels(vec![
1006 constraint.loc.primary(),
1007 field.loc.secondary().with_message(format!(
1008 "`{}` is declared here as scalar field",
1009 constraint.id
1010 )),
1011 ])
1012 .with_notes(vec!["hint: expected scalar value".to_owned()]),
1013 ),
1014 Some(value) if bit_width(value) > *width => diagnostics.push(
1015 Diagnostic::error()
1016 .with_code(ErrorCode::ConstraintValueOutOfRange)
1017 .with_message(format!(
1018 "constraint value `{value}` is larger than maximum value"
1019 ))
1020 .with_labels(vec![constraint.loc.primary(), field.loc.secondary()]),
1021 ),
1022 _ => (),
1023 }
1024 }
1025 Some(field @ Field { desc: FieldDesc::Typedef { type_id, .. }, .. }) => {
1026 match scope.typedef.get(type_id) {
1027 None => (),
1028 Some(Decl { desc: DeclDesc::Enum { tags, .. }, .. }) => match &constraint.tag_id {
1029 None => diagnostics.push(
1030 Diagnostic::error()
1031 .with_code(ErrorCode::E19)
1032 .with_message(format!(
1033 "invalid constraint value `{}`",
1034 constraint.value.unwrap()
1035 ))
1036 .with_labels(vec![
1037 constraint.loc.primary(),
1038 field.loc.secondary().with_message(format!(
1039 "`{}` is declared here as typedef field",
1040 constraint.id
1041 )),
1042 ])
1043 .with_notes(vec!["hint: expected enum value".to_owned()]),
1044 ),
1045 Some(tag_id) => match tags.iter().find(|tag| tag.id() == tag_id) {
1046 None => diagnostics.push(
1047 Diagnostic::error()
1048 .with_code(ErrorCode::E20)
1049 .with_message(format!("undeclared enum tag `{tag_id}`"))
1050 .with_labels(vec![
1051 constraint.loc.primary(),
1052 field.loc.secondary().with_message(format!(
1053 "`{}` is declared here",
1054 constraint.id
1055 )),
1056 ]),
1057 ),
1058 Some(Tag::Range { .. }) => diagnostics.push(
1059 Diagnostic::error()
1060 .with_code(ErrorCode::E42)
1061 .with_message(format!("enum tag `{tag_id}` defines a range"))
1062 .with_labels(vec![
1063 constraint.loc.primary(),
1064 field.loc.secondary().with_message(format!(
1065 "`{}` is declared here",
1066 constraint.id
1067 )),
1068 ])
1069 .with_notes(vec!["hint: expected enum tag with value".to_owned()]),
1070 ),
1071 Some(_) => (),
1072 },
1073 },
1074 Some(decl) => diagnostics.push(
1075 Diagnostic::error()
1076 .with_code(ErrorCode::E21)
1077 .with_message(format!(
1078 "invalid constraint identifier `{}`",
1079 constraint.value.unwrap()
1080 ))
1081 .with_labels(vec![
1082 constraint.loc.primary(),
1083 field.loc.secondary().with_message(format!(
1084 "`{}` is declared here as {} typedef field",
1085 constraint.id,
1086 decl.kind()
1087 )),
1088 ])
1089 .with_notes(vec!["hint: expected enum value".to_owned()]),
1090 ),
1091 }
1092 }
1093 Some(_) => unreachable!(),
1094 }
1095}
1096
1097fn check_constraints_list<'d>(
1099 constraints: &'d [Constraint],
1100 parent_decl: &Decl,
1101 scope: &Scope,
1102 mut constraints_by_id: HashMap<String, &'d Constraint>,
1103 diagnostics: &mut Diagnostics,
1104) {
1105 for constraint in constraints {
1106 check_constraint(constraint, parent_decl, scope, diagnostics);
1107 if let Some(prev) = constraints_by_id.insert(constraint.id.to_string(), constraint) {
1108 diagnostics.push(
1110 Diagnostic::error()
1111 .with_code(ErrorCode::DuplicateConstraintIdentifier)
1112 .with_message(format!("duplicate constraint identifier `{}`", constraint.id))
1113 .with_labels(vec![
1114 constraint.loc.primary(),
1115 prev.loc
1116 .secondary()
1117 .with_message(format!("`{}` is first constrained here", prev.id)),
1118 ]),
1119 )
1120 }
1121 }
1122}
1123
1124fn check_decl_constraints(file: &File, scope: &Scope) -> Result<(), Diagnostics> {
1134 let mut diagnostics: Diagnostics = Default::default();
1135 for decl in &file.declarations {
1136 match &decl.desc {
1138 DeclDesc::Packet { constraints, parent_id: Some(parent_id), .. }
1139 | DeclDesc::Struct { constraints, parent_id: Some(parent_id), .. } => {
1140 let parent_decl = scope.typedef.get(parent_id).unwrap();
1141 check_constraints_list(
1142 constraints,
1143 parent_decl,
1144 scope,
1145 scope.iter_parents(decl).fold(HashMap::new(), |acc, decl| {
1148 decl.constraints().fold(acc, |mut acc, constraint| {
1149 let _ = acc.insert(constraint.id.to_string(), constraint);
1150 acc
1151 })
1152 }),
1153 &mut diagnostics,
1154 )
1155 }
1156 _ => (),
1157 }
1158 }
1159
1160 diagnostics.err_or(())
1161}
1162
1163fn check_group_constraints(file: &File, scope: &Scope) -> Result<(), Diagnostics> {
1173 let mut diagnostics: Diagnostics = Default::default();
1174 for decl in &file.declarations {
1175 for field in decl.fields() {
1177 if let FieldDesc::Group { group_id, constraints } = &field.desc {
1178 let group_decl = scope.typedef.get(group_id).unwrap();
1179 check_constraints_list(
1180 constraints,
1181 group_decl,
1182 scope,
1183 HashMap::new(),
1184 &mut diagnostics,
1185 )
1186 }
1187 }
1188 }
1189
1190 diagnostics.err_or(())
1191}
1192
1193fn check_size_fields(file: &File) -> Result<(), Diagnostics> {
1205 let mut diagnostics: Diagnostics = Default::default();
1206 for decl in &file.declarations {
1207 let mut size_for_id = HashMap::new();
1208 let mut element_size_for_id = HashMap::new();
1209 for field in decl.fields() {
1210 if let Some((reverse_map, field_id, err)) = match &field.desc {
1212 FieldDesc::Size { field_id, .. } => {
1213 Some((&mut size_for_id, field_id, ErrorCode::DuplicateSizeField))
1214 }
1215 FieldDesc::Count { field_id, .. } => {
1216 Some((&mut size_for_id, field_id, ErrorCode::DuplicateCountField))
1217 }
1218 FieldDesc::ElementSize { field_id, .. } => {
1219 Some((&mut element_size_for_id, field_id, ErrorCode::DuplicateElementSizeField))
1220 }
1221 _ => None,
1222 } {
1223 if let Some(prev) = reverse_map.insert(field_id, field) {
1224 diagnostics.push(
1225 Diagnostic::error()
1226 .with_code(err)
1227 .with_message(format!("duplicate {} field", field.kind()))
1228 .with_labels(vec![
1229 field.loc.primary(),
1230 prev.loc.secondary().with_message(format!(
1231 "{} is first declared here",
1232 prev.kind()
1233 )),
1234 ]),
1235 )
1236 }
1237 }
1238
1239 match &field.desc {
1241 FieldDesc::Size { field_id, .. } => {
1242 match decl.fields().find(|field| match &field.desc {
1243 FieldDesc::Payload { .. } => field_id == "_payload_",
1244 FieldDesc::Body => field_id == "_body_",
1245 _ => field.id() == Some(field_id),
1246 }) {
1247 None => diagnostics.push(
1248 Diagnostic::error()
1249 .with_code(ErrorCode::UndeclaredSizeIdentifier)
1250 .with_message(format!(
1251 "undeclared {} identifier `{}`",
1252 field.kind(),
1253 field_id
1254 ))
1255 .with_labels(vec![field.loc.primary()])
1256 .with_notes(vec![
1257 "hint: expected payload, body, or array identifier".to_owned(),
1258 ]),
1259 ),
1260 Some(Field { desc: FieldDesc::Body, .. })
1261 | Some(Field { desc: FieldDesc::Payload { .. }, .. })
1262 | Some(Field { desc: FieldDesc::Array { .. }, .. }) => (),
1263 Some(Field { loc, .. }) => diagnostics.push(
1264 Diagnostic::error()
1265 .with_code(ErrorCode::InvalidSizeIdentifier)
1266 .with_message(format!(
1267 "invalid {} identifier `{}`",
1268 field.kind(),
1269 field_id
1270 ))
1271 .with_labels(vec![field.loc.primary(), loc.secondary()])
1272 .with_notes(vec![
1273 "hint: expected payload, body, or array identifier".to_owned(),
1274 ]),
1275 ),
1276 }
1277 }
1278
1279 FieldDesc::Count { field_id, .. } | FieldDesc::ElementSize { field_id, .. } => {
1280 let (undeclared_err, invalid_err) =
1281 if matches!(&field.desc, FieldDesc::Count { .. }) {
1282 (
1283 ErrorCode::UndeclaredCountIdentifier,
1284 ErrorCode::InvalidCountIdentifier,
1285 )
1286 } else {
1287 (
1288 ErrorCode::UndeclaredElementSizeIdentifier,
1289 ErrorCode::InvalidElementSizeIdentifier,
1290 )
1291 };
1292 match decl.fields().find(|field| field.id() == Some(field_id)) {
1293 None => diagnostics.push(
1294 Diagnostic::error()
1295 .with_code(undeclared_err)
1296 .with_message(format!(
1297 "undeclared {} identifier `{}`",
1298 field.kind(),
1299 field_id
1300 ))
1301 .with_labels(vec![field.loc.primary()])
1302 .with_notes(vec!["hint: expected array identifier".to_owned()]),
1303 ),
1304 Some(Field { desc: FieldDesc::Array { .. }, .. }) => (),
1305 Some(Field { loc, .. }) => diagnostics.push(
1306 Diagnostic::error()
1307 .with_code(invalid_err)
1308 .with_message(format!(
1309 "invalid {} identifier `{}`",
1310 field.kind(),
1311 field_id
1312 ))
1313 .with_labels(vec![field.loc.primary(), loc.secondary()])
1314 .with_notes(vec!["hint: expected array identifier".to_owned()]),
1315 ),
1316 }
1317 }
1318 _ => (),
1319 }
1320 }
1321 }
1322
1323 diagnostics.err_or(())
1324}
1325
1326fn check_fixed_fields(file: &File, scope: &Scope) -> Result<(), Diagnostics> {
1333 let mut diagnostics: Diagnostics = Default::default();
1334 for decl in &file.declarations {
1335 for field in decl.fields() {
1336 match &field.desc {
1337 FieldDesc::FixedScalar { value, width } if bit_width(*value) > *width => {
1338 diagnostics.push(
1339 Diagnostic::error()
1340 .with_code(ErrorCode::FixedValueOutOfRange)
1341 .with_message(format!(
1342 "fixed value `{value}` is larger than maximum value"
1343 ))
1344 .with_labels(vec![field.loc.primary()]),
1345 )
1346 }
1347 FieldDesc::FixedEnum { tag_id, enum_id } => match scope.typedef.get(enum_id) {
1348 None => diagnostics.push(
1349 Diagnostic::error()
1350 .with_code(ErrorCode::E33)
1351 .with_message(format!("undeclared type identifier `{enum_id}`"))
1352 .with_labels(vec![field.loc.primary()])
1353 .with_notes(vec!["hint: expected enum identifier".to_owned()]),
1354 ),
1355 Some(enum_decl @ Decl { desc: DeclDesc::Enum { tags, .. }, .. }) => {
1356 if !tags.iter().any(|tag| tag.id() == tag_id) {
1357 diagnostics.push(
1358 Diagnostic::error()
1359 .with_code(ErrorCode::E34)
1360 .with_message(format!("undeclared tag identifier `{tag_id}`"))
1361 .with_labels(vec![
1362 field.loc.primary(),
1363 enum_decl.loc.secondary(),
1364 ]),
1365 )
1366 }
1367 }
1368 Some(decl) => diagnostics.push(
1369 Diagnostic::error()
1370 .with_code(ErrorCode::E35)
1371 .with_message(format!("invalid type identifier `{enum_id}`"))
1372 .with_labels(vec![
1373 field.loc.primary(),
1374 decl.loc
1375 .secondary()
1376 .with_message(format!("`{enum_id}` is declared here")),
1377 ])
1378 .with_notes(vec!["hint: expected enum identifier".to_owned()]),
1379 ),
1380 },
1381 _ => (),
1382 }
1383 }
1384 }
1385
1386 diagnostics.err_or(())
1387}
1388
1389fn check_payload_fields(file: &File) -> Result<(), Diagnostics> {
1397 fn requires_payload(file: &File, decl: &Decl) -> bool {
1400 file.iter_children(decl).any(|child| child.fields().next().is_some())
1401 }
1402
1403 let mut diagnostics: Diagnostics = Default::default();
1404 for decl in &file.declarations {
1405 let mut payload: Option<&Field> = None;
1406 for field in decl.fields() {
1407 match &field.desc {
1408 FieldDesc::Payload { .. } | FieldDesc::Body => {
1409 if let Some(prev) = payload {
1410 diagnostics.push(
1411 Diagnostic::error()
1412 .with_code(ErrorCode::DuplicatePayloadField)
1413 .with_message(format!("duplicate {} field", field.kind()))
1414 .with_labels(vec![
1415 field.loc.primary(),
1416 prev.loc.secondary().with_message(format!(
1417 "{} is first declared here",
1418 prev.kind()
1419 )),
1420 ]),
1421 )
1422 } else {
1423 payload = Some(field);
1424 }
1425 }
1426 _ => (),
1427 }
1428 }
1429
1430 if payload.is_none() && requires_payload(file, decl) {
1431 diagnostics.push(
1432 Diagnostic::error()
1433 .with_code(ErrorCode::MissingPayloadField)
1434 .with_message("missing payload field".to_owned())
1435 .with_labels(vec![decl.loc.primary()])
1436 .with_notes(vec![format!(
1437 "hint: one child packet is extending `{}`",
1438 decl.id().unwrap()
1439 )]),
1440 )
1441 }
1442 }
1443
1444 diagnostics.err_or(())
1445}
1446
1447fn check_array_fields(file: &File) -> Result<(), Diagnostics> {
1451 let mut diagnostics: Diagnostics = Default::default();
1452 for decl in &file.declarations {
1453 for field in decl.fields() {
1454 if let FieldDesc::Array { id, size: Some(size), .. } = &field.desc {
1455 if let Some(size_field) = decl.fields().find(|field| match &field.desc {
1456 FieldDesc::Size { field_id, .. } | FieldDesc::Count { field_id, .. } => {
1457 field_id == id
1458 }
1459 _ => false,
1460 }) {
1461 diagnostics.push(
1462 Diagnostic::error()
1463 .with_code(ErrorCode::RedundantArraySize)
1464 .with_message(format!("redundant array {} field", size_field.kind()))
1465 .with_labels(vec![
1466 size_field.loc.primary(),
1467 field
1468 .loc
1469 .secondary()
1470 .with_message(format!("`{id}` has constant size {size}")),
1471 ]),
1472 )
1473 }
1474 }
1475 }
1476 }
1477
1478 diagnostics.err_or(())
1479}
1480
1481fn check_padding_fields(file: &File) -> Result<(), Diagnostics> {
1485 let mut diagnostics: Diagnostics = Default::default();
1486 for decl in &file.declarations {
1487 let mut previous_is_array = false;
1488 for field in decl.fields() {
1489 match &field.desc {
1490 FieldDesc::Padding { .. } if !previous_is_array => diagnostics.push(
1491 Diagnostic::error()
1492 .with_code(ErrorCode::InvalidPaddingField)
1493 .with_message("padding field does not follow an array field".to_owned())
1494 .with_labels(vec![field.loc.primary()]),
1495 ),
1496 FieldDesc::Array { .. } => previous_is_array = true,
1497 _ => previous_is_array = false,
1498 }
1499 }
1500 }
1501
1502 diagnostics.err_or(())
1503}
1504
1505fn check_checksum_fields(_file: &File, _scope: &Scope) -> Result<(), Diagnostics> {
1511 Ok(())
1513}
1514
1515fn check_optional_fields(file: &File) -> Result<(), Diagnostics> {
1522 let mut diagnostics: Diagnostics = Default::default();
1523 for decl in &file.declarations {
1524 let mut local_scope: HashMap<String, &Field> = HashMap::new();
1525 for field in decl.fields() {
1526 if let Some(ref cond) = field.cond {
1527 match &field.desc {
1528 FieldDesc::Scalar { .. } | FieldDesc::Typedef { .. } => (),
1529 _ => diagnostics.push(
1530 Diagnostic::error()
1531 .with_code(ErrorCode::InvalidOptionalField)
1532 .with_message("invalid optional field".to_owned())
1533 .with_labels(vec![field.loc.primary()])
1534 .with_notes(vec!["note: expected scalar, or typedef field".to_owned()]),
1535 ),
1536 }
1537 match local_scope.get(&cond.id) {
1538 None => diagnostics.push(
1539 Diagnostic::error()
1540 .with_code(ErrorCode::UndeclaredConditionIdentifier)
1541 .with_message("undeclared condition identifier".to_owned())
1542 .with_labels(vec![field.loc.primary()])
1543 .with_notes(vec!["note: expected scalar field identifier".to_owned()]),
1544 ),
1545 Some(Field { cond: Some(_), loc, .. }) => diagnostics.push(
1546 Diagnostic::error()
1547 .with_code(ErrorCode::E49)
1548 .with_message("invalid condition identifier".to_owned())
1549 .with_labels(vec![
1550 field.loc.primary(),
1551 loc.secondary().with_message(format!(
1552 "`{}` is declared optional here",
1553 cond.id
1554 )),
1555 ])
1556 .with_notes(vec!["note: expected scalar field identifier".to_owned()]),
1557 ),
1558 Some(Field { desc: FieldDesc::Scalar { width: 1, .. }, .. }) => (),
1559 Some(Field { desc: FieldDesc::Scalar { width, .. }, loc, .. }) => diagnostics
1560 .push(
1561 Diagnostic::error()
1562 .with_code(ErrorCode::InvalidConditionIdentifier)
1563 .with_message("invalid condition identifier".to_owned())
1564 .with_labels(vec![
1565 field.loc.primary(),
1566 loc.secondary().with_message(format!(
1567 "`{}` is declared with width `{}` here",
1568 cond.id, width
1569 )),
1570 ])
1571 .with_notes(vec![
1572 "note: expected scalar field identifier".to_owned()
1573 ]),
1574 ),
1575 Some(Field { loc, .. }) => diagnostics.push(
1576 Diagnostic::error()
1577 .with_code(ErrorCode::InvalidConditionIdentifier)
1578 .with_message("invalid condition identifier".to_owned())
1579 .with_labels(vec![
1580 field.loc.primary(),
1581 loc.secondary()
1582 .with_message(format!("`{}` is declared here", cond.id)),
1583 ])
1584 .with_notes(vec!["note: expected scalar field identifier".to_owned()]),
1585 ),
1586 }
1587 match (&cond.value, &cond.tag_id) {
1588 (_, Some(_)) => diagnostics.push(
1589 Diagnostic::error()
1590 .with_code(ErrorCode::InvalidConditionValue)
1591 .with_message("invalid condition value".to_owned())
1592 .with_labels(vec![field.loc.primary()])
1593 .with_notes(vec!["note: expected 0 or 1".to_owned()]),
1594 ),
1595 (Some(0), _) | (Some(1), _) => (),
1596 (Some(_), _) => diagnostics.push(
1597 Diagnostic::error()
1598 .with_code(ErrorCode::InvalidConditionValue)
1599 .with_message("invalid condition value".to_owned())
1600 .with_labels(vec![field.loc.primary()])
1601 .with_notes(vec!["note: expected 0 or 1".to_owned()]),
1602 ),
1603 _ => unreachable!(),
1604 }
1605 }
1606 if let Some(id) = field.id() {
1607 local_scope.insert(id.to_owned(), field);
1608 }
1609 }
1610 }
1611 diagnostics.err_or(())
1612}
1613
1614fn check_field_offsets(file: &File, scope: &Scope, schema: &Schema) -> Result<(), Diagnostics> {
1618 let mut diagnostics: Diagnostics = Default::default();
1619 for decl in &file.declarations {
1620 let mut offset = 0;
1621
1622 for field in decl.fields() {
1623 match &field.desc {
1624 FieldDesc::Typedef { type_id, .. }
1625 if matches!(
1626 scope.typedef.get(type_id),
1627 Some(Decl { desc: DeclDesc::Enum { .. }, .. })
1628 ) => {}
1629 FieldDesc::Payload { .. }
1630 | FieldDesc::Body
1631 | FieldDesc::Typedef { .. }
1632 | FieldDesc::Array { .. }
1633 | FieldDesc::Padding { .. }
1634 | FieldDesc::Checksum { .. } => {
1635 if offset % 8 != 0 {
1636 diagnostics.push(
1637 Diagnostic::error()
1638 .with_code(ErrorCode::InvalidFieldOffset)
1639 .with_message(format!(
1640 "{} field is not aligned to an octet boundary",
1641 field.kind()
1642 ))
1643 .with_labels(vec![field.loc.primary()]),
1644 )
1645 }
1646 }
1647 FieldDesc::Size { .. }
1648 | FieldDesc::Count { .. }
1649 | FieldDesc::ElementSize { .. }
1650 | FieldDesc::FixedEnum { .. }
1651 | FieldDesc::FixedScalar { .. }
1652 | FieldDesc::Group { .. }
1653 | FieldDesc::Flag { .. }
1654 | FieldDesc::Reserved { .. }
1655 | FieldDesc::Scalar { .. } => (),
1656 }
1657 offset = match schema.field_size[&field.key] {
1658 Size::Static(size) => offset + size,
1659 Size::Dynamic | Size::Unknown => 0,
1660 };
1661 }
1662 }
1663 diagnostics.err_or(())
1664}
1665
1666fn check_decl_sizes(file: &File, schema: &Schema) -> Result<(), Diagnostics> {
1672 let mut diagnostics: Diagnostics = Default::default();
1673 for decl in &file.declarations {
1674 let mut static_size = 0;
1675
1676 for field in decl.fields() {
1677 match &field.desc {
1678 FieldDesc::Array { width: Some(width), .. } if width % 8 != 0 => diagnostics.push(
1679 Diagnostic::error()
1680 .with_code(ErrorCode::InvalidFieldSize)
1681 .with_message(
1682 "array element size is not an integral number of octets".to_owned(),
1683 )
1684 .with_labels(vec![field.loc.primary()]),
1685 ),
1686 _ => (),
1687 }
1688 static_size += schema.field_size[&field.key].static_().unwrap_or(0);
1689 }
1690
1691 if static_size % 8 != 0 {
1692 diagnostics.push(
1693 Diagnostic::error()
1694 .with_code(ErrorCode::InvalidPacketSize)
1695 .with_message(format!(
1696 "{} size is not an integral number of octets",
1697 decl.kind()
1698 ))
1699 .with_labels(vec![decl.loc.primary()]),
1700 )
1701 }
1702 }
1703 diagnostics.err_or(())
1704}
1705
1706fn inline_groups(file: &File) -> Result<File, Diagnostics> {
1708 fn inline_fields<'a>(
1709 fields: impl Iterator<Item = &'a Field>,
1710 groups: &HashMap<String, &Decl>,
1711 constraints: &HashMap<String, Constraint>,
1712 ) -> Vec<Field> {
1713 fields
1714 .flat_map(|field| match &field.desc {
1715 FieldDesc::Group { group_id, constraints: group_constraints } => {
1716 let mut constraints = constraints.clone();
1717 constraints.extend(
1718 group_constraints
1719 .iter()
1720 .map(|constraint| (constraint.id.clone(), constraint.clone())),
1721 );
1722 inline_fields(groups.get(group_id).unwrap().fields(), groups, &constraints)
1723 }
1724 FieldDesc::Scalar { id, width } if constraints.contains_key(id) => {
1725 vec![Field {
1726 desc: FieldDesc::FixedScalar {
1727 width: *width,
1728 value: constraints.get(id).unwrap().value.unwrap(),
1729 },
1730 loc: field.loc,
1731 key: field.key,
1732 cond: field.cond.clone(),
1733 }]
1734 }
1735 FieldDesc::Typedef { id, type_id, .. } if constraints.contains_key(id) => {
1736 vec![Field {
1737 desc: FieldDesc::FixedEnum {
1738 enum_id: type_id.clone(),
1739 tag_id: constraints
1740 .get(id)
1741 .and_then(|constraint| constraint.tag_id.clone())
1742 .unwrap(),
1743 },
1744 loc: field.loc,
1745 key: field.key,
1746 cond: field.cond.clone(),
1747 }]
1748 }
1749 _ => vec![field.clone()],
1750 })
1751 .collect()
1752 }
1753
1754 let groups = file
1755 .declarations
1756 .iter()
1757 .filter(|decl| matches!(&decl.desc, DeclDesc::Group { .. }))
1758 .map(|decl| (decl.id().unwrap().to_owned(), decl))
1759 .collect::<HashMap<String, _>>();
1760
1761 let declarations = file
1762 .declarations
1763 .iter()
1764 .filter_map(|decl| match &decl.desc {
1765 DeclDesc::Packet { fields, id, parent_id, constraints } => Some(Decl {
1766 desc: DeclDesc::Packet {
1767 fields: inline_fields(fields.iter(), &groups, &HashMap::new()),
1768 id: id.clone(),
1769 parent_id: parent_id.clone(),
1770 constraints: constraints.clone(),
1771 },
1772 loc: decl.loc,
1773 key: decl.key,
1774 }),
1775 DeclDesc::Struct { fields, id, parent_id, constraints } => Some(Decl {
1776 desc: DeclDesc::Struct {
1777 fields: inline_fields(fields.iter(), &groups, &HashMap::new()),
1778 id: id.clone(),
1779 parent_id: parent_id.clone(),
1780 constraints: constraints.clone(),
1781 },
1782 loc: decl.loc,
1783 key: decl.key,
1784 }),
1785 DeclDesc::Group { .. } => None,
1786 _ => Some(decl.clone()),
1787 })
1788 .collect();
1789
1790 Ok(File {
1791 declarations,
1792 version: file.version.clone(),
1793 file: file.file,
1794 comments: file.comments.clone(),
1795 endianness: file.endianness,
1796 max_key: file.max_key,
1798 })
1799}
1800
1801fn desugar_flags(file: &mut File) {
1804 for decl in &mut file.declarations {
1805 match &mut decl.desc {
1806 DeclDesc::Packet { fields, .. }
1807 | DeclDesc::Struct { fields, .. }
1808 | DeclDesc::Group { fields, .. } => {
1809 let mut condition_ids: HashMap<String, Vec<(String, usize)>> = HashMap::new();
1811 for field in fields.iter() {
1812 if let Some(ref cond) = field.cond {
1813 condition_ids
1814 .entry(cond.id.to_owned())
1815 .or_default()
1816 .push((field.id().unwrap().to_owned(), cond.value.unwrap()));
1817 }
1818 }
1819 for field in fields.iter_mut() {
1821 if let Some(optional_field_ids) =
1822 field.id().and_then(|id| condition_ids.get(id))
1823 {
1824 field.desc = FieldDesc::Flag {
1825 id: field.id().unwrap().to_owned(),
1826 optional_field_ids: optional_field_ids.to_owned(),
1827 };
1828 }
1829 }
1830 }
1831 _ => (),
1832 }
1833 }
1834}
1835
1836pub fn analyze(file: &File) -> Result<File, Diagnostics> {
1839 let scope = Scope::new(file)?;
1840 check_decl_identifiers(file, &scope)?;
1841 check_field_identifiers(file)?;
1842 check_enum_declarations(file)?;
1843 check_size_fields(file)?;
1844 check_fixed_fields(file, &scope)?;
1845 check_payload_fields(file)?;
1846 check_array_fields(file)?;
1847 check_padding_fields(file)?;
1848 check_checksum_fields(file, &scope)?;
1849 check_optional_fields(file)?;
1850 check_group_constraints(file, &scope)?;
1851 let mut file = inline_groups(file)?;
1852 desugar_flags(&mut file);
1853 let scope = Scope::new(&file)?;
1854 check_decl_constraints(&file, &scope)?;
1855 let schema = Schema::new(&file);
1856 check_field_offsets(&file, &scope, &schema)?;
1857 check_decl_sizes(&file, &schema)?;
1858 Ok(file)
1859}
1860
1861#[cfg(test)]
1862mod test {
1863 use crate::analyzer;
1864 use crate::ast;
1865 use crate::parser::parse_inline;
1866 use codespan_reporting::term::termcolor;
1867
1868 use googletest::prelude::{assert_that, eq};
1869
1870 macro_rules! raises {
1871 ($code:ident, $text:literal) => {{
1872 let mut db = ast::SourceDatabase::new();
1873 let file = parse_inline(&mut db, "stdin", $text.to_owned()).expect("parsing failure");
1874 let result = analyzer::analyze(&file);
1875 assert!(matches!(result, Err(_)));
1876 let diagnostics = result.err().unwrap();
1877 let mut buffer = termcolor::Buffer::no_color();
1878 let _ = diagnostics.emit(&db, &mut buffer);
1879 println!("{}", std::str::from_utf8(buffer.as_slice()).unwrap());
1880 assert_eq!(diagnostics.diagnostics.len(), 1);
1881 assert_eq!(diagnostics.diagnostics[0].code, Some(analyzer::ErrorCode::$code.into()));
1882 }};
1883 }
1884
1885 macro_rules! valid {
1886 ($text:literal) => {{
1887 let mut db = ast::SourceDatabase::new();
1888 let file = parse_inline(&mut db, "stdin", $text.to_owned()).expect("parsing failure");
1889 assert!(analyzer::analyze(&file).is_ok());
1890 }};
1891 }
1892
1893 #[test]
1894 fn test_e1() {
1895 raises!(
1896 DuplicateDeclIdentifier,
1897 r#"
1898 little_endian_packets
1899 struct A { }
1900 packet A { }
1901 "#
1902 );
1903
1904 raises!(
1905 DuplicateDeclIdentifier,
1906 r#"
1907 little_endian_packets
1908 struct A { }
1909 enum A : 8 { X = 0, Y = 1 }
1910 "#
1911 );
1912 }
1913
1914 #[test]
1915 fn test_e2() {
1916 raises!(
1917 RecursiveDecl,
1918 r#"
1919 little_endian_packets
1920 packet A : A { }
1921 "#
1922 );
1923
1924 raises!(
1925 RecursiveDecl,
1926 r#"
1927 little_endian_packets
1928 packet A : B { }
1929 packet B : A { }
1930 "#
1931 );
1932
1933 raises!(
1934 RecursiveDecl,
1935 r#"
1936 little_endian_packets
1937 struct B { x : B }
1938 "#
1939 );
1940
1941 raises!(
1942 RecursiveDecl,
1943 r#"
1944 little_endian_packets
1945 struct B { x : B[8] }
1946 "#
1947 );
1948
1949 raises!(
1950 RecursiveDecl,
1951 r#"
1952 little_endian_packets
1953 group C { C { x = 1 } }
1954 "#
1955 );
1956 }
1957
1958 #[test]
1959 fn test_e3() {
1960 raises!(
1961 UndeclaredGroupIdentifier,
1962 r#"
1963 little_endian_packets
1964 packet A { C { x = 1 } }
1965 "#
1966 );
1967 }
1968
1969 #[test]
1970 fn test_e4() {
1971 raises!(
1972 InvalidGroupIdentifier,
1973 r#"
1974 little_endian_packets
1975 struct C { x : 8 }
1976 packet A { C { x = 1 } }
1977 "#
1978 );
1979 }
1980
1981 #[test]
1982 fn test_e5() {
1983 raises!(
1984 UndeclaredTypeIdentifier,
1985 r#"
1986 little_endian_packets
1987 packet A { x : B }
1988 "#
1989 );
1990
1991 raises!(
1992 UndeclaredTypeIdentifier,
1993 r#"
1994 little_endian_packets
1995 packet A { x : B[] }
1996 "#
1997 );
1998 }
1999
2000 #[test]
2001 fn test_e6() {
2002 raises!(
2003 InvalidTypeIdentifier,
2004 r#"
2005 little_endian_packets
2006 packet A { x : 8 }
2007 packet B { x : A }
2008 "#
2009 );
2010
2011 raises!(
2012 InvalidTypeIdentifier,
2013 r#"
2014 little_endian_packets
2015 packet A { x : 8 }
2016 packet B { x : A[] }
2017 "#
2018 );
2019 }
2020
2021 #[test]
2022 fn test_e7() {
2023 raises!(
2024 UndeclaredParentIdentifier,
2025 r#"
2026 little_endian_packets
2027 packet A : B { }
2028 "#
2029 );
2030
2031 raises!(
2032 UndeclaredParentIdentifier,
2033 r#"
2034 little_endian_packets
2035 struct A : B { }
2036 "#
2037 );
2038 }
2039
2040 #[test]
2041 fn test_e8() {
2042 raises!(
2043 InvalidParentIdentifier,
2044 r#"
2045 little_endian_packets
2046 struct A { }
2047 packet B : A { }
2048 "#
2049 );
2050
2051 raises!(
2052 InvalidParentIdentifier,
2053 r#"
2054 little_endian_packets
2055 packet A { }
2056 struct B : A { }
2057 "#
2058 );
2059
2060 raises!(
2061 InvalidParentIdentifier,
2062 r#"
2063 little_endian_packets
2064 group A { x : 1 }
2065 struct B : A { }
2066 "#
2067 );
2068 }
2069
2070 #[ignore]
2071 #[test]
2072 fn test_e9() {
2073 raises!(
2074 UndeclaredTestIdentifier,
2075 r#"
2076 little_endian_packets
2077 test A { "aaa" }
2078 "#
2079 );
2080 }
2081
2082 #[ignore]
2083 #[test]
2084 fn test_e10() {
2085 raises!(
2086 InvalidTestIdentifier,
2087 r#"
2088 little_endian_packets
2089 struct A { }
2090 test A { "aaa" }
2091 "#
2092 );
2093
2094 raises!(
2095 InvalidTestIdentifier,
2096 r#"
2097 little_endian_packets
2098 group A { x : 8 }
2099 test A { "aaa" }
2100 "#
2101 );
2102 }
2103
2104 #[test]
2105 fn test_e11() {
2106 raises!(
2107 DuplicateFieldIdentifier,
2108 r#"
2109 little_endian_packets
2110 enum A : 8 { X = 0 }
2111 struct B {
2112 x : 8,
2113 x : A
2114 }
2115 "#
2116 );
2117
2118 raises!(
2119 DuplicateFieldIdentifier,
2120 r#"
2121 little_endian_packets
2122 enum A : 8 { X = 0 }
2123 packet B {
2124 x : 8,
2125 x : A[]
2126 }
2127 "#
2128 );
2129 }
2130
2131 #[test]
2132 fn test_e12() {
2133 raises!(
2134 DuplicateTagIdentifier,
2135 r#"
2136 little_endian_packets
2137 enum A : 8 {
2138 X = 0,
2139 X = 1,
2140 }
2141 "#
2142 );
2143
2144 raises!(
2145 DuplicateTagIdentifier,
2146 r#"
2147 little_endian_packets
2148 enum A : 8 {
2149 X = 0,
2150 A = 1..10 {
2151 X = 1,
2152 }
2153 }
2154 "#
2155 );
2156
2157 raises!(
2158 DuplicateTagIdentifier,
2159 r#"
2160 little_endian_packets
2161 enum A : 8 {
2162 X = 0,
2163 X = 1..10,
2164 }
2165 "#
2166 );
2167
2168 raises!(
2169 DuplicateTagIdentifier,
2170 r#"
2171 little_endian_packets
2172 enum A : 8 {
2173 X = 0,
2174 X = ..,
2175 }
2176 "#
2177 );
2178 }
2179
2180 #[test]
2181 fn test_e13() {
2182 raises!(
2183 DuplicateTagValue,
2184 r#"
2185 little_endian_packets
2186 enum A : 8 {
2187 X = 0,
2188 Y = 0,
2189 }
2190 "#
2191 );
2192
2193 raises!(
2194 DuplicateTagValue,
2195 r#"
2196 little_endian_packets
2197 enum A : 8 {
2198 A = 1..10 {
2199 X = 1,
2200 Y = 1,
2201 }
2202 }
2203 "#
2204 );
2205 }
2206
2207 #[test]
2208 fn test_e14() {
2209 raises!(
2210 InvalidTagValue,
2211 r#"
2212 little_endian_packets
2213 enum A : 8 {
2214 X = 256,
2215 }
2216 "#
2217 );
2218
2219 raises!(
2220 InvalidTagValue,
2221 r#"
2222 little_endian_packets
2223 enum A : 8 {
2224 A = 0,
2225 X = 10..20 {
2226 B = 1,
2227 },
2228 }
2229 "#
2230 );
2231 }
2232
2233 #[test]
2234 fn test_e15() {
2235 raises!(
2236 UndeclaredConstraintIdentifier,
2237 r#"
2238 little_endian_packets
2239 packet A { }
2240 packet B : A (x = 1) { }
2241 "#
2242 );
2243
2244 raises!(
2245 UndeclaredConstraintIdentifier,
2246 r#"
2247 little_endian_packets
2248 group A { x : 8 }
2249 packet B {
2250 A { y = 1 }
2251 }
2252 "#
2253 );
2254
2255 valid!(
2256 r#"
2257 little_endian_packets
2258 group A { x : 8 }
2259 packet B { A }
2260 packet C : B (x = 1) { }
2261 "#
2262 );
2263 }
2264
2265 #[test]
2266 fn test_e16() {
2267 raises!(
2268 InvalidConstraintIdentifier,
2269 r#"
2270 little_endian_packets
2271 packet A { x : 8[] }
2272 packet B : A (x = 1) { }
2273 "#
2274 );
2275
2276 raises!(
2277 InvalidConstraintIdentifier,
2278 r#"
2279 little_endian_packets
2280 group A { x : 8[] }
2281 packet B {
2282 A { x = 1 }
2283 }
2284 "#
2285 );
2286 }
2287
2288 #[test]
2289 fn test_e17() {
2290 raises!(
2291 E17,
2292 r#"
2293 little_endian_packets
2294 packet A { x : 8 }
2295 packet B : A (x = X) { }
2296 "#
2297 );
2298
2299 raises!(
2300 E17,
2301 r#"
2302 little_endian_packets
2303 group A { x : 8 }
2304 packet B {
2305 A { x = X }
2306 }
2307 "#
2308 );
2309 }
2310
2311 #[test]
2312 fn test_e18() {
2313 raises!(
2314 ConstraintValueOutOfRange,
2315 r#"
2316 little_endian_packets
2317 packet A { x : 8 }
2318 packet B : A (x = 256) { }
2319 "#
2320 );
2321
2322 raises!(
2323 ConstraintValueOutOfRange,
2324 r#"
2325 little_endian_packets
2326 group A { x : 8 }
2327 packet B {
2328 A { x = 256 }
2329 }
2330 "#
2331 );
2332 }
2333
2334 #[test]
2335 fn test_e19() {
2336 raises!(
2337 E19,
2338 r#"
2339 little_endian_packets
2340 enum C : 8 { X = 0 }
2341 packet A { x : C }
2342 packet B : A (x = 0) { }
2343 "#
2344 );
2345
2346 raises!(
2347 E19,
2348 r#"
2349 little_endian_packets
2350 enum C : 8 { X = 0 }
2351 group A { x : C }
2352 packet B {
2353 A { x = 0 }
2354 }
2355 "#
2356 );
2357 }
2358
2359 #[test]
2360 fn test_e20() {
2361 raises!(
2362 E20,
2363 r#"
2364 little_endian_packets
2365 enum C : 8 { X = 0 }
2366 packet A { x : C }
2367 packet B : A (x = Y) { }
2368 "#
2369 );
2370
2371 raises!(
2372 E20,
2373 r#"
2374 little_endian_packets
2375 enum C : 8 { X = 0 }
2376 group A { x : C }
2377 packet B {
2378 A { x = Y }
2379 }
2380 "#
2381 );
2382 }
2383
2384 #[test]
2385 fn test_e21() {
2386 raises!(
2387 E21,
2388 r#"
2389 little_endian_packets
2390 struct C { }
2391 packet A { x : C }
2392 packet B : A (x = 0) { }
2393 "#
2394 );
2395
2396 raises!(
2397 E21,
2398 r#"
2399 little_endian_packets
2400 struct C { }
2401 group A { x : C }
2402 packet B {
2403 A { x = 0 }
2404 }
2405 "#
2406 );
2407 }
2408
2409 #[test]
2410 fn test_e22() {
2411 raises!(
2412 DuplicateConstraintIdentifier,
2413 r#"
2414 little_endian_packets
2415 packet A { x: 8 }
2416 packet B : A (x = 0, x = 1) { }
2417 "#
2418 );
2419
2420 raises!(
2421 DuplicateConstraintIdentifier,
2422 r#"
2423 little_endian_packets
2424 packet A { x: 8 }
2425 packet B : A (x = 0) { }
2426 packet C : B (x = 1) { }
2427 "#
2428 );
2429
2430 raises!(
2431 DuplicateConstraintIdentifier,
2432 r#"
2433 little_endian_packets
2434 group A { x : 8 }
2435 packet B {
2436 A { x = 0, x = 1 }
2437 }
2438 "#
2439 );
2440 }
2441
2442 #[test]
2443 fn test_e23() {
2444 raises!(
2445 DuplicateSizeField,
2446 r#"
2447 little_endian_packets
2448 struct A {
2449 _size_ (_payload_) : 8,
2450 _size_ (_payload_) : 8,
2451 _payload_,
2452 }
2453 "#
2454 );
2455
2456 raises!(
2457 DuplicateSizeField,
2458 r#"
2459 little_endian_packets
2460 struct A {
2461 _count_ (x) : 8,
2462 _size_ (x) : 8,
2463 x: 8[],
2464 }
2465 "#
2466 );
2467 }
2468
2469 #[test]
2470 fn test_e24() {
2471 raises!(
2472 UndeclaredSizeIdentifier,
2473 r#"
2474 little_endian_packets
2475 struct A {
2476 _size_ (x) : 8,
2477 }
2478 "#
2479 );
2480
2481 raises!(
2482 UndeclaredSizeIdentifier,
2483 r#"
2484 little_endian_packets
2485 struct A {
2486 _size_ (_payload_) : 8,
2487 }
2488 "#
2489 );
2490 }
2491
2492 #[test]
2493 fn test_e25() {
2494 raises!(
2495 InvalidSizeIdentifier,
2496 r#"
2497 little_endian_packets
2498 enum B : 8 { X = 0 }
2499 struct A {
2500 _size_ (x) : 8,
2501 x : B,
2502 }
2503 "#
2504 );
2505 }
2506
2507 #[test]
2508 fn test_e26() {
2509 raises!(
2510 DuplicateCountField,
2511 r#"
2512 little_endian_packets
2513 struct A {
2514 _size_ (x) : 8,
2515 _count_ (x) : 8,
2516 x: 8[],
2517 }
2518 "#
2519 );
2520 }
2521
2522 #[test]
2523 fn test_e27() {
2524 raises!(
2525 UndeclaredCountIdentifier,
2526 r#"
2527 little_endian_packets
2528 struct A {
2529 _count_ (x) : 8,
2530 }
2531 "#
2532 );
2533 }
2534
2535 #[test]
2536 fn test_e28() {
2537 raises!(
2538 InvalidCountIdentifier,
2539 r#"
2540 little_endian_packets
2541 enum B : 8 { X = 0 }
2542 struct A {
2543 _count_ (x) : 8,
2544 x : B,
2545 }
2546 "#
2547 );
2548 }
2549
2550 #[test]
2551 fn test_e29() {
2552 raises!(
2553 DuplicateElementSizeField,
2554 r#"
2555 little_endian_packets
2556 struct A {
2557 _elementsize_ (x) : 8,
2558 _elementsize_ (x) : 8,
2559 x: 8[],
2560 }
2561 "#
2562 );
2563 }
2564
2565 #[test]
2566 fn test_e30() {
2567 raises!(
2568 UndeclaredElementSizeIdentifier,
2569 r#"
2570 little_endian_packets
2571 struct A {
2572 _elementsize_ (x) : 8,
2573 }
2574 "#
2575 );
2576 }
2577
2578 #[test]
2579 fn test_e31() {
2580 raises!(
2581 InvalidElementSizeIdentifier,
2582 r#"
2583 little_endian_packets
2584 enum B : 8 { X = 0 }
2585 struct A {
2586 _elementsize_ (x) : 8,
2587 x : B,
2588 }
2589 "#
2590 );
2591 }
2592
2593 #[test]
2594 fn test_e32() {
2595 raises!(
2596 FixedValueOutOfRange,
2597 r#"
2598 little_endian_packets
2599 struct A {
2600 _fixed_ = 256 : 8,
2601 }
2602 "#
2603 );
2604 }
2605
2606 #[test]
2607 fn test_e33() {
2608 raises!(
2609 E33,
2610 r#"
2611 little_endian_packets
2612 struct A {
2613 _fixed_ = X : B,
2614 }
2615 "#
2616 );
2617 }
2618
2619 #[test]
2620 fn test_e34() {
2621 raises!(
2622 E34,
2623 r#"
2624 little_endian_packets
2625 enum B : 8 { X = 0 }
2626 struct A {
2627 _fixed_ = Y : B,
2628 }
2629 "#
2630 );
2631 }
2632
2633 #[test]
2634 fn test_e35() {
2635 raises!(
2636 E35,
2637 r#"
2638 little_endian_packets
2639 struct B { }
2640 struct A {
2641 _fixed_ = X : B,
2642 }
2643 "#
2644 );
2645 }
2646
2647 #[test]
2648 fn test_e36() {
2649 raises!(
2650 DuplicatePayloadField,
2651 r#"
2652 little_endian_packets
2653 packet A {
2654 _payload_,
2655 _body_,
2656 }
2657 "#
2658 );
2659
2660 raises!(
2661 DuplicatePayloadField,
2662 r#"
2663 little_endian_packets
2664 packet A {
2665 _body_,
2666 _payload_,
2667 }
2668 "#
2669 );
2670 }
2671
2672 #[test]
2673 fn test_e37() {
2674 raises!(
2675 MissingPayloadField,
2676 r#"
2677 little_endian_packets
2678 packet A { x : 8 }
2679 packet B : A { y : 8 }
2680 "#
2681 );
2682
2683 raises!(
2684 MissingPayloadField,
2685 r#"
2686 little_endian_packets
2687 packet A { x : 8 }
2688 packet B : A (x = 0) { }
2689 packet C : B { y : 8 }
2690 "#
2691 );
2692 }
2693
2694 #[test]
2695 fn test_e38() {
2696 raises!(
2697 RedundantArraySize,
2698 r#"
2699 little_endian_packets
2700 packet A {
2701 _size_ (x) : 8,
2702 x : 8[8]
2703 }
2704 "#
2705 );
2706
2707 raises!(
2708 RedundantArraySize,
2709 r#"
2710 little_endian_packets
2711 packet A {
2712 _count_ (x) : 8,
2713 x : 8[8]
2714 }
2715 "#
2716 );
2717 }
2718
2719 #[test]
2720 fn test_e39() {
2721 raises!(
2722 InvalidPaddingField,
2723 r#"
2724 little_endian_packets
2725 packet A {
2726 _padding_ [16],
2727 x : 8[]
2728 }
2729 "#
2730 );
2731
2732 raises!(
2733 InvalidPaddingField,
2734 r#"
2735 little_endian_packets
2736 enum A : 8 { X = 0 }
2737 packet B {
2738 x : A,
2739 _padding_ [16]
2740 }
2741 "#
2742 );
2743
2744 valid!(
2745 r#"
2746 little_endian_packets
2747 packet A {
2748 x : 8[],
2749 _padding_ [16]
2750 }
2751 "#
2752 );
2753 }
2754
2755 #[test]
2756 fn test_e40() {
2757 raises!(
2758 InvalidTagRange,
2759 r#"
2760 little_endian_packets
2761 enum A : 8 {
2762 X = 4..2,
2763 }
2764 "#
2765 );
2766
2767 raises!(
2768 InvalidTagRange,
2769 r#"
2770 little_endian_packets
2771 enum A : 8 {
2772 X = 2..2,
2773 }
2774 "#
2775 );
2776
2777 raises!(
2778 InvalidTagRange,
2779 r#"
2780 little_endian_packets
2781 enum A : 8 {
2782 X = 258..259,
2783 }
2784 "#
2785 );
2786 }
2787
2788 #[test]
2789 fn test_e41() {
2790 raises!(
2791 DuplicateTagRange,
2792 r#"
2793 little_endian_packets
2794 enum A : 8 {
2795 X = 0..15,
2796 Y = 8..31,
2797 }
2798 "#
2799 );
2800
2801 raises!(
2802 DuplicateTagRange,
2803 r#"
2804 little_endian_packets
2805 enum A : 8 {
2806 X = 8..31,
2807 Y = 0..15,
2808 }
2809 "#
2810 );
2811
2812 raises!(
2813 DuplicateTagRange,
2814 r#"
2815 little_endian_packets
2816 enum A : 8 {
2817 X = 1..9,
2818 Y = 9..11,
2819 }
2820 "#
2821 );
2822 }
2823
2824 #[test]
2825 fn test_e42() {
2826 raises!(
2827 E42,
2828 r#"
2829 little_endian_packets
2830 enum C : 8 { X = 0..15 }
2831 packet A { x : C }
2832 packet B : A (x = X) { }
2833 "#
2834 );
2835
2836 raises!(
2837 E42,
2838 r#"
2839 little_endian_packets
2840 enum C : 8 { X = 0..15 }
2841 group A { x : C }
2842 packet B {
2843 A { x = X }
2844 }
2845 "#
2846 );
2847 }
2848
2849 #[test]
2850 fn test_e43() {
2851 raises!(
2852 E43,
2853 r#"
2854 little_endian_packets
2855 enum A : 8 {
2856 A = 0,
2857 B = 1,
2858 X = 1..15,
2859 }
2860 "#
2861 );
2862 }
2863
2864 #[test]
2865 fn test_e44() {
2866 raises!(
2867 DuplicateDefaultTag,
2868 r#"
2869 little_endian_packets
2870 enum A : 8 {
2871 A = 0,
2872 X = ..,
2873 B = 1,
2874 Y = ..,
2875 }
2876 "#
2877 );
2878 }
2879
2880 #[test]
2881 fn test_e45() {
2882 valid!(
2883 r#"
2884 little_endian_packets
2885 packet B {
2886 c : 1,
2887 _reserved_ : 7,
2888 x : 8 if c = 1,
2889 }
2890 "#
2891 );
2892
2893 valid!(
2894 r#"
2895 little_endian_packets
2896 enum A : 8 { X = 0 }
2897 packet B {
2898 c : 1,
2899 _reserved_ : 7,
2900 x : A if c = 0,
2901 }
2902 "#
2903 );
2904
2905 raises!(
2906 InvalidOptionalField,
2907 r#"
2908 little_endian_packets
2909 packet B {
2910 c : 1,
2911 _reserved_ : 7,
2912 x : 8[] if c = 1,
2913 }
2914 "#
2915 );
2916
2917 raises!(
2918 InvalidOptionalField,
2919 r#"
2920 little_endian_packets
2921 packet A {
2922 c : 1,
2923 _reserved_ : 7,
2924 _size_(x) : 8 if c = 1,
2925 x : 8[],
2926 }
2927 "#
2928 );
2929
2930 raises!(
2931 InvalidOptionalField,
2932 r#"
2933 little_endian_packets
2934 packet B {
2935 c : 1,
2936 _reserved_ : 7,
2937 x : 8[],
2938 _padding_ [10] if c = 1,
2939 }
2940 "#
2941 );
2942
2943 raises!(
2944 InvalidOptionalField,
2945 r#"
2946 little_endian_packets
2947 packet B {
2948 c : 1,
2949 _reserved_ : 7,
2950 _reserved_ : 8 if c = 1,
2951 }
2952 "#
2953 );
2954
2955 raises!(
2956 InvalidOptionalField,
2957 r#"
2958 little_endian_packets
2959 packet B {
2960 c : 1,
2961 _reserved_ : 7,
2962 _fixed_ = 0x42 : 8 if c = 1,
2963 }
2964 "#
2965 );
2966
2967 raises!(
2968 InvalidOptionalField,
2969 r#"
2970 little_endian_packets
2971 enum A : 8 { X = 0 }
2972 packet B {
2973 c : 1,
2974 _reserved_ : 7,
2975 _fixed_ = X : A if c = 1,
2976 }
2977 "#
2978 );
2979 }
2980
2981 #[test]
2982 fn test_e46() {
2983 raises!(
2984 UndeclaredConditionIdentifier,
2985 r#"
2986 little_endian_packets
2987 packet B {
2988 x : 8 if c = 1,
2989 _reserved_ : 7,
2990 }
2991 "#
2992 );
2993 }
2994
2995 #[test]
2996 fn test_e47() {
2997 raises!(
2998 InvalidConditionIdentifier,
2999 r#"
3000 little_endian_packets
3001 enum A : 8 { X = 0 }
3002 packet B {
3003 c : A,
3004 x : 8 if c = 1,
3005 }
3006 "#
3007 );
3008
3009 raises!(
3010 InvalidConditionIdentifier,
3011 r#"
3012 little_endian_packets
3013 packet B {
3014 c : 8[],
3015 x : 8 if c = 1,
3016 }
3017 "#
3018 );
3019
3020 raises!(
3021 InvalidConditionIdentifier,
3022 r#"
3023 little_endian_packets
3024 packet B {
3025 c : 8,
3026 x : 8 if c = 1,
3027 }
3028 "#
3029 );
3030 }
3031
3032 #[test]
3033 fn test_e48() {
3034 raises!(
3035 InvalidConditionValue,
3036 r#"
3037 little_endian_packets
3038 packet B {
3039 c : 1,
3040 _reserved_ : 7,
3041 x : 8 if c = A,
3042 }
3043 "#
3044 );
3045
3046 raises!(
3047 InvalidConditionValue,
3048 r#"
3049 little_endian_packets
3050 packet B {
3051 c : 1,
3052 _reserved_ : 7,
3053 x : 8 if c = 2,
3054 }
3055 "#
3056 );
3057 }
3058
3059 #[test]
3060 fn test_e49() {
3061 raises!(
3062 E49,
3063 r#"
3064 little_endian_packets
3065 packet B {
3066 c0 : 1,
3067 _reserved_ : 7,
3068 c1 : 1 if c0 = 1,
3069 _reserved_ : 7,
3070 x : 8 if c1 = 1,
3071 }
3072 "#
3073 );
3074 }
3075
3076 #[test]
3077 fn test_e51() {
3078 raises!(
3079 InvalidFieldOffset,
3080 r#"
3081 little_endian_packets
3082 struct S { a: 8 }
3083 packet A {
3084 a : 1,
3085 s : S,
3086 c : 7,
3087 }
3088 "#
3089 );
3090
3091 raises!(
3092 InvalidFieldOffset,
3093 r#"
3094 little_endian_packets
3095 packet A {
3096 a : 1,
3097 b : 8[],
3098 c : 7,
3099 }
3100 "#
3101 );
3102
3103 raises!(
3104 InvalidFieldOffset,
3105 r#"
3106 big_endian_packets
3107 packet A {
3108 a : 1,
3109 _payload_,
3110 b : 7,
3111 }
3112 "#
3113 );
3114
3115 raises!(
3116 InvalidFieldOffset,
3117 r#"
3118 big_endian_packets
3119 packet A {
3120 a : 1,
3121 _body_,
3122 b : 7,
3123 }
3124 "#
3125 );
3126
3127 raises!(
3128 InvalidFieldOffset,
3129 r#"
3130 little_endian_packets
3131 custom_field F : 8 "f"
3132 packet A {
3133 a : 1,
3134 f : F,
3135 }
3136 "#
3137 );
3138 }
3139
3140 #[test]
3141 fn test_e52() {
3142 raises!(
3143 InvalidPacketSize,
3144 r#"
3145 little_endian_packets
3146 packet A {
3147 a : 1,
3148 }
3149 "#
3150 );
3151
3152 raises!(
3153 InvalidPacketSize,
3154 r#"
3155 little_endian_packets
3156 packet A {
3157 a : 8[],
3158 b : 1,
3159 }
3160 "#
3161 );
3162
3163 raises!(
3164 InvalidPacketSize,
3165 r#"
3166 little_endian_packets
3167 packet A {
3168 a : 8[],
3169 b : 1,
3170 }
3171 "#
3172 );
3173
3174 raises!(
3175 InvalidPacketSize,
3176 r#"
3177 little_endian_packets
3178 struct S {
3179 _size_(_payload_) : 8,
3180 _payload_,
3181 }
3182 packet A {
3183 a : S,
3184 b : 1,
3185 }
3186 "#
3187 );
3188
3189 raises!(
3190 InvalidPacketSize,
3191 r#"
3192 little_endian_packets
3193 struct A {
3194 a : 1,
3195 }
3196 "#
3197 );
3198 }
3199
3200 #[test]
3201 fn test_e53() {
3202 raises!(
3203 InvalidFieldSize,
3204 r#"
3205 little_endian_packets
3206 packet A {
3207 a : 12[],
3208 }
3209 "#
3210 );
3211 }
3212
3213 #[test]
3214 fn test_enum_declaration() {
3215 valid!(
3216 r#"
3217 little_endian_packets
3218 enum A : 7 {
3219 X = 0,
3220 Y = 1,
3221 Z = 127,
3222 }
3223 "#
3224 );
3225
3226 valid!(
3227 r#"
3228 little_endian_packets
3229 enum A : 7 {
3230 A = 50..100 {
3231 X = 50,
3232 Y = 100,
3233 },
3234 Z = 101,
3235 }
3236 "#
3237 );
3238
3239 valid!(
3240 r#"
3241 little_endian_packets
3242 enum A : 7 {
3243 A = 50..100,
3244 X = 101,
3245 }
3246 "#
3247 );
3248
3249 valid!(
3250 r#"
3251 little_endian_packets
3252 enum A : 7 {
3253 A = 50..100,
3254 X = 101,
3255 UNKNOWN = ..,
3256 }
3257 "#
3258 );
3259 }
3260
3261 use analyzer::Size;
3262 use Size::*;
3263
3264 #[derive(Debug, PartialEq, Eq)]
3265 struct Annotations {
3266 size: Size,
3267 parent_size: Size,
3268 payload_size: Size,
3269 fields: Vec<Size>,
3270 }
3271
3272 fn annotations(text: &str) -> Vec<Annotations> {
3273 let mut db = ast::SourceDatabase::new();
3274 let file = parse_inline(&mut db, "stdin", text.to_owned()).expect("parsing failure");
3275 let file = analyzer::analyze(&file).expect("analyzer failure");
3276 let schema = analyzer::Schema::new(&file);
3277 file.declarations
3278 .iter()
3279 .map(|decl| Annotations {
3280 size: schema.decl_size(decl.key),
3281 parent_size: schema.parent_size(decl.key),
3282 payload_size: schema.payload_size(decl.key),
3283 fields: decl.fields().map(|field| schema.field_size(field.key)).collect(),
3284 })
3285 .collect()
3286 }
3287
3288 #[test]
3289 fn test_bitfield_annotations() {
3290 assert_that!(
3291 annotations(
3292 r#"
3293 little_endian_packets
3294 enum E : 6 { X=0, Y=1 }
3295 packet A {
3296 a : 14,
3297 b : E,
3298 _reserved_ : 3,
3299 _fixed_ = 3 : 4,
3300 _fixed_ = X : E,
3301 _size_(_payload_) : 7,
3302 _payload_,
3303 }
3304 "#
3305 ),
3306 eq(vec![
3307 Annotations {
3308 size: Static(6),
3309 parent_size: Static(0),
3310 payload_size: Static(0),
3311 fields: vec![]
3312 },
3313 Annotations {
3314 size: Static(40),
3315 parent_size: Static(0),
3316 payload_size: Dynamic,
3317 fields: vec![
3318 Static(14),
3319 Static(6),
3320 Static(3),
3321 Static(4),
3322 Static(6),
3323 Static(7),
3324 Dynamic
3325 ]
3326 },
3327 ])
3328 )
3329 }
3330
3331 #[test]
3332 fn test_typedef_annotations() {
3333 assert_that!(
3335 annotations(
3336 r#"
3337 little_endian_packets
3338 struct S {
3339 a: 8[4],
3340 }
3341 packet A {
3342 a: 16,
3343 s: S,
3344 }
3345 "#
3346 ),
3347 eq(vec![
3348 Annotations {
3349 size: Static(32),
3350 parent_size: Static(0),
3351 payload_size: Static(0),
3352 fields: vec![Static(32)]
3353 },
3354 Annotations {
3355 size: Static(48),
3356 parent_size: Static(0),
3357 payload_size: Static(0),
3358 fields: vec![Static(16), Static(32)]
3359 },
3360 ])
3361 );
3362
3363 assert_that!(
3365 annotations(
3366 r#"
3367 little_endian_packets
3368 struct S {
3369 _size_ (a) : 8,
3370 a: 8[],
3371 }
3372 packet A {
3373 a: 16,
3374 s: S,
3375 }
3376 "#
3377 ),
3378 eq(vec![
3379 Annotations {
3380 size: Dynamic,
3381 parent_size: Static(0),
3382 payload_size: Static(0),
3383 fields: vec![Static(8), Dynamic]
3384 },
3385 Annotations {
3386 size: Dynamic,
3387 parent_size: Static(0),
3388 payload_size: Static(0),
3389 fields: vec![Static(16), Dynamic]
3390 },
3391 ])
3392 );
3393
3394 assert_that!(
3396 annotations(
3397 r#"
3398 little_endian_packets
3399 struct S {
3400 a: 8[],
3401 }
3402 packet A {
3403 a: 16,
3404 s: S,
3405 }
3406 "#
3407 ),
3408 eq(vec![
3409 Annotations {
3410 size: Unknown,
3411 parent_size: Static(0),
3412 payload_size: Static(0),
3413 fields: vec![Unknown]
3414 },
3415 Annotations {
3416 size: Unknown,
3417 parent_size: Static(0),
3418 payload_size: Static(0),
3419 fields: vec![Static(16), Unknown]
3420 },
3421 ])
3422 );
3423 }
3424
3425 #[test]
3426 fn test_array_annotations() {
3427 assert_that!(
3429 annotations(
3430 r#"
3431 little_endian_packets
3432 enum E : 8 { X=0, Y=1 }
3433 packet A {
3434 a: E[8],
3435 }
3436 "#
3437 ),
3438 eq(vec![
3439 Annotations {
3440 size: Static(8),
3441 parent_size: Static(0),
3442 payload_size: Static(0),
3443 fields: vec![]
3444 },
3445 Annotations {
3446 size: Static(64),
3447 parent_size: Static(0),
3448 payload_size: Static(0),
3449 fields: vec![Static(64)]
3450 },
3451 ])
3452 );
3453
3454 assert_that!(
3456 annotations(
3457 r#"
3458 little_endian_packets
3459 struct S { _size_(a): 8, a: 8[] }
3460 packet A {
3461 a: S[8],
3462 }
3463 "#
3464 ),
3465 eq(vec![
3466 Annotations {
3467 size: Dynamic,
3468 parent_size: Static(0),
3469 payload_size: Static(0),
3470 fields: vec![Static(8), Dynamic]
3471 },
3472 Annotations {
3473 size: Dynamic,
3474 parent_size: Static(0),
3475 payload_size: Static(0),
3476 fields: vec![Dynamic]
3477 },
3478 ])
3479 );
3480
3481 assert_that!(
3483 annotations(
3484 r#"
3485 little_endian_packets
3486 struct S { a: 7, _reserved_: 1 }
3487 packet A {
3488 _size_ (a) : 8,
3489 a: S[],
3490 }
3491 "#
3492 ),
3493 eq(vec![
3494 Annotations {
3495 size: Static(8),
3496 parent_size: Static(0),
3497 payload_size: Static(0),
3498 fields: vec![Static(7), Static(1)]
3499 },
3500 Annotations {
3501 size: Dynamic,
3502 parent_size: Static(0),
3503 payload_size: Static(0),
3504 fields: vec![Static(8), Dynamic]
3505 },
3506 ])
3507 );
3508
3509 assert_that!(
3511 annotations(
3512 r#"
3513 little_endian_packets
3514 struct S { _size_(a): 8, a: 8[] }
3515 packet A {
3516 _size_ (a) : 8,
3517 a: S[],
3518 }
3519 "#
3520 ),
3521 eq(vec![
3522 Annotations {
3523 size: Dynamic,
3524 parent_size: Static(0),
3525 payload_size: Static(0),
3526 fields: vec![Static(8), Dynamic]
3527 },
3528 Annotations {
3529 size: Dynamic,
3530 parent_size: Static(0),
3531 payload_size: Static(0),
3532 fields: vec![Static(8), Dynamic]
3533 },
3534 ])
3535 );
3536
3537 assert_that!(
3539 annotations(
3540 r#"
3541 little_endian_packets
3542 struct S { a: 7, _reserved_: 1 }
3543 packet A {
3544 _count_ (a) : 8,
3545 a: S[],
3546 }
3547 "#
3548 ),
3549 eq(vec![
3550 Annotations {
3551 size: Static(8),
3552 parent_size: Static(0),
3553 payload_size: Static(0),
3554 fields: vec![Static(7), Static(1)]
3555 },
3556 Annotations {
3557 size: Dynamic,
3558 parent_size: Static(0),
3559 payload_size: Static(0),
3560 fields: vec![Static(8), Dynamic]
3561 },
3562 ])
3563 );
3564
3565 assert_that!(
3567 annotations(
3568 r#"
3569 little_endian_packets
3570 struct S { _size_(a): 8, a: 8[] }
3571 packet A {
3572 _count_ (a) : 8,
3573 a: S[],
3574 }
3575 "#
3576 ),
3577 eq(vec![
3578 Annotations {
3579 size: Dynamic,
3580 parent_size: Static(0),
3581 payload_size: Static(0),
3582 fields: vec![Static(8), Dynamic]
3583 },
3584 Annotations {
3585 size: Dynamic,
3586 parent_size: Static(0),
3587 payload_size: Static(0),
3588 fields: vec![Static(8), Dynamic]
3589 },
3590 ])
3591 );
3592
3593 assert_that!(
3595 annotations(
3596 r#"
3597 little_endian_packets
3598 struct S { a: 7, _fixed_ = 1 : 1 }
3599 packet A {
3600 a: S[],
3601 }
3602 "#
3603 ),
3604 eq(vec![
3605 Annotations {
3606 size: Static(8),
3607 parent_size: Static(0),
3608 payload_size: Static(0),
3609 fields: vec![Static(7), Static(1)]
3610 },
3611 Annotations {
3612 size: Unknown,
3613 parent_size: Static(0),
3614 payload_size: Static(0),
3615 fields: vec![Unknown]
3616 },
3617 ])
3618 );
3619
3620 assert_that!(
3622 annotations(
3623 r#"
3624 little_endian_packets
3625 struct S { _size_(a): 8, a: 8[] }
3626 packet A {
3627 a: S[],
3628 }
3629 "#
3630 ),
3631 eq(vec![
3632 Annotations {
3633 size: Dynamic,
3634 parent_size: Static(0),
3635 payload_size: Static(0),
3636 fields: vec![Static(8), Dynamic]
3637 },
3638 Annotations {
3639 size: Unknown,
3640 parent_size: Static(0),
3641 payload_size: Static(0),
3642 fields: vec![Unknown]
3643 },
3644 ])
3645 );
3646
3647 assert_that!(
3649 annotations(
3650 r#"
3651 little_endian_packets
3652 struct S {
3653 _count_(a): 40,
3654 a: 16[],
3655 }
3656 packet A {
3657 a: S[],
3658 _padding_ [128],
3659 }
3660 "#
3661 ),
3662 eq(vec![
3663 Annotations {
3664 size: Dynamic,
3665 parent_size: Static(0),
3666 payload_size: Static(0),
3667 fields: vec![Static(40), Dynamic]
3668 },
3669 Annotations {
3670 size: Static(1024),
3671 parent_size: Static(0),
3672 payload_size: Static(0),
3673 fields: vec![Unknown, Static(0)]
3674 },
3675 ])
3676 );
3677 }
3678
3679 #[test]
3680 fn test_payload_annotations() {
3681 assert_that!(
3683 annotations(
3684 r#"
3685 little_endian_packets
3686 packet A {
3687 _size_(_payload_) : 8,
3688 _payload_
3689 }
3690 "#
3691 ),
3692 eq(vec![Annotations {
3693 size: Static(8),
3694 parent_size: Static(0),
3695 payload_size: Dynamic,
3696 fields: vec![Static(8), Dynamic]
3697 },])
3698 );
3699
3700 assert_that!(
3702 annotations(
3703 r#"
3704 little_endian_packets
3705 packet A {
3706 a : 8,
3707 _payload_
3708 }
3709 "#
3710 ),
3711 eq(vec![Annotations {
3712 size: Static(8),
3713 parent_size: Static(0),
3714 payload_size: Unknown,
3715 fields: vec![Static(8), Unknown]
3716 },])
3717 );
3718 }
3719
3720 #[test]
3721 fn test_body_annotations() {
3722 assert_that!(
3724 annotations(
3725 r#"
3726 little_endian_packets
3727 packet A {
3728 _size_(_body_) : 8,
3729 _body_
3730 }
3731 "#
3732 ),
3733 eq(vec![Annotations {
3734 size: Static(8),
3735 parent_size: Static(0),
3736 payload_size: Dynamic,
3737 fields: vec![Static(8), Dynamic]
3738 },])
3739 );
3740
3741 assert_that!(
3743 annotations(
3744 r#"
3745 little_endian_packets
3746 packet A {
3747 a : 8,
3748 _body_
3749 }
3750 "#
3751 ),
3752 eq(vec![Annotations {
3753 size: Static(8),
3754 parent_size: Static(0),
3755 payload_size: Unknown,
3756 fields: vec![Static(8), Unknown]
3757 },])
3758 );
3759 }
3760
3761 #[test]
3762 fn test_decl_annotations() {
3763 assert_that!(
3765 annotations(
3766 r#"
3767 little_endian_packets
3768 packet A {
3769 a: 2,
3770 _reserved_: 6,
3771 _payload_
3772 }
3773 packet B : A {
3774 b: 8,
3775 }
3776 "#
3777 ),
3778 eq(vec![
3779 Annotations {
3780 size: Static(8),
3781 parent_size: Static(0),
3782 payload_size: Unknown,
3783 fields: vec![Static(2), Static(6), Unknown]
3784 },
3785 Annotations {
3786 size: Static(8),
3787 parent_size: Static(8),
3788 payload_size: Static(0),
3789 fields: vec![Static(8)]
3790 },
3791 ])
3792 );
3793
3794 assert_that!(
3796 annotations(
3797 r#"
3798 little_endian_packets
3799 packet A {
3800 _size_(a) : 8,
3801 a: 8[],
3802 _size_(_payload_) : 8,
3803 _payload_
3804 }
3805 packet B : A {
3806 b: 8,
3807 }
3808 "#
3809 ),
3810 eq(vec![
3811 Annotations {
3812 size: Dynamic,
3813 parent_size: Static(0),
3814 payload_size: Dynamic,
3815 fields: vec![Static(8), Dynamic, Static(8), Dynamic]
3816 },
3817 Annotations {
3818 size: Static(8),
3819 parent_size: Dynamic,
3820 payload_size: Static(0),
3821 fields: vec![Static(8)]
3822 },
3823 ])
3824 );
3825
3826 assert_that!(
3828 annotations(
3829 r#"
3830 little_endian_packets
3831 packet A {
3832 _size_(_payload_) : 8,
3833 a: 8[],
3834 _payload_
3835 }
3836 packet B : A {
3837 b: 8,
3838 }
3839 "#
3840 ),
3841 eq(vec![
3842 Annotations {
3843 size: Unknown,
3844 parent_size: Static(0),
3845 payload_size: Dynamic,
3846 fields: vec![Static(8), Unknown, Dynamic]
3847 },
3848 Annotations {
3849 size: Static(8),
3850 parent_size: Unknown,
3851 payload_size: Static(0),
3852 fields: vec![Static(8)]
3853 },
3854 ])
3855 );
3856 }
3857
3858 fn desugar(text: &str) -> analyzer::File {
3859 let mut db = ast::SourceDatabase::new();
3860 let file = parse_inline(&mut db, "stdin", text.to_owned()).expect("parsing failure");
3861 analyzer::analyze(&file).expect("analyzer failure")
3862 }
3863
3864 #[test]
3865 fn test_inline_groups() {
3866 assert_eq!(
3867 desugar(
3868 r#"
3869 little_endian_packets
3870 enum E : 8 { X=0, Y=1 }
3871 group G {
3872 a: 8,
3873 b: E,
3874 }
3875 packet A {
3876 G { }
3877 }
3878 "#
3879 ),
3880 desugar(
3881 r#"
3882 little_endian_packets
3883 enum E : 8 { X=0, Y=1 }
3884 packet A {
3885 a: 8,
3886 b: E,
3887 }
3888 "#
3889 )
3890 );
3891
3892 assert_eq!(
3893 desugar(
3894 r#"
3895 little_endian_packets
3896 enum E : 8 { X=0, Y=1 }
3897 group G {
3898 a: 8,
3899 b: E,
3900 }
3901 packet A {
3902 G { a=1, b=X }
3903 }
3904 "#
3905 ),
3906 desugar(
3907 r#"
3908 little_endian_packets
3909 enum E : 8 { X=0, Y=1 }
3910 packet A {
3911 _fixed_ = 1: 8,
3912 _fixed_ = X: E,
3913 }
3914 "#
3915 )
3916 );
3917
3918 assert_eq!(
3919 desugar(
3920 r#"
3921 little_endian_packets
3922 enum E : 8 { X=0, Y=1 }
3923 group G1 {
3924 a: 8,
3925 }
3926 group G2 {
3927 G1 { a=1 },
3928 b: E,
3929 }
3930 packet A {
3931 G2 { b=X }
3932 }
3933 "#
3934 ),
3935 desugar(
3936 r#"
3937 little_endian_packets
3938 enum E : 8 { X=0, Y=1 }
3939 packet A {
3940 _fixed_ = 1: 8,
3941 _fixed_ = X: E,
3942 }
3943 "#
3944 )
3945 );
3946 }
3947}