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