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!("`{}` is first declared here", id)),
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!("`{}` is first declared here", id)),
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 `{}` is larger than maximum value",
1019 value
1020 ))
1021 .with_labels(vec![constraint.loc.primary(), field.loc.secondary()]),
1022 ),
1023 _ => (),
1024 }
1025 }
1026 Some(field @ Field { desc: FieldDesc::Typedef { type_id, .. }, .. }) => {
1027 match scope.typedef.get(type_id) {
1028 None => (),
1029 Some(Decl { desc: DeclDesc::Enum { tags, .. }, .. }) => match &constraint.tag_id {
1030 None => diagnostics.push(
1031 Diagnostic::error()
1032 .with_code(ErrorCode::E19)
1033 .with_message(format!(
1034 "invalid constraint value `{}`",
1035 constraint.value.unwrap()
1036 ))
1037 .with_labels(vec![
1038 constraint.loc.primary(),
1039 field.loc.secondary().with_message(format!(
1040 "`{}` is declared here as typedef field",
1041 constraint.id
1042 )),
1043 ])
1044 .with_notes(vec!["hint: expected enum value".to_owned()]),
1045 ),
1046 Some(tag_id) => match tags.iter().find(|tag| tag.id() == tag_id) {
1047 None => diagnostics.push(
1048 Diagnostic::error()
1049 .with_code(ErrorCode::E20)
1050 .with_message(format!("undeclared enum tag `{}`", tag_id))
1051 .with_labels(vec![
1052 constraint.loc.primary(),
1053 field.loc.secondary().with_message(format!(
1054 "`{}` is declared here",
1055 constraint.id
1056 )),
1057 ]),
1058 ),
1059 Some(Tag::Range { .. }) => diagnostics.push(
1060 Diagnostic::error()
1061 .with_code(ErrorCode::E42)
1062 .with_message(format!("enum tag `{}` defines a range", tag_id))
1063 .with_labels(vec![
1064 constraint.loc.primary(),
1065 field.loc.secondary().with_message(format!(
1066 "`{}` is declared here",
1067 constraint.id
1068 )),
1069 ])
1070 .with_notes(vec!["hint: expected enum tag with value".to_owned()]),
1071 ),
1072 Some(_) => (),
1073 },
1074 },
1075 Some(decl) => diagnostics.push(
1076 Diagnostic::error()
1077 .with_code(ErrorCode::E21)
1078 .with_message(format!(
1079 "invalid constraint identifier `{}`",
1080 constraint.value.unwrap()
1081 ))
1082 .with_labels(vec![
1083 constraint.loc.primary(),
1084 field.loc.secondary().with_message(format!(
1085 "`{}` is declared here as {} typedef field",
1086 constraint.id,
1087 decl.kind()
1088 )),
1089 ])
1090 .with_notes(vec!["hint: expected enum value".to_owned()]),
1091 ),
1092 }
1093 }
1094 Some(_) => unreachable!(),
1095 }
1096}
1097
1098fn check_constraints_list<'d>(
1100 constraints: &'d [Constraint],
1101 parent_decl: &Decl,
1102 scope: &Scope,
1103 mut constraints_by_id: HashMap<String, &'d Constraint>,
1104 diagnostics: &mut Diagnostics,
1105) {
1106 for constraint in constraints {
1107 check_constraint(constraint, parent_decl, scope, diagnostics);
1108 if let Some(prev) = constraints_by_id.insert(constraint.id.to_string(), constraint) {
1109 diagnostics.push(
1111 Diagnostic::error()
1112 .with_code(ErrorCode::DuplicateConstraintIdentifier)
1113 .with_message(format!("duplicate constraint identifier `{}`", constraint.id))
1114 .with_labels(vec![
1115 constraint.loc.primary(),
1116 prev.loc
1117 .secondary()
1118 .with_message(format!("`{}` is first constrained here", prev.id)),
1119 ]),
1120 )
1121 }
1122 }
1123}
1124
1125fn check_decl_constraints(file: &File, scope: &Scope) -> Result<(), Diagnostics> {
1135 let mut diagnostics: Diagnostics = Default::default();
1136 for decl in &file.declarations {
1137 match &decl.desc {
1139 DeclDesc::Packet { constraints, parent_id: Some(parent_id), .. }
1140 | DeclDesc::Struct { constraints, parent_id: Some(parent_id), .. } => {
1141 let parent_decl = scope.typedef.get(parent_id).unwrap();
1142 check_constraints_list(
1143 constraints,
1144 parent_decl,
1145 scope,
1146 scope.iter_parents(decl).fold(HashMap::new(), |acc, decl| {
1149 decl.constraints().fold(acc, |mut acc, constraint| {
1150 let _ = acc.insert(constraint.id.to_string(), constraint);
1151 acc
1152 })
1153 }),
1154 &mut diagnostics,
1155 )
1156 }
1157 _ => (),
1158 }
1159 }
1160
1161 diagnostics.err_or(())
1162}
1163
1164fn check_group_constraints(file: &File, scope: &Scope) -> Result<(), Diagnostics> {
1174 let mut diagnostics: Diagnostics = Default::default();
1175 for decl in &file.declarations {
1176 for field in decl.fields() {
1178 if let FieldDesc::Group { group_id, constraints } = &field.desc {
1179 let group_decl = scope.typedef.get(group_id).unwrap();
1180 check_constraints_list(
1181 constraints,
1182 group_decl,
1183 scope,
1184 HashMap::new(),
1185 &mut diagnostics,
1186 )
1187 }
1188 }
1189 }
1190
1191 diagnostics.err_or(())
1192}
1193
1194fn check_size_fields(file: &File) -> Result<(), Diagnostics> {
1206 let mut diagnostics: Diagnostics = Default::default();
1207 for decl in &file.declarations {
1208 let mut size_for_id = HashMap::new();
1209 let mut element_size_for_id = HashMap::new();
1210 for field in decl.fields() {
1211 if let Some((reverse_map, field_id, err)) = match &field.desc {
1213 FieldDesc::Size { field_id, .. } => {
1214 Some((&mut size_for_id, field_id, ErrorCode::DuplicateSizeField))
1215 }
1216 FieldDesc::Count { field_id, .. } => {
1217 Some((&mut size_for_id, field_id, ErrorCode::DuplicateCountField))
1218 }
1219 FieldDesc::ElementSize { field_id, .. } => {
1220 Some((&mut element_size_for_id, field_id, ErrorCode::DuplicateElementSizeField))
1221 }
1222 _ => None,
1223 } {
1224 if let Some(prev) = reverse_map.insert(field_id, field) {
1225 diagnostics.push(
1226 Diagnostic::error()
1227 .with_code(err)
1228 .with_message(format!("duplicate {} field", field.kind()))
1229 .with_labels(vec![
1230 field.loc.primary(),
1231 prev.loc.secondary().with_message(format!(
1232 "{} is first declared here",
1233 prev.kind()
1234 )),
1235 ]),
1236 )
1237 }
1238 }
1239
1240 match &field.desc {
1242 FieldDesc::Size { field_id, .. } => {
1243 match decl.fields().find(|field| match &field.desc {
1244 FieldDesc::Payload { .. } => field_id == "_payload_",
1245 FieldDesc::Body => field_id == "_body_",
1246 _ => field.id() == Some(field_id),
1247 }) {
1248 None => diagnostics.push(
1249 Diagnostic::error()
1250 .with_code(ErrorCode::UndeclaredSizeIdentifier)
1251 .with_message(format!(
1252 "undeclared {} identifier `{}`",
1253 field.kind(),
1254 field_id
1255 ))
1256 .with_labels(vec![field.loc.primary()])
1257 .with_notes(vec![
1258 "hint: expected payload, body, or array identifier".to_owned(),
1259 ]),
1260 ),
1261 Some(Field { desc: FieldDesc::Body, .. })
1262 | Some(Field { desc: FieldDesc::Payload { .. }, .. })
1263 | Some(Field { desc: FieldDesc::Array { .. }, .. }) => (),
1264 Some(Field { loc, .. }) => diagnostics.push(
1265 Diagnostic::error()
1266 .with_code(ErrorCode::InvalidSizeIdentifier)
1267 .with_message(format!(
1268 "invalid {} identifier `{}`",
1269 field.kind(),
1270 field_id
1271 ))
1272 .with_labels(vec![field.loc.primary(), loc.secondary()])
1273 .with_notes(vec![
1274 "hint: expected payload, body, or array identifier".to_owned(),
1275 ]),
1276 ),
1277 }
1278 }
1279
1280 FieldDesc::Count { field_id, .. } | FieldDesc::ElementSize { field_id, .. } => {
1281 let (undeclared_err, invalid_err) =
1282 if matches!(&field.desc, FieldDesc::Count { .. }) {
1283 (
1284 ErrorCode::UndeclaredCountIdentifier,
1285 ErrorCode::InvalidCountIdentifier,
1286 )
1287 } else {
1288 (
1289 ErrorCode::UndeclaredElementSizeIdentifier,
1290 ErrorCode::InvalidElementSizeIdentifier,
1291 )
1292 };
1293 match decl.fields().find(|field| field.id() == Some(field_id)) {
1294 None => diagnostics.push(
1295 Diagnostic::error()
1296 .with_code(undeclared_err)
1297 .with_message(format!(
1298 "undeclared {} identifier `{}`",
1299 field.kind(),
1300 field_id
1301 ))
1302 .with_labels(vec![field.loc.primary()])
1303 .with_notes(vec!["hint: expected array identifier".to_owned()]),
1304 ),
1305 Some(Field { desc: FieldDesc::Array { .. }, .. }) => (),
1306 Some(Field { loc, .. }) => diagnostics.push(
1307 Diagnostic::error()
1308 .with_code(invalid_err)
1309 .with_message(format!(
1310 "invalid {} identifier `{}`",
1311 field.kind(),
1312 field_id
1313 ))
1314 .with_labels(vec![field.loc.primary(), loc.secondary()])
1315 .with_notes(vec!["hint: expected array identifier".to_owned()]),
1316 ),
1317 }
1318 }
1319 _ => (),
1320 }
1321 }
1322 }
1323
1324 diagnostics.err_or(())
1325}
1326
1327fn check_fixed_fields(file: &File, scope: &Scope) -> Result<(), Diagnostics> {
1334 let mut diagnostics: Diagnostics = Default::default();
1335 for decl in &file.declarations {
1336 for field in decl.fields() {
1337 match &field.desc {
1338 FieldDesc::FixedScalar { value, width } if bit_width(*value) > *width => {
1339 diagnostics.push(
1340 Diagnostic::error()
1341 .with_code(ErrorCode::FixedValueOutOfRange)
1342 .with_message(format!(
1343 "fixed value `{}` is larger than maximum value",
1344 value
1345 ))
1346 .with_labels(vec![field.loc.primary()]),
1347 )
1348 }
1349 FieldDesc::FixedEnum { tag_id, enum_id } => match scope.typedef.get(enum_id) {
1350 None => diagnostics.push(
1351 Diagnostic::error()
1352 .with_code(ErrorCode::E33)
1353 .with_message(format!("undeclared type identifier `{}`", enum_id))
1354 .with_labels(vec![field.loc.primary()])
1355 .with_notes(vec!["hint: expected enum identifier".to_owned()]),
1356 ),
1357 Some(enum_decl @ Decl { desc: DeclDesc::Enum { tags, .. }, .. }) => {
1358 if !tags.iter().any(|tag| tag.id() == tag_id) {
1359 diagnostics.push(
1360 Diagnostic::error()
1361 .with_code(ErrorCode::E34)
1362 .with_message(format!("undeclared tag identifier `{}`", tag_id))
1363 .with_labels(vec![
1364 field.loc.primary(),
1365 enum_decl.loc.secondary(),
1366 ]),
1367 )
1368 }
1369 }
1370 Some(decl) => diagnostics.push(
1371 Diagnostic::error()
1372 .with_code(ErrorCode::E35)
1373 .with_message(format!("invalid type identifier `{}`", enum_id))
1374 .with_labels(vec![
1375 field.loc.primary(),
1376 decl.loc
1377 .secondary()
1378 .with_message(format!("`{}` is declared here", enum_id)),
1379 ])
1380 .with_notes(vec!["hint: expected enum identifier".to_owned()]),
1381 ),
1382 },
1383 _ => (),
1384 }
1385 }
1386 }
1387
1388 diagnostics.err_or(())
1389}
1390
1391fn check_payload_fields(file: &File) -> Result<(), Diagnostics> {
1399 fn requires_payload(file: &File, decl: &Decl) -> bool {
1402 file.iter_children(decl).any(|child| child.fields().next().is_some())
1403 }
1404
1405 let mut diagnostics: Diagnostics = Default::default();
1406 for decl in &file.declarations {
1407 let mut payload: Option<&Field> = None;
1408 for field in decl.fields() {
1409 match &field.desc {
1410 FieldDesc::Payload { .. } | FieldDesc::Body => {
1411 if let Some(prev) = payload {
1412 diagnostics.push(
1413 Diagnostic::error()
1414 .with_code(ErrorCode::DuplicatePayloadField)
1415 .with_message(format!("duplicate {} field", field.kind()))
1416 .with_labels(vec![
1417 field.loc.primary(),
1418 prev.loc.secondary().with_message(format!(
1419 "{} is first declared here",
1420 prev.kind()
1421 )),
1422 ]),
1423 )
1424 } else {
1425 payload = Some(field);
1426 }
1427 }
1428 _ => (),
1429 }
1430 }
1431
1432 if payload.is_none() && requires_payload(file, decl) {
1433 diagnostics.push(
1434 Diagnostic::error()
1435 .with_code(ErrorCode::MissingPayloadField)
1436 .with_message("missing payload field".to_owned())
1437 .with_labels(vec![decl.loc.primary()])
1438 .with_notes(vec![format!(
1439 "hint: one child packet is extending `{}`",
1440 decl.id().unwrap()
1441 )]),
1442 )
1443 }
1444 }
1445
1446 diagnostics.err_or(())
1447}
1448
1449fn check_array_fields(file: &File) -> Result<(), Diagnostics> {
1453 let mut diagnostics: Diagnostics = Default::default();
1454 for decl in &file.declarations {
1455 for field in decl.fields() {
1456 if let FieldDesc::Array { id, size: Some(size), .. } = &field.desc {
1457 if let Some(size_field) = decl.fields().find(|field| match &field.desc {
1458 FieldDesc::Size { field_id, .. } | FieldDesc::Count { field_id, .. } => {
1459 field_id == id
1460 }
1461 _ => false,
1462 }) {
1463 diagnostics.push(
1464 Diagnostic::error()
1465 .with_code(ErrorCode::RedundantArraySize)
1466 .with_message(format!("redundant array {} field", size_field.kind()))
1467 .with_labels(vec![
1468 size_field.loc.primary(),
1469 field
1470 .loc
1471 .secondary()
1472 .with_message(format!("`{}` has constant size {}", id, size)),
1473 ]),
1474 )
1475 }
1476 }
1477 }
1478 }
1479
1480 diagnostics.err_or(())
1481}
1482
1483fn check_padding_fields(file: &File) -> Result<(), Diagnostics> {
1487 let mut diagnostics: Diagnostics = Default::default();
1488 for decl in &file.declarations {
1489 let mut previous_is_array = false;
1490 for field in decl.fields() {
1491 match &field.desc {
1492 FieldDesc::Padding { .. } if !previous_is_array => diagnostics.push(
1493 Diagnostic::error()
1494 .with_code(ErrorCode::InvalidPaddingField)
1495 .with_message("padding field does not follow an array field".to_owned())
1496 .with_labels(vec![field.loc.primary()]),
1497 ),
1498 FieldDesc::Array { .. } => previous_is_array = true,
1499 _ => previous_is_array = false,
1500 }
1501 }
1502 }
1503
1504 diagnostics.err_or(())
1505}
1506
1507fn check_checksum_fields(_file: &File, _scope: &Scope) -> Result<(), Diagnostics> {
1513 Ok(())
1515}
1516
1517fn check_optional_fields(file: &File) -> Result<(), Diagnostics> {
1524 let mut diagnostics: Diagnostics = Default::default();
1525 for decl in &file.declarations {
1526 let mut local_scope: HashMap<String, &Field> = HashMap::new();
1527 for field in decl.fields() {
1528 if let Some(ref cond) = field.cond {
1529 match &field.desc {
1530 FieldDesc::Scalar { .. } | FieldDesc::Typedef { .. } => (),
1531 _ => diagnostics.push(
1532 Diagnostic::error()
1533 .with_code(ErrorCode::InvalidOptionalField)
1534 .with_message("invalid optional field".to_owned())
1535 .with_labels(vec![field.loc.primary()])
1536 .with_notes(vec!["note: expected scalar, or typedef field".to_owned()]),
1537 ),
1538 }
1539 match local_scope.get(&cond.id) {
1540 None => diagnostics.push(
1541 Diagnostic::error()
1542 .with_code(ErrorCode::UndeclaredConditionIdentifier)
1543 .with_message("undeclared condition identifier".to_owned())
1544 .with_labels(vec![field.loc.primary()])
1545 .with_notes(vec!["note: expected scalar field identifier".to_owned()]),
1546 ),
1547 Some(Field { cond: Some(_), loc, .. }) => diagnostics.push(
1548 Diagnostic::error()
1549 .with_code(ErrorCode::E49)
1550 .with_message("invalid condition identifier".to_owned())
1551 .with_labels(vec![
1552 field.loc.primary(),
1553 loc.secondary().with_message(format!(
1554 "`{}` is declared optional here",
1555 cond.id
1556 )),
1557 ])
1558 .with_notes(vec!["note: expected scalar field identifier".to_owned()]),
1559 ),
1560 Some(Field { desc: FieldDesc::Scalar { width: 1, .. }, .. }) => (),
1561 Some(Field { desc: FieldDesc::Scalar { width, .. }, loc, .. }) => diagnostics
1562 .push(
1563 Diagnostic::error()
1564 .with_code(ErrorCode::InvalidConditionIdentifier)
1565 .with_message("invalid condition identifier".to_owned())
1566 .with_labels(vec![
1567 field.loc.primary(),
1568 loc.secondary().with_message(format!(
1569 "`{}` is declared with width `{}` here",
1570 cond.id, width
1571 )),
1572 ])
1573 .with_notes(vec![
1574 "note: expected scalar field identifier".to_owned()
1575 ]),
1576 ),
1577 Some(Field { loc, .. }) => diagnostics.push(
1578 Diagnostic::error()
1579 .with_code(ErrorCode::InvalidConditionIdentifier)
1580 .with_message("invalid condition identifier".to_owned())
1581 .with_labels(vec![
1582 field.loc.primary(),
1583 loc.secondary()
1584 .with_message(format!("`{}` is declared here", cond.id)),
1585 ])
1586 .with_notes(vec!["note: expected scalar field identifier".to_owned()]),
1587 ),
1588 }
1589 match (&cond.value, &cond.tag_id) {
1590 (_, Some(_)) => diagnostics.push(
1591 Diagnostic::error()
1592 .with_code(ErrorCode::InvalidConditionValue)
1593 .with_message("invalid condition value".to_owned())
1594 .with_labels(vec![field.loc.primary()])
1595 .with_notes(vec!["note: expected 0 or 1".to_owned()]),
1596 ),
1597 (Some(0), _) | (Some(1), _) => (),
1598 (Some(_), _) => diagnostics.push(
1599 Diagnostic::error()
1600 .with_code(ErrorCode::InvalidConditionValue)
1601 .with_message("invalid condition value".to_owned())
1602 .with_labels(vec![field.loc.primary()])
1603 .with_notes(vec!["note: expected 0 or 1".to_owned()]),
1604 ),
1605 _ => unreachable!(),
1606 }
1607 }
1608 if let Some(id) = field.id() {
1609 local_scope.insert(id.to_owned(), field);
1610 }
1611 }
1612 }
1613 diagnostics.err_or(())
1614}
1615
1616fn check_field_offsets(file: &File, scope: &Scope, schema: &Schema) -> Result<(), Diagnostics> {
1620 let mut diagnostics: Diagnostics = Default::default();
1621 for decl in &file.declarations {
1622 let mut offset = 0;
1623
1624 for field in decl.fields() {
1625 match &field.desc {
1626 FieldDesc::Typedef { type_id, .. }
1627 if matches!(
1628 scope.typedef.get(type_id),
1629 Some(Decl { desc: DeclDesc::Enum { .. }, .. })
1630 ) => {}
1631 FieldDesc::Payload { .. }
1632 | FieldDesc::Body
1633 | FieldDesc::Typedef { .. }
1634 | FieldDesc::Array { .. }
1635 | FieldDesc::Padding { .. }
1636 | FieldDesc::Checksum { .. } => {
1637 if offset % 8 != 0 {
1638 diagnostics.push(
1639 Diagnostic::error()
1640 .with_code(ErrorCode::InvalidFieldOffset)
1641 .with_message(format!(
1642 "{} field is not aligned to an octet boundary",
1643 field.kind()
1644 ))
1645 .with_labels(vec![field.loc.primary()]),
1646 )
1647 }
1648 }
1649 FieldDesc::Size { .. }
1650 | FieldDesc::Count { .. }
1651 | FieldDesc::ElementSize { .. }
1652 | FieldDesc::FixedEnum { .. }
1653 | FieldDesc::FixedScalar { .. }
1654 | FieldDesc::Group { .. }
1655 | FieldDesc::Flag { .. }
1656 | FieldDesc::Reserved { .. }
1657 | FieldDesc::Scalar { .. } => (),
1658 }
1659 offset = match schema.field_size[&field.key] {
1660 Size::Static(size) => offset + size,
1661 Size::Dynamic | Size::Unknown => 0,
1662 };
1663 }
1664 }
1665 diagnostics.err_or(())
1666}
1667
1668fn check_decl_sizes(file: &File, schema: &Schema) -> Result<(), Diagnostics> {
1674 let mut diagnostics: Diagnostics = Default::default();
1675 for decl in &file.declarations {
1676 let mut static_size = 0;
1677
1678 for field in decl.fields() {
1679 match &field.desc {
1680 FieldDesc::Array { width: Some(width), .. } if width % 8 != 0 => diagnostics.push(
1681 Diagnostic::error()
1682 .with_code(ErrorCode::InvalidFieldSize)
1683 .with_message(
1684 "array element size is not an integral number of octets".to_owned(),
1685 )
1686 .with_labels(vec![field.loc.primary()]),
1687 ),
1688 _ => (),
1689 }
1690 static_size += schema.field_size[&field.key].static_().unwrap_or(0);
1691 }
1692
1693 if static_size % 8 != 0 {
1694 diagnostics.push(
1695 Diagnostic::error()
1696 .with_code(ErrorCode::InvalidPacketSize)
1697 .with_message(format!(
1698 "{} size is not an integral number of octets",
1699 decl.kind()
1700 ))
1701 .with_labels(vec![decl.loc.primary()]),
1702 )
1703 }
1704 }
1705 diagnostics.err_or(())
1706}
1707
1708fn inline_groups(file: &File) -> Result<File, Diagnostics> {
1710 fn inline_fields<'a>(
1711 fields: impl Iterator<Item = &'a Field>,
1712 groups: &HashMap<String, &Decl>,
1713 constraints: &HashMap<String, Constraint>,
1714 ) -> Vec<Field> {
1715 fields
1716 .flat_map(|field| match &field.desc {
1717 FieldDesc::Group { group_id, constraints: group_constraints } => {
1718 let mut constraints = constraints.clone();
1719 constraints.extend(
1720 group_constraints
1721 .iter()
1722 .map(|constraint| (constraint.id.clone(), constraint.clone())),
1723 );
1724 inline_fields(groups.get(group_id).unwrap().fields(), groups, &constraints)
1725 }
1726 FieldDesc::Scalar { id, width } if constraints.contains_key(id) => {
1727 vec![Field {
1728 desc: FieldDesc::FixedScalar {
1729 width: *width,
1730 value: constraints.get(id).unwrap().value.unwrap(),
1731 },
1732 loc: field.loc,
1733 key: field.key,
1734 cond: field.cond.clone(),
1735 }]
1736 }
1737 FieldDesc::Typedef { id, type_id, .. } if constraints.contains_key(id) => {
1738 vec![Field {
1739 desc: FieldDesc::FixedEnum {
1740 enum_id: type_id.clone(),
1741 tag_id: constraints
1742 .get(id)
1743 .and_then(|constraint| constraint.tag_id.clone())
1744 .unwrap(),
1745 },
1746 loc: field.loc,
1747 key: field.key,
1748 cond: field.cond.clone(),
1749 }]
1750 }
1751 _ => vec![field.clone()],
1752 })
1753 .collect()
1754 }
1755
1756 let groups = file
1757 .declarations
1758 .iter()
1759 .filter(|decl| matches!(&decl.desc, DeclDesc::Group { .. }))
1760 .map(|decl| (decl.id().unwrap().to_owned(), decl))
1761 .collect::<HashMap<String, _>>();
1762
1763 let declarations = file
1764 .declarations
1765 .iter()
1766 .filter_map(|decl| match &decl.desc {
1767 DeclDesc::Packet { fields, id, parent_id, constraints } => Some(Decl {
1768 desc: DeclDesc::Packet {
1769 fields: inline_fields(fields.iter(), &groups, &HashMap::new()),
1770 id: id.clone(),
1771 parent_id: parent_id.clone(),
1772 constraints: constraints.clone(),
1773 },
1774 loc: decl.loc,
1775 key: decl.key,
1776 }),
1777 DeclDesc::Struct { fields, id, parent_id, constraints } => Some(Decl {
1778 desc: DeclDesc::Struct {
1779 fields: inline_fields(fields.iter(), &groups, &HashMap::new()),
1780 id: id.clone(),
1781 parent_id: parent_id.clone(),
1782 constraints: constraints.clone(),
1783 },
1784 loc: decl.loc,
1785 key: decl.key,
1786 }),
1787 DeclDesc::Group { .. } => None,
1788 _ => Some(decl.clone()),
1789 })
1790 .collect();
1791
1792 Ok(File {
1793 declarations,
1794 version: file.version.clone(),
1795 file: file.file,
1796 comments: file.comments.clone(),
1797 endianness: file.endianness,
1798 max_key: file.max_key,
1800 })
1801}
1802
1803fn desugar_flags(file: &mut File) {
1806 for decl in &mut file.declarations {
1807 match &mut decl.desc {
1808 DeclDesc::Packet { fields, .. }
1809 | DeclDesc::Struct { fields, .. }
1810 | DeclDesc::Group { fields, .. } => {
1811 let mut condition_ids: HashMap<String, Vec<(String, usize)>> = HashMap::new();
1813 for field in fields.iter() {
1814 if let Some(ref cond) = field.cond {
1815 condition_ids
1816 .entry(cond.id.to_owned())
1817 .or_default()
1818 .push((field.id().unwrap().to_owned(), cond.value.unwrap()));
1819 }
1820 }
1821 for field in fields.iter_mut() {
1823 if let Some(optional_field_ids) =
1824 field.id().and_then(|id| condition_ids.get(id))
1825 {
1826 field.desc = FieldDesc::Flag {
1827 id: field.id().unwrap().to_owned(),
1828 optional_field_ids: optional_field_ids.to_owned(),
1829 };
1830 }
1831 }
1832 }
1833 _ => (),
1834 }
1835 }
1836}
1837
1838pub fn analyze(file: &File) -> Result<File, Diagnostics> {
1841 let scope = Scope::new(file)?;
1842 check_decl_identifiers(file, &scope)?;
1843 check_field_identifiers(file)?;
1844 check_enum_declarations(file)?;
1845 check_size_fields(file)?;
1846 check_fixed_fields(file, &scope)?;
1847 check_payload_fields(file)?;
1848 check_array_fields(file)?;
1849 check_padding_fields(file)?;
1850 check_checksum_fields(file, &scope)?;
1851 check_optional_fields(file)?;
1852 check_group_constraints(file, &scope)?;
1853 let mut file = inline_groups(file)?;
1854 desugar_flags(&mut file);
1855 let scope = Scope::new(&file)?;
1856 check_decl_constraints(&file, &scope)?;
1857 let schema = Schema::new(&file);
1858 check_field_offsets(&file, &scope, &schema)?;
1859 check_decl_sizes(&file, &schema)?;
1860 Ok(file)
1861}
1862
1863#[cfg(test)]
1864mod test {
1865 use crate::analyzer;
1866 use crate::ast;
1867 use crate::parser::parse_inline;
1868 use codespan_reporting::term::termcolor;
1869
1870 use googletest::prelude::{assert_that, eq};
1871
1872 macro_rules! raises {
1873 ($code:ident, $text:literal) => {{
1874 let mut db = ast::SourceDatabase::new();
1875 let file = parse_inline(&mut db, "stdin", $text.to_owned()).expect("parsing failure");
1876 let result = analyzer::analyze(&file);
1877 assert!(matches!(result, Err(_)));
1878 let diagnostics = result.err().unwrap();
1879 let mut buffer = termcolor::Buffer::no_color();
1880 let _ = diagnostics.emit(&db, &mut buffer);
1881 println!("{}", std::str::from_utf8(buffer.as_slice()).unwrap());
1882 assert_eq!(diagnostics.diagnostics.len(), 1);
1883 assert_eq!(diagnostics.diagnostics[0].code, Some(analyzer::ErrorCode::$code.into()));
1884 }};
1885 }
1886
1887 macro_rules! valid {
1888 ($text:literal) => {{
1889 let mut db = ast::SourceDatabase::new();
1890 let file = parse_inline(&mut db, "stdin", $text.to_owned()).expect("parsing failure");
1891 assert!(analyzer::analyze(&file).is_ok());
1892 }};
1893 }
1894
1895 #[test]
1896 fn test_e1() {
1897 raises!(
1898 DuplicateDeclIdentifier,
1899 r#"
1900 little_endian_packets
1901 struct A { }
1902 packet A { }
1903 "#
1904 );
1905
1906 raises!(
1907 DuplicateDeclIdentifier,
1908 r#"
1909 little_endian_packets
1910 struct A { }
1911 enum A : 8 { X = 0, Y = 1 }
1912 "#
1913 );
1914 }
1915
1916 #[test]
1917 fn test_e2() {
1918 raises!(
1919 RecursiveDecl,
1920 r#"
1921 little_endian_packets
1922 packet A : A { }
1923 "#
1924 );
1925
1926 raises!(
1927 RecursiveDecl,
1928 r#"
1929 little_endian_packets
1930 packet A : B { }
1931 packet B : A { }
1932 "#
1933 );
1934
1935 raises!(
1936 RecursiveDecl,
1937 r#"
1938 little_endian_packets
1939 struct B { x : B }
1940 "#
1941 );
1942
1943 raises!(
1944 RecursiveDecl,
1945 r#"
1946 little_endian_packets
1947 struct B { x : B[8] }
1948 "#
1949 );
1950
1951 raises!(
1952 RecursiveDecl,
1953 r#"
1954 little_endian_packets
1955 group C { C { x = 1 } }
1956 "#
1957 );
1958 }
1959
1960 #[test]
1961 fn test_e3() {
1962 raises!(
1963 UndeclaredGroupIdentifier,
1964 r#"
1965 little_endian_packets
1966 packet A { C { x = 1 } }
1967 "#
1968 );
1969 }
1970
1971 #[test]
1972 fn test_e4() {
1973 raises!(
1974 InvalidGroupIdentifier,
1975 r#"
1976 little_endian_packets
1977 struct C { x : 8 }
1978 packet A { C { x = 1 } }
1979 "#
1980 );
1981 }
1982
1983 #[test]
1984 fn test_e5() {
1985 raises!(
1986 UndeclaredTypeIdentifier,
1987 r#"
1988 little_endian_packets
1989 packet A { x : B }
1990 "#
1991 );
1992
1993 raises!(
1994 UndeclaredTypeIdentifier,
1995 r#"
1996 little_endian_packets
1997 packet A { x : B[] }
1998 "#
1999 );
2000 }
2001
2002 #[test]
2003 fn test_e6() {
2004 raises!(
2005 InvalidTypeIdentifier,
2006 r#"
2007 little_endian_packets
2008 packet A { x : 8 }
2009 packet B { x : A }
2010 "#
2011 );
2012
2013 raises!(
2014 InvalidTypeIdentifier,
2015 r#"
2016 little_endian_packets
2017 packet A { x : 8 }
2018 packet B { x : A[] }
2019 "#
2020 );
2021 }
2022
2023 #[test]
2024 fn test_e7() {
2025 raises!(
2026 UndeclaredParentIdentifier,
2027 r#"
2028 little_endian_packets
2029 packet A : B { }
2030 "#
2031 );
2032
2033 raises!(
2034 UndeclaredParentIdentifier,
2035 r#"
2036 little_endian_packets
2037 struct A : B { }
2038 "#
2039 );
2040 }
2041
2042 #[test]
2043 fn test_e8() {
2044 raises!(
2045 InvalidParentIdentifier,
2046 r#"
2047 little_endian_packets
2048 struct A { }
2049 packet B : A { }
2050 "#
2051 );
2052
2053 raises!(
2054 InvalidParentIdentifier,
2055 r#"
2056 little_endian_packets
2057 packet A { }
2058 struct B : A { }
2059 "#
2060 );
2061
2062 raises!(
2063 InvalidParentIdentifier,
2064 r#"
2065 little_endian_packets
2066 group A { x : 1 }
2067 struct B : A { }
2068 "#
2069 );
2070 }
2071
2072 #[ignore]
2073 #[test]
2074 fn test_e9() {
2075 raises!(
2076 UndeclaredTestIdentifier,
2077 r#"
2078 little_endian_packets
2079 test A { "aaa" }
2080 "#
2081 );
2082 }
2083
2084 #[ignore]
2085 #[test]
2086 fn test_e10() {
2087 raises!(
2088 InvalidTestIdentifier,
2089 r#"
2090 little_endian_packets
2091 struct A { }
2092 test A { "aaa" }
2093 "#
2094 );
2095
2096 raises!(
2097 InvalidTestIdentifier,
2098 r#"
2099 little_endian_packets
2100 group A { x : 8 }
2101 test A { "aaa" }
2102 "#
2103 );
2104 }
2105
2106 #[test]
2107 fn test_e11() {
2108 raises!(
2109 DuplicateFieldIdentifier,
2110 r#"
2111 little_endian_packets
2112 enum A : 8 { X = 0 }
2113 struct B {
2114 x : 8,
2115 x : A
2116 }
2117 "#
2118 );
2119
2120 raises!(
2121 DuplicateFieldIdentifier,
2122 r#"
2123 little_endian_packets
2124 enum A : 8 { X = 0 }
2125 packet B {
2126 x : 8,
2127 x : A[]
2128 }
2129 "#
2130 );
2131 }
2132
2133 #[test]
2134 fn test_e12() {
2135 raises!(
2136 DuplicateTagIdentifier,
2137 r#"
2138 little_endian_packets
2139 enum A : 8 {
2140 X = 0,
2141 X = 1,
2142 }
2143 "#
2144 );
2145
2146 raises!(
2147 DuplicateTagIdentifier,
2148 r#"
2149 little_endian_packets
2150 enum A : 8 {
2151 X = 0,
2152 A = 1..10 {
2153 X = 1,
2154 }
2155 }
2156 "#
2157 );
2158
2159 raises!(
2160 DuplicateTagIdentifier,
2161 r#"
2162 little_endian_packets
2163 enum A : 8 {
2164 X = 0,
2165 X = 1..10,
2166 }
2167 "#
2168 );
2169
2170 raises!(
2171 DuplicateTagIdentifier,
2172 r#"
2173 little_endian_packets
2174 enum A : 8 {
2175 X = 0,
2176 X = ..,
2177 }
2178 "#
2179 );
2180 }
2181
2182 #[test]
2183 fn test_e13() {
2184 raises!(
2185 DuplicateTagValue,
2186 r#"
2187 little_endian_packets
2188 enum A : 8 {
2189 X = 0,
2190 Y = 0,
2191 }
2192 "#
2193 );
2194
2195 raises!(
2196 DuplicateTagValue,
2197 r#"
2198 little_endian_packets
2199 enum A : 8 {
2200 A = 1..10 {
2201 X = 1,
2202 Y = 1,
2203 }
2204 }
2205 "#
2206 );
2207 }
2208
2209 #[test]
2210 fn test_e14() {
2211 raises!(
2212 InvalidTagValue,
2213 r#"
2214 little_endian_packets
2215 enum A : 8 {
2216 X = 256,
2217 }
2218 "#
2219 );
2220
2221 raises!(
2222 InvalidTagValue,
2223 r#"
2224 little_endian_packets
2225 enum A : 8 {
2226 A = 0,
2227 X = 10..20 {
2228 B = 1,
2229 },
2230 }
2231 "#
2232 );
2233 }
2234
2235 #[test]
2236 fn test_e15() {
2237 raises!(
2238 UndeclaredConstraintIdentifier,
2239 r#"
2240 little_endian_packets
2241 packet A { }
2242 packet B : A (x = 1) { }
2243 "#
2244 );
2245
2246 raises!(
2247 UndeclaredConstraintIdentifier,
2248 r#"
2249 little_endian_packets
2250 group A { x : 8 }
2251 packet B {
2252 A { y = 1 }
2253 }
2254 "#
2255 );
2256
2257 valid!(
2258 r#"
2259 little_endian_packets
2260 group A { x : 8 }
2261 packet B { A }
2262 packet C : B (x = 1) { }
2263 "#
2264 );
2265 }
2266
2267 #[test]
2268 fn test_e16() {
2269 raises!(
2270 InvalidConstraintIdentifier,
2271 r#"
2272 little_endian_packets
2273 packet A { x : 8[] }
2274 packet B : A (x = 1) { }
2275 "#
2276 );
2277
2278 raises!(
2279 InvalidConstraintIdentifier,
2280 r#"
2281 little_endian_packets
2282 group A { x : 8[] }
2283 packet B {
2284 A { x = 1 }
2285 }
2286 "#
2287 );
2288 }
2289
2290 #[test]
2291 fn test_e17() {
2292 raises!(
2293 E17,
2294 r#"
2295 little_endian_packets
2296 packet A { x : 8 }
2297 packet B : A (x = X) { }
2298 "#
2299 );
2300
2301 raises!(
2302 E17,
2303 r#"
2304 little_endian_packets
2305 group A { x : 8 }
2306 packet B {
2307 A { x = X }
2308 }
2309 "#
2310 );
2311 }
2312
2313 #[test]
2314 fn test_e18() {
2315 raises!(
2316 ConstraintValueOutOfRange,
2317 r#"
2318 little_endian_packets
2319 packet A { x : 8 }
2320 packet B : A (x = 256) { }
2321 "#
2322 );
2323
2324 raises!(
2325 ConstraintValueOutOfRange,
2326 r#"
2327 little_endian_packets
2328 group A { x : 8 }
2329 packet B {
2330 A { x = 256 }
2331 }
2332 "#
2333 );
2334 }
2335
2336 #[test]
2337 fn test_e19() {
2338 raises!(
2339 E19,
2340 r#"
2341 little_endian_packets
2342 enum C : 8 { X = 0 }
2343 packet A { x : C }
2344 packet B : A (x = 0) { }
2345 "#
2346 );
2347
2348 raises!(
2349 E19,
2350 r#"
2351 little_endian_packets
2352 enum C : 8 { X = 0 }
2353 group A { x : C }
2354 packet B {
2355 A { x = 0 }
2356 }
2357 "#
2358 );
2359 }
2360
2361 #[test]
2362 fn test_e20() {
2363 raises!(
2364 E20,
2365 r#"
2366 little_endian_packets
2367 enum C : 8 { X = 0 }
2368 packet A { x : C }
2369 packet B : A (x = Y) { }
2370 "#
2371 );
2372
2373 raises!(
2374 E20,
2375 r#"
2376 little_endian_packets
2377 enum C : 8 { X = 0 }
2378 group A { x : C }
2379 packet B {
2380 A { x = Y }
2381 }
2382 "#
2383 );
2384 }
2385
2386 #[test]
2387 fn test_e21() {
2388 raises!(
2389 E21,
2390 r#"
2391 little_endian_packets
2392 struct C { }
2393 packet A { x : C }
2394 packet B : A (x = 0) { }
2395 "#
2396 );
2397
2398 raises!(
2399 E21,
2400 r#"
2401 little_endian_packets
2402 struct C { }
2403 group A { x : C }
2404 packet B {
2405 A { x = 0 }
2406 }
2407 "#
2408 );
2409 }
2410
2411 #[test]
2412 fn test_e22() {
2413 raises!(
2414 DuplicateConstraintIdentifier,
2415 r#"
2416 little_endian_packets
2417 packet A { x: 8 }
2418 packet B : A (x = 0, x = 1) { }
2419 "#
2420 );
2421
2422 raises!(
2423 DuplicateConstraintIdentifier,
2424 r#"
2425 little_endian_packets
2426 packet A { x: 8 }
2427 packet B : A (x = 0) { }
2428 packet C : B (x = 1) { }
2429 "#
2430 );
2431
2432 raises!(
2433 DuplicateConstraintIdentifier,
2434 r#"
2435 little_endian_packets
2436 group A { x : 8 }
2437 packet B {
2438 A { x = 0, x = 1 }
2439 }
2440 "#
2441 );
2442 }
2443
2444 #[test]
2445 fn test_e23() {
2446 raises!(
2447 DuplicateSizeField,
2448 r#"
2449 little_endian_packets
2450 struct A {
2451 _size_ (_payload_) : 8,
2452 _size_ (_payload_) : 8,
2453 _payload_,
2454 }
2455 "#
2456 );
2457
2458 raises!(
2459 DuplicateSizeField,
2460 r#"
2461 little_endian_packets
2462 struct A {
2463 _count_ (x) : 8,
2464 _size_ (x) : 8,
2465 x: 8[],
2466 }
2467 "#
2468 );
2469 }
2470
2471 #[test]
2472 fn test_e24() {
2473 raises!(
2474 UndeclaredSizeIdentifier,
2475 r#"
2476 little_endian_packets
2477 struct A {
2478 _size_ (x) : 8,
2479 }
2480 "#
2481 );
2482
2483 raises!(
2484 UndeclaredSizeIdentifier,
2485 r#"
2486 little_endian_packets
2487 struct A {
2488 _size_ (_payload_) : 8,
2489 }
2490 "#
2491 );
2492 }
2493
2494 #[test]
2495 fn test_e25() {
2496 raises!(
2497 InvalidSizeIdentifier,
2498 r#"
2499 little_endian_packets
2500 enum B : 8 { X = 0 }
2501 struct A {
2502 _size_ (x) : 8,
2503 x : B,
2504 }
2505 "#
2506 );
2507 }
2508
2509 #[test]
2510 fn test_e26() {
2511 raises!(
2512 DuplicateCountField,
2513 r#"
2514 little_endian_packets
2515 struct A {
2516 _size_ (x) : 8,
2517 _count_ (x) : 8,
2518 x: 8[],
2519 }
2520 "#
2521 );
2522 }
2523
2524 #[test]
2525 fn test_e27() {
2526 raises!(
2527 UndeclaredCountIdentifier,
2528 r#"
2529 little_endian_packets
2530 struct A {
2531 _count_ (x) : 8,
2532 }
2533 "#
2534 );
2535 }
2536
2537 #[test]
2538 fn test_e28() {
2539 raises!(
2540 InvalidCountIdentifier,
2541 r#"
2542 little_endian_packets
2543 enum B : 8 { X = 0 }
2544 struct A {
2545 _count_ (x) : 8,
2546 x : B,
2547 }
2548 "#
2549 );
2550 }
2551
2552 #[test]
2553 fn test_e29() {
2554 raises!(
2555 DuplicateElementSizeField,
2556 r#"
2557 little_endian_packets
2558 struct A {
2559 _elementsize_ (x) : 8,
2560 _elementsize_ (x) : 8,
2561 x: 8[],
2562 }
2563 "#
2564 );
2565 }
2566
2567 #[test]
2568 fn test_e30() {
2569 raises!(
2570 UndeclaredElementSizeIdentifier,
2571 r#"
2572 little_endian_packets
2573 struct A {
2574 _elementsize_ (x) : 8,
2575 }
2576 "#
2577 );
2578 }
2579
2580 #[test]
2581 fn test_e31() {
2582 raises!(
2583 InvalidElementSizeIdentifier,
2584 r#"
2585 little_endian_packets
2586 enum B : 8 { X = 0 }
2587 struct A {
2588 _elementsize_ (x) : 8,
2589 x : B,
2590 }
2591 "#
2592 );
2593 }
2594
2595 #[test]
2596 fn test_e32() {
2597 raises!(
2598 FixedValueOutOfRange,
2599 r#"
2600 little_endian_packets
2601 struct A {
2602 _fixed_ = 256 : 8,
2603 }
2604 "#
2605 );
2606 }
2607
2608 #[test]
2609 fn test_e33() {
2610 raises!(
2611 E33,
2612 r#"
2613 little_endian_packets
2614 struct A {
2615 _fixed_ = X : B,
2616 }
2617 "#
2618 );
2619 }
2620
2621 #[test]
2622 fn test_e34() {
2623 raises!(
2624 E34,
2625 r#"
2626 little_endian_packets
2627 enum B : 8 { X = 0 }
2628 struct A {
2629 _fixed_ = Y : B,
2630 }
2631 "#
2632 );
2633 }
2634
2635 #[test]
2636 fn test_e35() {
2637 raises!(
2638 E35,
2639 r#"
2640 little_endian_packets
2641 struct B { }
2642 struct A {
2643 _fixed_ = X : B,
2644 }
2645 "#
2646 );
2647 }
2648
2649 #[test]
2650 fn test_e36() {
2651 raises!(
2652 DuplicatePayloadField,
2653 r#"
2654 little_endian_packets
2655 packet A {
2656 _payload_,
2657 _body_,
2658 }
2659 "#
2660 );
2661
2662 raises!(
2663 DuplicatePayloadField,
2664 r#"
2665 little_endian_packets
2666 packet A {
2667 _body_,
2668 _payload_,
2669 }
2670 "#
2671 );
2672 }
2673
2674 #[test]
2675 fn test_e37() {
2676 raises!(
2677 MissingPayloadField,
2678 r#"
2679 little_endian_packets
2680 packet A { x : 8 }
2681 packet B : A { y : 8 }
2682 "#
2683 );
2684
2685 raises!(
2686 MissingPayloadField,
2687 r#"
2688 little_endian_packets
2689 packet A { x : 8 }
2690 packet B : A (x = 0) { }
2691 packet C : B { y : 8 }
2692 "#
2693 );
2694 }
2695
2696 #[test]
2697 fn test_e38() {
2698 raises!(
2699 RedundantArraySize,
2700 r#"
2701 little_endian_packets
2702 packet A {
2703 _size_ (x) : 8,
2704 x : 8[8]
2705 }
2706 "#
2707 );
2708
2709 raises!(
2710 RedundantArraySize,
2711 r#"
2712 little_endian_packets
2713 packet A {
2714 _count_ (x) : 8,
2715 x : 8[8]
2716 }
2717 "#
2718 );
2719 }
2720
2721 #[test]
2722 fn test_e39() {
2723 raises!(
2724 InvalidPaddingField,
2725 r#"
2726 little_endian_packets
2727 packet A {
2728 _padding_ [16],
2729 x : 8[]
2730 }
2731 "#
2732 );
2733
2734 raises!(
2735 InvalidPaddingField,
2736 r#"
2737 little_endian_packets
2738 enum A : 8 { X = 0 }
2739 packet B {
2740 x : A,
2741 _padding_ [16]
2742 }
2743 "#
2744 );
2745
2746 valid!(
2747 r#"
2748 little_endian_packets
2749 packet A {
2750 x : 8[],
2751 _padding_ [16]
2752 }
2753 "#
2754 );
2755 }
2756
2757 #[test]
2758 fn test_e40() {
2759 raises!(
2760 InvalidTagRange,
2761 r#"
2762 little_endian_packets
2763 enum A : 8 {
2764 X = 4..2,
2765 }
2766 "#
2767 );
2768
2769 raises!(
2770 InvalidTagRange,
2771 r#"
2772 little_endian_packets
2773 enum A : 8 {
2774 X = 2..2,
2775 }
2776 "#
2777 );
2778
2779 raises!(
2780 InvalidTagRange,
2781 r#"
2782 little_endian_packets
2783 enum A : 8 {
2784 X = 258..259,
2785 }
2786 "#
2787 );
2788 }
2789
2790 #[test]
2791 fn test_e41() {
2792 raises!(
2793 DuplicateTagRange,
2794 r#"
2795 little_endian_packets
2796 enum A : 8 {
2797 X = 0..15,
2798 Y = 8..31,
2799 }
2800 "#
2801 );
2802
2803 raises!(
2804 DuplicateTagRange,
2805 r#"
2806 little_endian_packets
2807 enum A : 8 {
2808 X = 8..31,
2809 Y = 0..15,
2810 }
2811 "#
2812 );
2813
2814 raises!(
2815 DuplicateTagRange,
2816 r#"
2817 little_endian_packets
2818 enum A : 8 {
2819 X = 1..9,
2820 Y = 9..11,
2821 }
2822 "#
2823 );
2824 }
2825
2826 #[test]
2827 fn test_e42() {
2828 raises!(
2829 E42,
2830 r#"
2831 little_endian_packets
2832 enum C : 8 { X = 0..15 }
2833 packet A { x : C }
2834 packet B : A (x = X) { }
2835 "#
2836 );
2837
2838 raises!(
2839 E42,
2840 r#"
2841 little_endian_packets
2842 enum C : 8 { X = 0..15 }
2843 group A { x : C }
2844 packet B {
2845 A { x = X }
2846 }
2847 "#
2848 );
2849 }
2850
2851 #[test]
2852 fn test_e43() {
2853 raises!(
2854 E43,
2855 r#"
2856 little_endian_packets
2857 enum A : 8 {
2858 A = 0,
2859 B = 1,
2860 X = 1..15,
2861 }
2862 "#
2863 );
2864 }
2865
2866 #[test]
2867 fn test_e44() {
2868 raises!(
2869 DuplicateDefaultTag,
2870 r#"
2871 little_endian_packets
2872 enum A : 8 {
2873 A = 0,
2874 X = ..,
2875 B = 1,
2876 Y = ..,
2877 }
2878 "#
2879 );
2880 }
2881
2882 #[test]
2883 fn test_e45() {
2884 valid!(
2885 r#"
2886 little_endian_packets
2887 packet B {
2888 c : 1,
2889 _reserved_ : 7,
2890 x : 8 if c = 1,
2891 }
2892 "#
2893 );
2894
2895 valid!(
2896 r#"
2897 little_endian_packets
2898 enum A : 8 { X = 0 }
2899 packet B {
2900 c : 1,
2901 _reserved_ : 7,
2902 x : A if c = 0,
2903 }
2904 "#
2905 );
2906
2907 raises!(
2908 InvalidOptionalField,
2909 r#"
2910 little_endian_packets
2911 packet B {
2912 c : 1,
2913 _reserved_ : 7,
2914 x : 8[] if c = 1,
2915 }
2916 "#
2917 );
2918
2919 raises!(
2920 InvalidOptionalField,
2921 r#"
2922 little_endian_packets
2923 packet A {
2924 c : 1,
2925 _reserved_ : 7,
2926 _size_(x) : 8 if c = 1,
2927 x : 8[],
2928 }
2929 "#
2930 );
2931
2932 raises!(
2933 InvalidOptionalField,
2934 r#"
2935 little_endian_packets
2936 packet B {
2937 c : 1,
2938 _reserved_ : 7,
2939 x : 8[],
2940 _padding_ [10] if c = 1,
2941 }
2942 "#
2943 );
2944
2945 raises!(
2946 InvalidOptionalField,
2947 r#"
2948 little_endian_packets
2949 packet B {
2950 c : 1,
2951 _reserved_ : 7,
2952 _reserved_ : 8 if c = 1,
2953 }
2954 "#
2955 );
2956
2957 raises!(
2958 InvalidOptionalField,
2959 r#"
2960 little_endian_packets
2961 packet B {
2962 c : 1,
2963 _reserved_ : 7,
2964 _fixed_ = 0x42 : 8 if c = 1,
2965 }
2966 "#
2967 );
2968
2969 raises!(
2970 InvalidOptionalField,
2971 r#"
2972 little_endian_packets
2973 enum A : 8 { X = 0 }
2974 packet B {
2975 c : 1,
2976 _reserved_ : 7,
2977 _fixed_ = X : A if c = 1,
2978 }
2979 "#
2980 );
2981 }
2982
2983 #[test]
2984 fn test_e46() {
2985 raises!(
2986 UndeclaredConditionIdentifier,
2987 r#"
2988 little_endian_packets
2989 packet B {
2990 x : 8 if c = 1,
2991 _reserved_ : 7,
2992 }
2993 "#
2994 );
2995 }
2996
2997 #[test]
2998 fn test_e47() {
2999 raises!(
3000 InvalidConditionIdentifier,
3001 r#"
3002 little_endian_packets
3003 enum A : 8 { X = 0 }
3004 packet B {
3005 c : A,
3006 x : 8 if c = 1,
3007 }
3008 "#
3009 );
3010
3011 raises!(
3012 InvalidConditionIdentifier,
3013 r#"
3014 little_endian_packets
3015 packet B {
3016 c : 8[],
3017 x : 8 if c = 1,
3018 }
3019 "#
3020 );
3021
3022 raises!(
3023 InvalidConditionIdentifier,
3024 r#"
3025 little_endian_packets
3026 packet B {
3027 c : 8,
3028 x : 8 if c = 1,
3029 }
3030 "#
3031 );
3032 }
3033
3034 #[test]
3035 fn test_e48() {
3036 raises!(
3037 InvalidConditionValue,
3038 r#"
3039 little_endian_packets
3040 packet B {
3041 c : 1,
3042 _reserved_ : 7,
3043 x : 8 if c = A,
3044 }
3045 "#
3046 );
3047
3048 raises!(
3049 InvalidConditionValue,
3050 r#"
3051 little_endian_packets
3052 packet B {
3053 c : 1,
3054 _reserved_ : 7,
3055 x : 8 if c = 2,
3056 }
3057 "#
3058 );
3059 }
3060
3061 #[test]
3062 fn test_e49() {
3063 raises!(
3064 E49,
3065 r#"
3066 little_endian_packets
3067 packet B {
3068 c0 : 1,
3069 _reserved_ : 7,
3070 c1 : 1 if c0 = 1,
3071 _reserved_ : 7,
3072 x : 8 if c1 = 1,
3073 }
3074 "#
3075 );
3076 }
3077
3078 #[test]
3079 fn test_e51() {
3080 raises!(
3081 InvalidFieldOffset,
3082 r#"
3083 little_endian_packets
3084 struct S { a: 8 }
3085 packet A {
3086 a : 1,
3087 s : S,
3088 c : 7,
3089 }
3090 "#
3091 );
3092
3093 raises!(
3094 InvalidFieldOffset,
3095 r#"
3096 little_endian_packets
3097 packet A {
3098 a : 1,
3099 b : 8[],
3100 c : 7,
3101 }
3102 "#
3103 );
3104
3105 raises!(
3106 InvalidFieldOffset,
3107 r#"
3108 big_endian_packets
3109 packet A {
3110 a : 1,
3111 _payload_,
3112 b : 7,
3113 }
3114 "#
3115 );
3116
3117 raises!(
3118 InvalidFieldOffset,
3119 r#"
3120 big_endian_packets
3121 packet A {
3122 a : 1,
3123 _body_,
3124 b : 7,
3125 }
3126 "#
3127 );
3128
3129 raises!(
3130 InvalidFieldOffset,
3131 r#"
3132 little_endian_packets
3133 custom_field F : 8 "f"
3134 packet A {
3135 a : 1,
3136 f : F,
3137 }
3138 "#
3139 );
3140 }
3141
3142 #[test]
3143 fn test_e52() {
3144 raises!(
3145 InvalidPacketSize,
3146 r#"
3147 little_endian_packets
3148 packet A {
3149 a : 1,
3150 }
3151 "#
3152 );
3153
3154 raises!(
3155 InvalidPacketSize,
3156 r#"
3157 little_endian_packets
3158 packet A {
3159 a : 8[],
3160 b : 1,
3161 }
3162 "#
3163 );
3164
3165 raises!(
3166 InvalidPacketSize,
3167 r#"
3168 little_endian_packets
3169 packet A {
3170 a : 8[],
3171 b : 1,
3172 }
3173 "#
3174 );
3175
3176 raises!(
3177 InvalidPacketSize,
3178 r#"
3179 little_endian_packets
3180 struct S {
3181 _size_(_payload_) : 8,
3182 _payload_,
3183 }
3184 packet A {
3185 a : S,
3186 b : 1,
3187 }
3188 "#
3189 );
3190
3191 raises!(
3192 InvalidPacketSize,
3193 r#"
3194 little_endian_packets
3195 struct A {
3196 a : 1,
3197 }
3198 "#
3199 );
3200 }
3201
3202 #[test]
3203 fn test_e53() {
3204 raises!(
3205 InvalidFieldSize,
3206 r#"
3207 little_endian_packets
3208 packet A {
3209 a : 12[],
3210 }
3211 "#
3212 );
3213 }
3214
3215 #[test]
3216 fn test_enum_declaration() {
3217 valid!(
3218 r#"
3219 little_endian_packets
3220 enum A : 7 {
3221 X = 0,
3222 Y = 1,
3223 Z = 127,
3224 }
3225 "#
3226 );
3227
3228 valid!(
3229 r#"
3230 little_endian_packets
3231 enum A : 7 {
3232 A = 50..100 {
3233 X = 50,
3234 Y = 100,
3235 },
3236 Z = 101,
3237 }
3238 "#
3239 );
3240
3241 valid!(
3242 r#"
3243 little_endian_packets
3244 enum A : 7 {
3245 A = 50..100,
3246 X = 101,
3247 }
3248 "#
3249 );
3250
3251 valid!(
3252 r#"
3253 little_endian_packets
3254 enum A : 7 {
3255 A = 50..100,
3256 X = 101,
3257 UNKNOWN = ..,
3258 }
3259 "#
3260 );
3261 }
3262
3263 use analyzer::Size;
3264 use Size::*;
3265
3266 #[derive(Debug, PartialEq, Eq)]
3267 struct Annotations {
3268 size: Size,
3269 parent_size: Size,
3270 payload_size: Size,
3271 fields: Vec<Size>,
3272 }
3273
3274 fn annotations(text: &str) -> Vec<Annotations> {
3275 let mut db = ast::SourceDatabase::new();
3276 let file = parse_inline(&mut db, "stdin", text.to_owned()).expect("parsing failure");
3277 let file = analyzer::analyze(&file).expect("analyzer failure");
3278 let schema = analyzer::Schema::new(&file);
3279 file.declarations
3280 .iter()
3281 .map(|decl| Annotations {
3282 size: schema.decl_size(decl.key),
3283 parent_size: schema.parent_size(decl.key),
3284 payload_size: schema.payload_size(decl.key),
3285 fields: decl.fields().map(|field| schema.field_size(field.key)).collect(),
3286 })
3287 .collect()
3288 }
3289
3290 #[test]
3291 fn test_bitfield_annotations() {
3292 assert_that!(
3293 annotations(
3294 r#"
3295 little_endian_packets
3296 enum E : 6 { X=0, Y=1 }
3297 packet A {
3298 a : 14,
3299 b : E,
3300 _reserved_ : 3,
3301 _fixed_ = 3 : 4,
3302 _fixed_ = X : E,
3303 _size_(_payload_) : 7,
3304 _payload_,
3305 }
3306 "#
3307 ),
3308 eq(vec![
3309 Annotations {
3310 size: Static(6),
3311 parent_size: Static(0),
3312 payload_size: Static(0),
3313 fields: vec![]
3314 },
3315 Annotations {
3316 size: Static(40),
3317 parent_size: Static(0),
3318 payload_size: Dynamic,
3319 fields: vec![
3320 Static(14),
3321 Static(6),
3322 Static(3),
3323 Static(4),
3324 Static(6),
3325 Static(7),
3326 Dynamic
3327 ]
3328 },
3329 ])
3330 )
3331 }
3332
3333 #[test]
3334 fn test_typedef_annotations() {
3335 assert_that!(
3337 annotations(
3338 r#"
3339 little_endian_packets
3340 struct S {
3341 a: 8[4],
3342 }
3343 packet A {
3344 a: 16,
3345 s: S,
3346 }
3347 "#
3348 ),
3349 eq(vec![
3350 Annotations {
3351 size: Static(32),
3352 parent_size: Static(0),
3353 payload_size: Static(0),
3354 fields: vec![Static(32)]
3355 },
3356 Annotations {
3357 size: Static(48),
3358 parent_size: Static(0),
3359 payload_size: Static(0),
3360 fields: vec![Static(16), Static(32)]
3361 },
3362 ])
3363 );
3364
3365 assert_that!(
3367 annotations(
3368 r#"
3369 little_endian_packets
3370 struct S {
3371 _size_ (a) : 8,
3372 a: 8[],
3373 }
3374 packet A {
3375 a: 16,
3376 s: S,
3377 }
3378 "#
3379 ),
3380 eq(vec![
3381 Annotations {
3382 size: Dynamic,
3383 parent_size: Static(0),
3384 payload_size: Static(0),
3385 fields: vec![Static(8), Dynamic]
3386 },
3387 Annotations {
3388 size: Dynamic,
3389 parent_size: Static(0),
3390 payload_size: Static(0),
3391 fields: vec![Static(16), Dynamic]
3392 },
3393 ])
3394 );
3395
3396 assert_that!(
3398 annotations(
3399 r#"
3400 little_endian_packets
3401 struct S {
3402 a: 8[],
3403 }
3404 packet A {
3405 a: 16,
3406 s: S,
3407 }
3408 "#
3409 ),
3410 eq(vec![
3411 Annotations {
3412 size: Unknown,
3413 parent_size: Static(0),
3414 payload_size: Static(0),
3415 fields: vec![Unknown]
3416 },
3417 Annotations {
3418 size: Unknown,
3419 parent_size: Static(0),
3420 payload_size: Static(0),
3421 fields: vec![Static(16), Unknown]
3422 },
3423 ])
3424 );
3425 }
3426
3427 #[test]
3428 fn test_array_annotations() {
3429 assert_that!(
3431 annotations(
3432 r#"
3433 little_endian_packets
3434 enum E : 8 { X=0, Y=1 }
3435 packet A {
3436 a: E[8],
3437 }
3438 "#
3439 ),
3440 eq(vec![
3441 Annotations {
3442 size: Static(8),
3443 parent_size: Static(0),
3444 payload_size: Static(0),
3445 fields: vec![]
3446 },
3447 Annotations {
3448 size: Static(64),
3449 parent_size: Static(0),
3450 payload_size: Static(0),
3451 fields: vec![Static(64)]
3452 },
3453 ])
3454 );
3455
3456 assert_that!(
3458 annotations(
3459 r#"
3460 little_endian_packets
3461 struct S { _size_(a): 8, a: 8[] }
3462 packet A {
3463 a: S[8],
3464 }
3465 "#
3466 ),
3467 eq(vec![
3468 Annotations {
3469 size: Dynamic,
3470 parent_size: Static(0),
3471 payload_size: Static(0),
3472 fields: vec![Static(8), Dynamic]
3473 },
3474 Annotations {
3475 size: Dynamic,
3476 parent_size: Static(0),
3477 payload_size: Static(0),
3478 fields: vec![Dynamic]
3479 },
3480 ])
3481 );
3482
3483 assert_that!(
3485 annotations(
3486 r#"
3487 little_endian_packets
3488 struct S { a: 7, _reserved_: 1 }
3489 packet A {
3490 _size_ (a) : 8,
3491 a: S[],
3492 }
3493 "#
3494 ),
3495 eq(vec![
3496 Annotations {
3497 size: Static(8),
3498 parent_size: Static(0),
3499 payload_size: Static(0),
3500 fields: vec![Static(7), Static(1)]
3501 },
3502 Annotations {
3503 size: Dynamic,
3504 parent_size: Static(0),
3505 payload_size: Static(0),
3506 fields: vec![Static(8), Dynamic]
3507 },
3508 ])
3509 );
3510
3511 assert_that!(
3513 annotations(
3514 r#"
3515 little_endian_packets
3516 struct S { _size_(a): 8, a: 8[] }
3517 packet A {
3518 _size_ (a) : 8,
3519 a: S[],
3520 }
3521 "#
3522 ),
3523 eq(vec![
3524 Annotations {
3525 size: Dynamic,
3526 parent_size: Static(0),
3527 payload_size: Static(0),
3528 fields: vec![Static(8), Dynamic]
3529 },
3530 Annotations {
3531 size: Dynamic,
3532 parent_size: Static(0),
3533 payload_size: Static(0),
3534 fields: vec![Static(8), Dynamic]
3535 },
3536 ])
3537 );
3538
3539 assert_that!(
3541 annotations(
3542 r#"
3543 little_endian_packets
3544 struct S { a: 7, _reserved_: 1 }
3545 packet A {
3546 _count_ (a) : 8,
3547 a: S[],
3548 }
3549 "#
3550 ),
3551 eq(vec![
3552 Annotations {
3553 size: Static(8),
3554 parent_size: Static(0),
3555 payload_size: Static(0),
3556 fields: vec![Static(7), Static(1)]
3557 },
3558 Annotations {
3559 size: Dynamic,
3560 parent_size: Static(0),
3561 payload_size: Static(0),
3562 fields: vec![Static(8), Dynamic]
3563 },
3564 ])
3565 );
3566
3567 assert_that!(
3569 annotations(
3570 r#"
3571 little_endian_packets
3572 struct S { _size_(a): 8, a: 8[] }
3573 packet A {
3574 _count_ (a) : 8,
3575 a: S[],
3576 }
3577 "#
3578 ),
3579 eq(vec![
3580 Annotations {
3581 size: Dynamic,
3582 parent_size: Static(0),
3583 payload_size: Static(0),
3584 fields: vec![Static(8), Dynamic]
3585 },
3586 Annotations {
3587 size: Dynamic,
3588 parent_size: Static(0),
3589 payload_size: Static(0),
3590 fields: vec![Static(8), Dynamic]
3591 },
3592 ])
3593 );
3594
3595 assert_that!(
3597 annotations(
3598 r#"
3599 little_endian_packets
3600 struct S { a: 7, _fixed_ = 1 : 1 }
3601 packet A {
3602 a: S[],
3603 }
3604 "#
3605 ),
3606 eq(vec![
3607 Annotations {
3608 size: Static(8),
3609 parent_size: Static(0),
3610 payload_size: Static(0),
3611 fields: vec![Static(7), Static(1)]
3612 },
3613 Annotations {
3614 size: Unknown,
3615 parent_size: Static(0),
3616 payload_size: Static(0),
3617 fields: vec![Unknown]
3618 },
3619 ])
3620 );
3621
3622 assert_that!(
3624 annotations(
3625 r#"
3626 little_endian_packets
3627 struct S { _size_(a): 8, a: 8[] }
3628 packet A {
3629 a: S[],
3630 }
3631 "#
3632 ),
3633 eq(vec![
3634 Annotations {
3635 size: Dynamic,
3636 parent_size: Static(0),
3637 payload_size: Static(0),
3638 fields: vec![Static(8), Dynamic]
3639 },
3640 Annotations {
3641 size: Unknown,
3642 parent_size: Static(0),
3643 payload_size: Static(0),
3644 fields: vec![Unknown]
3645 },
3646 ])
3647 );
3648
3649 assert_that!(
3651 annotations(
3652 r#"
3653 little_endian_packets
3654 struct S {
3655 _count_(a): 40,
3656 a: 16[],
3657 }
3658 packet A {
3659 a: S[],
3660 _padding_ [128],
3661 }
3662 "#
3663 ),
3664 eq(vec![
3665 Annotations {
3666 size: Dynamic,
3667 parent_size: Static(0),
3668 payload_size: Static(0),
3669 fields: vec![Static(40), Dynamic]
3670 },
3671 Annotations {
3672 size: Static(1024),
3673 parent_size: Static(0),
3674 payload_size: Static(0),
3675 fields: vec![Unknown, Static(0)]
3676 },
3677 ])
3678 );
3679 }
3680
3681 #[test]
3682 fn test_payload_annotations() {
3683 assert_that!(
3685 annotations(
3686 r#"
3687 little_endian_packets
3688 packet A {
3689 _size_(_payload_) : 8,
3690 _payload_
3691 }
3692 "#
3693 ),
3694 eq(vec![Annotations {
3695 size: Static(8),
3696 parent_size: Static(0),
3697 payload_size: Dynamic,
3698 fields: vec![Static(8), Dynamic]
3699 },])
3700 );
3701
3702 assert_that!(
3704 annotations(
3705 r#"
3706 little_endian_packets
3707 packet A {
3708 a : 8,
3709 _payload_
3710 }
3711 "#
3712 ),
3713 eq(vec![Annotations {
3714 size: Static(8),
3715 parent_size: Static(0),
3716 payload_size: Unknown,
3717 fields: vec![Static(8), Unknown]
3718 },])
3719 );
3720 }
3721
3722 #[test]
3723 fn test_body_annotations() {
3724 assert_that!(
3726 annotations(
3727 r#"
3728 little_endian_packets
3729 packet A {
3730 _size_(_body_) : 8,
3731 _body_
3732 }
3733 "#
3734 ),
3735 eq(vec![Annotations {
3736 size: Static(8),
3737 parent_size: Static(0),
3738 payload_size: Dynamic,
3739 fields: vec![Static(8), Dynamic]
3740 },])
3741 );
3742
3743 assert_that!(
3745 annotations(
3746 r#"
3747 little_endian_packets
3748 packet A {
3749 a : 8,
3750 _body_
3751 }
3752 "#
3753 ),
3754 eq(vec![Annotations {
3755 size: Static(8),
3756 parent_size: Static(0),
3757 payload_size: Unknown,
3758 fields: vec![Static(8), Unknown]
3759 },])
3760 );
3761 }
3762
3763 #[test]
3764 fn test_decl_annotations() {
3765 assert_that!(
3767 annotations(
3768 r#"
3769 little_endian_packets
3770 packet A {
3771 a: 2,
3772 _reserved_: 6,
3773 _payload_
3774 }
3775 packet B : A {
3776 b: 8,
3777 }
3778 "#
3779 ),
3780 eq(vec![
3781 Annotations {
3782 size: Static(8),
3783 parent_size: Static(0),
3784 payload_size: Unknown,
3785 fields: vec![Static(2), Static(6), Unknown]
3786 },
3787 Annotations {
3788 size: Static(8),
3789 parent_size: Static(8),
3790 payload_size: Static(0),
3791 fields: vec![Static(8)]
3792 },
3793 ])
3794 );
3795
3796 assert_that!(
3798 annotations(
3799 r#"
3800 little_endian_packets
3801 packet A {
3802 _size_(a) : 8,
3803 a: 8[],
3804 _size_(_payload_) : 8,
3805 _payload_
3806 }
3807 packet B : A {
3808 b: 8,
3809 }
3810 "#
3811 ),
3812 eq(vec![
3813 Annotations {
3814 size: Dynamic,
3815 parent_size: Static(0),
3816 payload_size: Dynamic,
3817 fields: vec![Static(8), Dynamic, Static(8), Dynamic]
3818 },
3819 Annotations {
3820 size: Static(8),
3821 parent_size: Dynamic,
3822 payload_size: Static(0),
3823 fields: vec![Static(8)]
3824 },
3825 ])
3826 );
3827
3828 assert_that!(
3830 annotations(
3831 r#"
3832 little_endian_packets
3833 packet A {
3834 _size_(_payload_) : 8,
3835 a: 8[],
3836 _payload_
3837 }
3838 packet B : A {
3839 b: 8,
3840 }
3841 "#
3842 ),
3843 eq(vec![
3844 Annotations {
3845 size: Unknown,
3846 parent_size: Static(0),
3847 payload_size: Dynamic,
3848 fields: vec![Static(8), Unknown, Dynamic]
3849 },
3850 Annotations {
3851 size: Static(8),
3852 parent_size: Unknown,
3853 payload_size: Static(0),
3854 fields: vec![Static(8)]
3855 },
3856 ])
3857 );
3858 }
3859
3860 fn desugar(text: &str) -> analyzer::File {
3861 let mut db = ast::SourceDatabase::new();
3862 let file = parse_inline(&mut db, "stdin", text.to_owned()).expect("parsing failure");
3863 analyzer::analyze(&file).expect("analyzer failure")
3864 }
3865
3866 #[test]
3867 fn test_inline_groups() {
3868 assert_eq!(
3869 desugar(
3870 r#"
3871 little_endian_packets
3872 enum E : 8 { X=0, Y=1 }
3873 group G {
3874 a: 8,
3875 b: E,
3876 }
3877 packet A {
3878 G { }
3879 }
3880 "#
3881 ),
3882 desugar(
3883 r#"
3884 little_endian_packets
3885 enum E : 8 { X=0, Y=1 }
3886 packet A {
3887 a: 8,
3888 b: E,
3889 }
3890 "#
3891 )
3892 );
3893
3894 assert_eq!(
3895 desugar(
3896 r#"
3897 little_endian_packets
3898 enum E : 8 { X=0, Y=1 }
3899 group G {
3900 a: 8,
3901 b: E,
3902 }
3903 packet A {
3904 G { a=1, b=X }
3905 }
3906 "#
3907 ),
3908 desugar(
3909 r#"
3910 little_endian_packets
3911 enum E : 8 { X=0, Y=1 }
3912 packet A {
3913 _fixed_ = 1: 8,
3914 _fixed_ = X: E,
3915 }
3916 "#
3917 )
3918 );
3919
3920 assert_eq!(
3921 desugar(
3922 r#"
3923 little_endian_packets
3924 enum E : 8 { X=0, Y=1 }
3925 group G1 {
3926 a: 8,
3927 }
3928 group G2 {
3929 G1 { a=1 },
3930 b: E,
3931 }
3932 packet A {
3933 G2 { b=X }
3934 }
3935 "#
3936 ),
3937 desugar(
3938 r#"
3939 little_endian_packets
3940 enum E : 8 { X=0, Y=1 }
3941 packet A {
3942 _fixed_ = 1: 8,
3943 _fixed_ = X: E,
3944 }
3945 "#
3946 )
3947 );
3948 }
3949}