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