1use std::collections::{HashMap, HashSet};
10
11use crate::error::{Error, ErrorKind, Span};
12use crate::parser::dsl_to_hardware;
13use crate::types::*;
14
15pub fn validate(def: &DecoderDef) -> Result<ValidatedDef, Vec<Error>> {
26 let mut errors = Vec::new();
27
28 let sub_decoder_names: HashSet<String> =
30 def.sub_decoders.iter().map(|sd| sd.name.clone()).collect();
31
32 let instructions = convert_bit_ranges(def);
34
35 check_name_uniqueness(&instructions, &def.type_aliases, &mut errors);
37
38 resolve_types(
40 &instructions,
41 &def.type_aliases,
42 &sub_decoder_names,
43 &mut errors,
44 );
45
46 check_bit_coverage(&instructions, def.config.width, &mut errors);
48
49 if def.config.max_units.is_some() {
51 check_max_units(&instructions, &def.config, &mut errors);
52 }
53
54 check_pattern_conflicts(&instructions, &mut errors);
56
57 check_maps(&def.maps, &mut errors);
59
60 check_formats(&instructions, &def.maps, &mut errors);
62
63 let validated_sub_decoders = validate_sub_decoders(&def.sub_decoders, &mut errors);
65
66 check_sub_decoder_field_widths(
68 &instructions,
69 &def.sub_decoders,
70 &sub_decoder_names,
71 &mut errors,
72 );
73
74 if !errors.is_empty() {
75 return Err(errors);
76 }
77
78 let validated_instructions = instructions
80 .into_iter()
81 .map(|instr| {
82 let resolved_fields = instr
83 .segments
84 .iter()
85 .filter_map(|seg| {
86 if let Segment::Field {
87 name,
88 field_type,
89 ranges,
90 ..
91 } = seg
92 {
93 let resolved = resolve_field_type(
94 field_type,
95 &def.type_aliases,
96 &sub_decoder_names,
97 &def.sub_decoders,
98 );
99 Some(ResolvedField {
100 name: name.clone(),
101 ranges: ranges.clone(),
102 resolved_type: resolved,
103 })
104 } else {
105 None
106 }
107 })
108 .collect();
109
110 ValidatedInstruction {
111 name: instr.name.clone(),
112 segments: instr.segments.clone(),
113 resolved_fields,
114 format_lines: instr.format_lines.clone(),
115 span: instr.span.clone(),
116 }
117 })
118 .collect();
119
120 Ok(ValidatedDef {
121 config: def.config.clone(),
122 type_aliases: def.type_aliases.clone(),
123 maps: def.maps.clone(),
124 instructions: validated_instructions,
125 sub_decoders: validated_sub_decoders,
126 })
127}
128
129fn convert_bit_ranges(def: &DecoderDef) -> Vec<InstructionDef> {
132 let width = def.config.width;
133 let order = def.config.bit_order;
134
135 def.instructions
136 .iter()
137 .map(|instr| {
138 let segments = instr
139 .segments
140 .iter()
141 .map(|seg| match seg {
142 Segment::Fixed {
143 ranges,
144 pattern,
145 span,
146 } => {
147 let hw_ranges =
150 dsl_to_hardware(ranges[0].start, ranges[0].end, width, order);
151 Segment::Fixed {
152 ranges: hw_ranges,
153 pattern: pattern.clone(),
154 span: span.clone(),
155 }
156 }
157 Segment::Field {
158 name,
159 field_type,
160 ranges,
161 span,
162 } => {
163 let hw_ranges =
165 dsl_to_hardware(ranges[0].start, ranges[0].end, width, order);
166 Segment::Field {
167 name: name.clone(),
168 field_type: field_type.clone(),
169 ranges: hw_ranges,
170 span: span.clone(),
171 }
172 }
173 })
174 .collect();
175
176 InstructionDef {
177 name: instr.name.clone(),
178 segments,
179 format_lines: instr.format_lines.clone(),
180 span: instr.span.clone(),
181 }
182 })
183 .collect()
184}
185
186fn check_name_uniqueness(
187 instructions: &[InstructionDef],
188 type_aliases: &[TypeAlias],
189 errors: &mut Vec<Error>,
190) {
191 let mut seen_instructions: HashMap<&str, &Span> = HashMap::new();
192 for instr in instructions {
193 if let Some(prev_span) = seen_instructions.get(instr.name.as_str()) {
194 errors.push(
195 Error::new(
196 ErrorKind::DuplicateInstructionName(instr.name.clone()),
197 instr.span.clone(),
198 )
199 .with_help(format!("first defined at line {}", prev_span.line)),
200 );
201 } else {
202 seen_instructions.insert(&instr.name, &instr.span);
203 }
204 }
205
206 let mut seen_types: HashMap<&str, &Span> = HashMap::new();
207 for ta in type_aliases {
208 if let Some(prev_span) = seen_types.get(ta.name.as_str()) {
209 errors.push(
210 Error::new(
211 ErrorKind::DuplicateTypeAlias(ta.name.clone()),
212 ta.span.clone(),
213 )
214 .with_help(format!("first defined at line {}", prev_span.line)),
215 );
216 } else {
217 seen_types.insert(&ta.name, &ta.span);
218 }
219 }
220}
221
222fn resolve_types(
223 instructions: &[InstructionDef],
224 type_aliases: &[TypeAlias],
225 sub_decoder_names: &HashSet<String>,
226 errors: &mut Vec<Error>,
227) {
228 let alias_names: HashSet<&str> = type_aliases.iter().map(|ta| ta.name.as_str()).collect();
229
230 for instr in instructions {
231 for seg in &instr.segments {
232 if let Segment::Field {
233 field_type, span, ..
234 } = seg
235 {
236 if let FieldType::Alias(alias_name) = field_type {
237 if !alias_names.contains(alias_name.as_str())
238 && !is_builtin_type(alias_name)
239 && !sub_decoder_names.contains(alias_name)
240 {
241 errors.push(Error::new(
242 ErrorKind::UnresolvedType(alias_name.clone()),
243 span.clone(),
244 ));
245 }
246 }
247 }
248 }
249 }
250}
251
252fn check_bit_coverage(instructions: &[InstructionDef], width: u32, errors: &mut Vec<Error>) {
253 for instr in instructions {
254 let mut units_map: HashMap<u32, Vec<BitRange>> = HashMap::new();
256
257 for seg in &instr.segments {
258 match seg {
259 Segment::Fixed {
260 ranges,
261 pattern,
262 span,
263 ..
264 } => {
265 let total_width: u32 = ranges.iter().map(|r| r.width()).sum();
267 if pattern.len() as u32 != total_width {
268 errors.push(Error::new(
269 ErrorKind::PatternLengthMismatch {
270 instruction: instr.name.clone(),
271 expected: total_width,
272 got: pattern.len() as u32,
273 },
274 span.clone(),
275 ));
276 }
277 for range in ranges {
278 units_map.entry(range.unit).or_default().push(*range);
279 }
280 }
281 Segment::Field { ranges, .. } => {
282 for range in ranges {
283 units_map.entry(range.unit).or_default().push(*range);
284 }
285 }
286 };
287 }
288
289 if let Some(unit0_ranges) = units_map.get(&0) {
291 let mut covered = vec![false; width as usize];
292
293 for range in unit0_ranges {
294 for bit in range.end..=range.start {
295 let idx = bit as usize;
296 if covered[idx] {
297 errors.push(Error::new(
298 ErrorKind::OverlappingBits {
299 instruction: instr.name.clone(),
300 bit,
301 },
302 instr.span.clone(),
303 ));
304 }
305 covered[idx] = true;
306 }
307 }
308
309 let missing: Vec<u32> = covered
310 .iter()
311 .enumerate()
312 .filter(|&(_, c)| !c)
313 .map(|(i, _)| i as u32)
314 .collect();
315
316 if !missing.is_empty() {
317 errors.push(Error::new(
318 ErrorKind::BitCoverageGap {
319 instruction: instr.name.clone(),
320 missing_bits: missing,
321 },
322 instr.span.clone(),
323 ));
324 }
325 }
326
327 for (unit_idx, ranges) in &units_map {
329 if *unit_idx == 0 {
330 continue;
331 }
332
333 let mut covered = vec![false; width as usize];
334 for range in ranges {
335 for bit in range.end..=range.start {
336 let idx = bit as usize;
337 if covered[idx] {
338 errors.push(Error::new(
339 ErrorKind::OverlappingBits {
340 instruction: instr.name.clone(),
341 bit,
342 },
343 instr.span.clone(),
344 ));
345 }
346 covered[idx] = true;
347 }
348 }
349 }
350 }
351}
352
353fn check_max_units(
355 instructions: &[InstructionDef],
356 config: &DecoderConfig,
357 errors: &mut Vec<Error>,
358) {
359 let max_units = config
360 .max_units
361 .expect("check_max_units called without max_units configured");
362
363 for instr in instructions {
364 let max_unit = instr
366 .segments
367 .iter()
368 .flat_map(|seg| match seg {
369 Segment::Fixed { ranges, .. } | Segment::Field { ranges, .. } => ranges.iter(),
370 })
371 .map(|range| range.unit)
372 .max()
373 .unwrap_or(0);
374
375 let required_units = max_unit + 1;
376
377 if required_units > max_units {
378 errors.push(Error::new(
379 ErrorKind::ExceedsMaxUnits {
380 instruction: instr.name.clone(),
381 required: required_units,
382 max_units,
383 },
384 instr.span.clone(),
385 ).with_help(format!(
386 "set max_units = {} in the decoder block or remove max_units to allow any length",
387 required_units
388 )));
389 }
390 }
391}
392
393fn check_pattern_conflicts(instructions: &[InstructionDef], errors: &mut Vec<Error>) {
394 for i in 0..instructions.len() {
397 for j in (i + 1)..instructions.len() {
398 if patterns_conflict(&instructions[i], &instructions[j]) {
399 errors.push(Error::new(
400 ErrorKind::PatternConflict {
401 a: instructions[i].name.clone(),
402 b: instructions[j].name.clone(),
403 },
404 instructions[j].span.clone(),
405 ));
406 }
407 }
408 }
409}
410
411fn patterns_conflict(a: &InstructionDef, b: &InstructionDef) -> bool {
414 let a_fixed = fixed_bit_map(a);
415 let b_fixed = fixed_bit_map(b);
416
417 for (&bit, &a_val) in &a_fixed {
418 if let Some(&b_val) = b_fixed.get(&bit) {
419 if a_val != b_val {
420 return false;
421 }
422 }
423 }
424
425 if a_fixed.len() != b_fixed.len() {
426 return false;
427 }
428
429 true
430}
431
432fn fixed_bit_map(instr: &InstructionDef) -> HashMap<(u32, u32), Bit> {
433 let mut map = HashMap::new();
434 for seg in &instr.segments {
435 if let Segment::Fixed {
436 ranges, pattern, ..
437 } = seg
438 {
439 let mut bit_idx = 0;
440 for range in ranges {
441 for i in 0..range.width() as usize {
442 if bit_idx < pattern.len() {
443 let hw_bit = range.start - i as u32;
444 map.insert((range.unit, hw_bit), pattern[bit_idx]);
446 bit_idx += 1;
447 }
448 }
449 }
450 }
451 }
452 map
453}
454
455fn check_maps(maps: &[MapDef], errors: &mut Vec<Error>) {
456 let mut seen_names: HashMap<&str, &Span> = HashMap::new();
457
458 for map in maps {
459 if let Some(prev) = seen_names.get(map.name.as_str()) {
461 errors.push(
462 Error::new(
463 ErrorKind::DuplicateMapName(map.name.clone()),
464 map.span.clone(),
465 )
466 .with_help(format!("first defined at line {}", prev.line)),
467 );
468 } else {
469 seen_names.insert(&map.name, &map.span);
470 }
471
472 let mut seen_keys: Vec<&Vec<MapKey>> = Vec::new();
474 for entry in &map.entries {
475 if seen_keys.iter().any(|k| *k == &entry.keys) {
476 errors.push(Error::new(
477 ErrorKind::DuplicateMapEntry {
478 map: map.name.clone(),
479 },
480 entry.span.clone(),
481 ));
482 } else {
483 seen_keys.push(&entry.keys);
484 }
485 }
486
487 let mut seen_params: HashSet<&str> = HashSet::new();
489 for param in &map.params {
490 if !seen_params.insert(param.as_str()) {
491 errors.push(Error::new(
492 ErrorKind::InvalidFormatString(format!(
493 "duplicate parameter '{}' in map '{}'",
494 param, map.name
495 )),
496 map.span.clone(),
497 ));
498 }
499 }
500 }
501}
502
503fn check_formats(instructions: &[InstructionDef], maps: &[MapDef], errors: &mut Vec<Error>) {
504 let map_names: HashMap<&str, &MapDef> = maps.iter().map(|m| (m.name.as_str(), m)).collect();
505
506 for instr in instructions {
507 if instr.format_lines.is_empty() {
508 continue;
509 }
510
511 let field_names: HashSet<String> = instr
512 .segments
513 .iter()
514 .filter_map(|seg| {
515 if let Segment::Field { name, .. } = seg {
516 Some(name.clone())
517 } else {
518 None
519 }
520 })
521 .collect();
522
523 for (i, fl) in instr.format_lines.iter().enumerate() {
525 if i < instr.format_lines.len() - 1 && fl.guard.is_none() {
526 errors.push(Error::new(
527 ErrorKind::UnguardedNonLastFormatLine {
528 instruction: instr.name.clone(),
529 },
530 fl.span.clone(),
531 ));
532 }
533
534 if let Some(guard) = &fl.guard {
536 for cond in &guard.conditions {
537 check_guard_operand_field(
538 &cond.left,
539 &field_names,
540 &instr.name,
541 &fl.span,
542 errors,
543 );
544 check_guard_operand_field(
545 &cond.right,
546 &field_names,
547 &instr.name,
548 &fl.span,
549 errors,
550 );
551 }
552 }
553
554 for piece in &fl.pieces {
556 if let FormatPiece::FieldRef { expr, .. } = piece {
557 check_format_expr_fields(
558 expr,
559 &field_names,
560 &instr.name,
561 &fl.span,
562 &map_names,
563 errors,
564 );
565 }
566 }
567 }
568 }
569}
570
571fn check_guard_operand_field(
572 operand: &GuardOperand,
573 field_names: &HashSet<String>,
574 instr_name: &str,
575 span: &Span,
576 errors: &mut Vec<Error>,
577) {
578 match operand {
579 GuardOperand::Field(name) => {
580 if !field_names.contains(name.as_str()) {
581 errors.push(Error::new(
582 ErrorKind::UndefinedFieldInGuard {
583 instruction: instr_name.to_string(),
584 field: name.clone(),
585 },
586 span.clone(),
587 ));
588 }
589 }
590 GuardOperand::Expr { left, right, .. } => {
591 check_guard_operand_field(left, field_names, instr_name, span, errors);
592 check_guard_operand_field(right, field_names, instr_name, span, errors);
593 }
594 GuardOperand::Literal(_) => {}
595 }
596}
597
598fn check_format_expr_fields(
599 expr: &FormatExpr,
600 field_names: &HashSet<String>,
601 instr_name: &str,
602 span: &Span,
603 maps: &HashMap<&str, &MapDef>,
604 errors: &mut Vec<Error>,
605) {
606 match expr {
607 FormatExpr::Field(name) => {
608 if !field_names.contains(name.as_str()) {
609 errors.push(Error::new(
610 ErrorKind::UndefinedFieldInFormat {
611 instruction: instr_name.to_string(),
612 field: name.clone(),
613 },
614 span.clone(),
615 ));
616 }
617 }
618 FormatExpr::Ternary { field, .. } => {
619 if !field_names.contains(field.as_str()) {
620 errors.push(Error::new(
621 ErrorKind::UndefinedFieldInFormat {
622 instruction: instr_name.to_string(),
623 field: field.clone(),
624 },
625 span.clone(),
626 ));
627 }
628 }
629 FormatExpr::Arithmetic { left, right, .. } => {
630 check_format_expr_fields(left, field_names, instr_name, span, maps, errors);
631 check_format_expr_fields(right, field_names, instr_name, span, maps, errors);
632 }
633 FormatExpr::IntLiteral(_) => {}
634 FormatExpr::MapCall { map_name, args, .. } => {
635 if let Some(map_def) = maps.get(map_name.as_str()) {
636 if args.len() != map_def.params.len() {
637 errors.push(Error::new(
638 ErrorKind::MapArgCountMismatch {
639 map: map_name.clone(),
640 expected: map_def.params.len(),
641 got: args.len(),
642 },
643 span.clone(),
644 ));
645 }
646 } else {
647 errors.push(Error::new(
648 ErrorKind::UndefinedMap(map_name.clone()),
649 span.clone(),
650 ));
651 }
652 for arg in args {
653 check_format_expr_fields(arg, field_names, instr_name, span, maps, errors);
654 }
655 }
656 FormatExpr::BuiltinCall { args, .. } => {
657 for arg in args {
659 check_format_expr_fields(arg, field_names, instr_name, span, maps, errors);
660 }
661 }
662 FormatExpr::SubDecoderAccess { field, .. } => {
663 if !field_names.contains(field.as_str()) {
664 errors.push(Error::new(
665 ErrorKind::UndefinedFieldInFormat {
666 instruction: instr_name.to_string(),
667 field: field.clone(),
668 },
669 span.clone(),
670 ));
671 }
672 }
674 }
675}
676
677fn resolve_field_type(
678 field_type: &FieldType,
679 type_aliases: &[TypeAlias],
680 sub_decoder_names: &HashSet<String>,
681 sub_decoders: &[SubDecoderDef],
682) -> ResolvedFieldType {
683 match field_type {
684 FieldType::Alias(name) => {
685 if sub_decoder_names.contains(name) {
687 let sd = sub_decoders.iter().find(|sd| sd.name == *name).unwrap();
688 let base = match sd.width {
689 w if w <= 8 => "u8",
690 w if w <= 16 => "u16",
691 _ => "u32",
692 };
693 return ResolvedFieldType {
694 base_type: base.to_string(),
695 alias_name: None,
696 transforms: Vec::new(),
697 display_format: None,
698 sub_decoder: Some(name.clone()),
699 };
700 }
701 if let Some(alias) = type_aliases.iter().find(|ta| ta.name == *name) {
702 ResolvedFieldType {
703 base_type: alias.base_type.clone(),
704 alias_name: Some(name.clone()),
705 transforms: alias.transforms.clone(),
706 display_format: alias.display_format,
707 sub_decoder: None,
708 }
709 } else {
710 ResolvedFieldType {
712 base_type: resolve_builtin(name),
713 alias_name: None,
714 transforms: Vec::new(),
715 display_format: None,
716 sub_decoder: None,
717 }
718 }
719 }
720 FieldType::Inline {
721 base_type,
722 transforms,
723 } => ResolvedFieldType {
724 base_type: resolve_builtin(base_type),
725 alias_name: None,
726 transforms: transforms.clone(),
727 display_format: None,
728 sub_decoder: None,
729 },
730 }
731}
732
733fn is_builtin_type(name: &str) -> bool {
734 matches!(
735 name,
736 "u1" | "u2"
737 | "u3"
738 | "u4"
739 | "u5"
740 | "u6"
741 | "u7"
742 | "u8"
743 | "u16"
744 | "u32"
745 | "i8"
746 | "i16"
747 | "i32"
748 | "bool"
749 )
750}
751
752fn resolve_builtin(name: &str) -> String {
753 match name {
754 "u1" | "u2" | "u3" | "u4" | "u5" | "u6" | "u7" => "u8".to_string(),
755 other => other.to_string(),
756 }
757}
758
759fn validate_sub_decoders(
761 sub_decoders: &[SubDecoderDef],
762 errors: &mut Vec<Error>,
763) -> Vec<ValidatedSubDecoder> {
764 let mut validated = Vec::new();
765
766 for sd in sub_decoders {
767 let instructions: Vec<_> = sd
769 .instructions
770 .iter()
771 .map(|instr| {
772 let segments: Vec<Segment> = instr
773 .segments
774 .iter()
775 .map(|seg| match seg {
776 Segment::Fixed {
777 ranges,
778 pattern,
779 span,
780 } => {
781 let hw_ranges = crate::parser::dsl_to_hardware(
782 ranges[0].start,
783 ranges[0].end,
784 sd.width,
785 sd.bit_order,
786 );
787 Segment::Fixed {
788 ranges: hw_ranges,
789 pattern: pattern.clone(),
790 span: span.clone(),
791 }
792 }
793 Segment::Field {
794 name,
795 field_type,
796 ranges,
797 span,
798 } => {
799 let hw_ranges = crate::parser::dsl_to_hardware(
800 ranges[0].start,
801 ranges[0].end,
802 sd.width,
803 sd.bit_order,
804 );
805 Segment::Field {
806 name: name.clone(),
807 field_type: field_type.clone(),
808 ranges: hw_ranges,
809 span: span.clone(),
810 }
811 }
812 })
813 .collect();
814 (instr, segments)
815 })
816 .collect();
817
818 for (instr, segments) in &instructions {
820 let as_instr = InstructionDef {
821 name: instr.name.clone(),
822 segments: segments.clone(),
823 format_lines: Vec::new(),
824 span: instr.span.clone(),
825 };
826 check_bit_coverage(&[as_instr], sd.width, errors);
827 }
828
829 let mut fragment_names: Option<Vec<String>> = None;
831 for instr in &sd.instructions {
832 let names: Vec<String> = instr.fragments.iter().map(|f| f.name.clone()).collect();
833 if let Some(ref expected) = fragment_names {
834 if &names != expected {
835 errors.push(Error::new(
836 ErrorKind::InconsistentFragmentNames {
837 subdecoder: sd.name.clone(),
838 instruction: instr.name.clone(),
839 expected: expected.clone(),
840 got: names,
841 },
842 instr.span.clone(),
843 ));
844 }
845 } else {
846 fragment_names = Some(names);
847 }
848 }
849
850 let fragment_names = fragment_names.unwrap_or_default();
851
852 check_maps(&sd.maps, errors);
854
855 let validated_instructions = instructions
857 .into_iter()
858 .map(|(instr, segments)| {
859 let resolved_fields = segments
860 .iter()
861 .filter_map(|seg| {
862 if let Segment::Field {
863 name,
864 field_type,
865 ranges,
866 ..
867 } = seg
868 {
869 let resolved =
870 resolve_field_type(&field_type, &[], &HashSet::new(), &[]);
871 Some(ResolvedField {
872 name: name.clone(),
873 ranges: ranges.clone(),
874 resolved_type: resolved,
875 })
876 } else {
877 None
878 }
879 })
880 .collect();
881
882 ValidatedSubInstruction {
883 name: instr.name.clone(),
884 segments,
885 resolved_fields,
886 fragments: instr.fragments.clone(),
887 span: instr.span.clone(),
888 }
889 })
890 .collect();
891
892 validated.push(ValidatedSubDecoder {
893 name: sd.name.clone(),
894 width: sd.width,
895 bit_order: sd.bit_order,
896 fragment_names,
897 maps: sd.maps.clone(),
898 instructions: validated_instructions,
899 });
900 }
901
902 validated
903}
904
905fn check_sub_decoder_field_widths(
907 instructions: &[InstructionDef],
908 sub_decoders: &[SubDecoderDef],
909 sub_decoder_names: &HashSet<String>,
910 errors: &mut Vec<Error>,
911) {
912 for instr in instructions {
913 for seg in &instr.segments {
914 if let Segment::Field {
915 name,
916 field_type,
917 ranges,
918 span,
919 } = seg
920 {
921 if let FieldType::Alias(alias_name) = field_type {
922 if sub_decoder_names.contains(alias_name) {
923 let sd = sub_decoders
924 .iter()
925 .find(|sd| sd.name == *alias_name)
926 .unwrap();
927 let field_width: u32 = ranges.iter().map(|r| r.width()).sum();
928 if field_width > sd.width {
929 errors.push(Error::new(
930 ErrorKind::SubDecoderFieldTooWide {
931 field: name.clone(),
932 field_width,
933 subdecoder: alias_name.clone(),
934 subdecoder_width: sd.width,
935 },
936 span.clone(),
937 ));
938 }
939 }
940 }
941 }
942 }
943 }
944}