pdl_compiler/
analyzer.rs

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