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