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