1use super::{CodecTarget, Constant, Handle, Handoff, Routine, Scalar};
43use crate::adapter::ada83::{ada83_map_entry_name, component_name};
44use crate::default_common::resolve_alias;
45use crate::encode::EncodeError;
46use zerodds_ast::{Ast, MemberNode, PrimitiveKind, TypeKind, TypeNode};
47use zerodds_ast_core::Id;
48use zerodds_lang_cst::ada83;
49use zerodds_lang_cst::common::{Doc, Ident, Literal, Path};
50
51#[derive(Debug, Clone, Copy, PartialEq, Eq)]
53pub struct Ada83;
54
55const RUNTIME: &str = "Zd_Wire83";
57
58const SIGNED_CHAR: &str = "signed char";
62
63const OWN_SAMPLE: &str = "Zd83_Sample";
66
67const OWN_ARRAY: &str = "Zd83_Own_Array";
70
71const RECEIVERLESS: &[&str] = &["bitfield", "trim_utf8", "trim_utf16"];
88
89#[derive(Debug, Clone, PartialEq, Eq)]
91pub struct AdaType {
92 pub mark: String,
94 pub is_bool: bool,
97 pub is_union: bool,
100 pub own_array: Option<String>,
103 pub counts: bool,
114}
115
116impl AdaType {
117 fn bare(mark: &str) -> Self {
118 Self {
119 mark: mark.to_string(),
120 is_bool: false,
121 is_union: false,
122 own_array: None,
123 counts: false,
124 }
125 }
126}
127
128#[derive(Debug, Clone)]
133pub enum AExpr {
134 Plain(ada83::Expr),
136 OptionalSlot(ada83::Expr),
138 Discriminant(ada83::Expr),
140 RuntimeEnum(ada83::Expr),
155 ReferenceSlot {
160 place: ada83::Expr,
162 mark: Path,
164 },
165 Assignment {
167 place: Box<AExpr>,
169 value: ada83::Expr,
171 },
172}
173
174fn inner(expr: AExpr) -> ada83::Expr {
179 match expr {
180 AExpr::Plain(e)
181 | AExpr::OptionalSlot(e)
182 | AExpr::Discriminant(e)
183 | AExpr::RuntimeEnum(e) => e,
184 AExpr::ReferenceSlot { place, .. } => place,
185 AExpr::Assignment { place, value } => ada83::Expr::Binary {
186 op: "=",
187 lhs: Box::new(inner(*place)),
188 rhs: Box::new(value),
189 },
190 }
191}
192
193fn plain(e: ada83::Expr) -> AExpr {
194 AExpr::Plain(e)
195}
196
197fn pattern_literal(value: i128) -> ada83::Expr {
217 const WIDTH: i128 = 1 << 64;
219 if value > i128::from(i64::MAX) && value <= i128::from(u64::MAX) {
220 return ada83::Expr::int(value - WIDTH);
221 }
222 ada83::Expr::int(value)
223}
224
225const fn bitwise_binary(op: &str) -> Option<&'static str> {
243 match op.as_bytes() {
244 b"&" => Some("Bits_And"),
245 b"|" => Some("Bits_Or"),
246 b"^" => Some("Bits_Xor"),
247 b">>" => Some("Shift_Right"),
248 b"<<" => Some("Shift_Left"),
249 _ => None,
250 }
251}
252
253fn mark_path(mark: &str) -> Path {
254 Path::new(&mark.split('.').collect::<Vec<&str>>())
255}
256
257impl Ada83 {
258 fn runtime_path(name: &str) -> Path {
259 Path::new(&[RUNTIME, name])
260 }
261
262 fn runtime_constant(name: &str) -> AExpr {
268 AExpr::RuntimeEnum(ada83::Expr::Name(Self::runtime_path(name)))
269 }
270
271 fn operation(method: &str) -> String {
272 ada83::ada_case(method)
273 }
274
275 fn selected(value: ada83::Expr, name: &str) -> ada83::Expr {
276 ada83::Expr::Selected {
277 value: Box::new(value),
278 name: Ident::new(name),
279 }
280 }
281
282 fn call_path(path: Path, args: Vec<ada83::Expr>) -> ada83::Expr {
283 ada83::Expr::Call { name: path, args }
284 }
285
286 fn narrow_integer(method: &str, arguments: &[ada83::Expr]) -> Option<ada83::Expr> {
303 let (width, signed) = match method {
304 "write_i8" | "read_i8" => (1, true),
305 "write_u8" | "read_u8" => (1, false),
306 "write_i16" | "read_i16" => (2, true),
307 "write_u16" | "read_u16" => (2, false),
308 "write_i32" | "read_i32" => (4, true),
309 "write_u32" | "read_u32" => (4, false),
310 _ => return None,
311 };
312 let bits = width * 8;
316 let (low, high) = if signed {
317 (-(1_i64 << (bits - 1)), (1_i64 << (bits - 1)) - 1)
318 } else {
319 (0, (1_i64 << bits) - 1)
320 };
321 let number = |value: i64| ada83::Expr::int(i128::from(value));
322
323 if method.starts_with("read_") {
324 let name = if signed { "Read_Int" } else { "Read_Uint" };
325 let mut args = arguments.to_vec();
326 args.push(number(width));
327 return Some(Self::call_path(Self::runtime_path(name), args));
328 }
329 let mut args = arguments.to_vec();
330 args.push(number(width));
331 args.push(number(low));
332 args.push(number(high));
333 Some(Self::call_path(Self::runtime_path("Write_Int"), args))
334 }
335
336 fn to_natural(value: ada83::Expr) -> ada83::Expr {
338 ada83::Expr::Convert {
339 mark: Path::single("Natural"),
340 value: Box::new(value),
341 }
342 }
343
344 fn engaged(value: ada83::Expr) -> ada83::Expr {
346 ada83::Expr::Aggregate(vec![
347 ada83::Association {
348 choice: Ident::new(crate::adapter::ada83::PRESENT),
349 value: ada83::Expr::Literal(Literal::Bool(true)),
350 },
351 ada83::Association {
352 choice: Ident::new(crate::adapter::ada83::VALUE),
353 value,
354 },
355 ])
356 }
357
358 fn discriminant_record(place: ada83::Expr) -> ada83::Expr {
359 match place {
360 ada83::Expr::Selected { value, .. } => *value,
361 other => other,
362 }
363 }
364
365 fn assign_discriminant(place: ada83::Expr, value: ada83::Expr) -> ada83::Stmt {
368 ada83::Stmt::Declare {
369 vars: vec![ada83::VarDecl {
370 name: Ident::new("zd_nd"),
371 mark: Path::single(OWN_SAMPLE),
372 constraint: Some(value),
373 value: None,
374 }],
375 body: vec![ada83::Stmt::Assign {
376 place: Self::discriminant_record(place),
377 value: ada83::Expr::name("zd_nd"),
378 }],
379 }
380 }
381}
382
383impl CodecTarget for Ada83 {
384 type Expr = AExpr;
385 type Stmt = ada83::Stmt;
386 type Block = Vec<ada83::Stmt>;
387 type Type = AdaType;
388 type Decl = ada83::Decl;
389
390 fn scalar(kind: Scalar) -> Self::Type {
406 match kind {
407 Scalar::Bool => AdaType {
408 is_bool: true,
409 ..AdaType::bare("Boolean")
410 },
411 Scalar::Float => AdaType::bare("Float"),
412 Scalar::Double => AdaType::bare("Long_Float"),
413 Scalar::LongDouble => AdaType::bare("Zd_Wire83.Text"),
415 Scalar::Index | Scalar::Size => AdaType::bare("Natural"),
416 Scalar::UInt32 => AdaType {
421 counts: true,
422 ..AdaType::bare("Long_Integer")
423 },
424 _ => AdaType::bare("Long_Integer"),
425 }
426 }
427
428 fn named(name: &str) -> Self::Type {
429 AdaType::bare(name)
430 }
431
432 fn nothing() -> Self::Type {
433 AdaType::bare("Zd83_No_Type")
434 }
435
436 fn handle(kind: Handle) -> Self::Type {
437 AdaType::bare(match kind {
438 Handle::DHeader => "Zd_Wire83.Dheader",
439 Handle::EmHeader => "Zd_Wire83.Emheader",
440 Handle::Pid => "Zd_Wire83.Pid_Write",
441 Handle::TryConstruct => "Zd_Wire83.Try_Construct",
442 Handle::ReaderMark => "Zd_Wire83.Reader_Mark",
443 Handle::PidRead => "Zd_Wire83.Pid_Read",
444 Handle::EmHeaderRead => "Zd_Wire83.Emheader_Read",
445 })
446 }
447
448 fn code_point(value: Self::Expr, _narrow: bool) -> Self::Expr {
453 value
454 }
455
456 fn constant(which: Constant) -> Self::Expr {
457 match which {
458 Constant::WcharWidth2 => plain(ada83::Expr::int(2)),
459 Constant::WcharWidth4 => plain(ada83::Expr::int(4)),
460 Constant::WcharFixed => Self::runtime_constant("Wchar_Fixed"),
461 Constant::WcharGiopLengthPrefixed => {
462 Self::runtime_constant("Wchar_Giop_Length_Prefixed")
463 }
464 Constant::WstringUnitsStream => Self::runtime_constant("Unit_Stream"),
465 Constant::WstringUnitsBigEndianAlways => {
466 Self::runtime_constant("Unit_Big_Endian_Always")
467 }
468 Constant::WstringUnitsByteOrderMark => Self::runtime_constant("Unit_Byte_Order_Mark"),
469 Constant::WstringUnitsHostUnswapped => Self::runtime_constant("Unit_Host_Unswapped"),
470 Constant::WstringSpecification => Self::runtime_constant("Wstr_Octets_Unterminated_2"),
471 Constant::WstringCharacterCount => {
472 Self::runtime_constant("Wstr_Characters_Unterminated_2")
473 }
474 Constant::WstringCharacterCountTerminated => {
475 Self::runtime_constant("Wstr_Characters_Terminated_4")
476 }
477 Constant::WstringSpecificationWideUnits => {
478 Self::runtime_constant("Wstr_Octets_Unterminated_4")
479 }
480 Constant::WstringRosTypeSupport => {
481 Self::runtime_constant("Wstr_Characters_Unterminated_4")
482 }
483 Constant::WstringOctetsTerminated2 => {
484 Self::runtime_constant("Wstr_Octets_Terminated_2")
485 }
486 Constant::WstringOctetsTerminated4 => {
487 Self::runtime_constant("Wstr_Octets_Terminated_4")
488 }
489 Constant::WstringCharactersTerminated2 => {
490 Self::runtime_constant("Wstr_Characters_Terminated_2")
491 }
492 Constant::FixedDeclared => Self::runtime_constant("Fixed_Declared"),
493 Constant::FixedValuePrecision => Self::runtime_constant("Fixed_Value_Precision"),
494 Constant::FixedValueStringDigits => Self::runtime_constant("Fixed_Value_String_Digits"),
495 Constant::ParameterMember => Self::runtime_constant("Role_Member"),
496 Constant::ParameterOptional => Self::runtime_constant("Role_Optional"),
497 Constant::TryConstructDiscard => Self::runtime_constant("Tc_Discard"),
498 Constant::TryConstructTrim => Self::runtime_constant("Tc_Trim"),
499 Constant::TryConstructUseDefault => Self::runtime_constant("Tc_Use_Default"),
500 Constant::StatusOk => Self::runtime_constant("Status_Ok"),
501 Constant::StatusDiscarded => Self::runtime_constant("Status_Discarded"),
502 Constant::StatusImpossibleLength => Self::runtime_constant("Status_Impossible_Length"),
503 Constant::StatusOutOfRange => Self::runtime_constant("Status_Out_Of_Range"),
504 Constant::StatusTruncated => Self::runtime_constant("Status_Truncated"),
505 }
506 }
507
508 fn unsigned_holder(_bits: u16) -> Self::Type {
512 AdaType::bare("Long_Integer")
513 }
514
515 fn carries_hdds_axes() -> bool {
521 true
522 }
523
524 fn value_type(ast: &Ast, id: Id<TypeNode>) -> Self::Type {
525 let mark = match crate::adapter::ada83::ada83_value_path(ast, id) {
526 Ok(path) => path
527 .segments()
528 .iter()
529 .map(Ident::as_str)
530 .collect::<Vec<&str>>()
531 .join("."),
532 Err(_) => "Zd83_No_Ada_Form".to_string(),
533 };
534 let resolved = resolve_alias(ast, id);
535 let kind = ast.type_(resolved).map(|node| node.kind.clone());
536 AdaType {
537 mark,
538 is_bool: matches!(kind, Ok(TypeKind::Primitive(PrimitiveKind::Boolean))),
539 is_union: matches!(kind, Ok(TypeKind::Union { .. })),
540 own_array: match kind {
541 Ok(TypeKind::Sequence { .. } | TypeKind::Map { .. }) => Some(format!(
542 "{}_Array",
543 crate::adapter::ada83::ada83_type_name(ast, resolved)
544 )),
545 _ => None,
546 },
547 counts: false,
549 }
550 }
551
552 fn type_name(ast: &Ast, id: Id<TypeNode>) -> String {
553 crate::adapter::ada83::type_tag(ast, id)
554 }
555
556 fn map_entry_name(ast: &Ast, id: Id<TypeNode>) -> String {
557 ada83_map_entry_name(ast, id)
558 }
559
560 fn module_prefix(_ast: &Ast, _id: Id<TypeNode>) -> String {
562 String::new()
563 }
564
565 fn escape(name: &str) -> String {
566 component_name(name)
567 }
568
569 fn inherited_path(depth: usize) -> Option<String> {
571 Some(format!("{}.", component_name("parent")).repeat(depth))
572 }
573
574 fn name(text: &str) -> Self::Expr {
577 plain(ada83::Expr::name(local_name(text)))
578 }
579
580 fn int(value: i128) -> Self::Expr {
581 plain(ada83::Expr::int(value))
582 }
583
584 fn literal(value: Literal) -> Self::Expr {
585 let Literal::Int(text) = &value else {
586 return plain(ada83::Expr::Literal(value));
587 };
588 match text.as_str() {
589 "true" => plain(ada83::Expr::Literal(Literal::Bool(true))),
590 "false" => plain(ada83::Expr::Literal(Literal::Bool(false))),
591 _ => plain(ada83::Expr::Literal(value)),
592 }
593 }
594
595 fn wide_int(value: i128) -> Self::Expr {
599 plain(pattern_literal(value))
600 }
601
602 fn unsigned_int(value: i128) -> Self::Expr {
603 plain(pattern_literal(value))
604 }
605
606 fn wide_unsigned(value: u64) -> Self::Expr {
607 plain(pattern_literal(i128::from(value)))
608 }
609
610 fn wide_signed(value: i128) -> Self::Expr {
611 plain(pattern_literal(value))
612 }
613
614 fn member(base: &str, field: &str) -> Self::Expr {
615 if field == "_d" {
616 return AExpr::Discriminant(Self::selected(
617 ada83::Expr::name(local_name(base)),
618 crate::adapter::ada83::DISCRIMINANT,
619 ));
620 }
621 plain(Self::selected(ada83::Expr::name(local_name(base)), field))
622 }
623
624 fn whole(base: &str) -> Self::Expr {
625 plain(ada83::Expr::name(local_name(base)))
626 }
627
628 fn field_of(value: Self::Expr, field: &str) -> Self::Expr {
629 plain(Self::selected(inner(value), field))
630 }
631
632 fn header_field(value: Self::Expr, field: &str) -> Self::Expr {
635 let name = if field == "end" {
636 "End_Flag".to_string()
637 } else {
638 ada83::ada_case(field)
639 };
640 plain(Self::selected(inner(value), &name))
641 }
642
643 fn index(value: Self::Expr, at: Self::Expr) -> Self::Expr {
644 plain(ada83::Expr::Indexed {
645 value: Box::new(inner(value)),
646 index: Box::new(inner(at)),
647 })
648 }
649
650 fn count_of(base: &str, fixed: Option<u64>) -> Self::Expr {
653 match fixed {
654 Some(bound) => plain(ada83::Expr::int(i128::from(bound))),
655 None => plain(ada83::Expr::Convert {
656 mark: mark_path("Long_Integer"),
657 value: Box::new(ada83::Expr::Attribute {
658 value: Box::new(ada83::Expr::Deref(Box::new(ada83::Expr::name(local_name(
659 base,
660 ))))),
661 name: Ident::new("Length"),
662 args: Vec::new(),
663 }),
664 }),
665 }
666 }
667
668 fn elements(base: &str) -> Self::Expr {
669 plain(ada83::Expr::name(local_name(base)))
670 }
671
672 fn case_member(base: &str, field: &str) -> Self::Expr {
673 Self::member(base, field)
674 }
675
676 fn entry_half(entry: Self::Expr, key: bool) -> Self::Expr {
677 plain(Self::selected(
678 inner(entry),
679 if key {
680 "Key"
681 } else {
682 crate::adapter::ada83::VALUE
683 },
684 ))
685 }
686
687 fn absent() -> Self::Expr {
688 plain(ada83::Expr::Literal(Literal::Null))
689 }
690
691 fn materialised(_value: Self::Expr) -> Option<Self::Expr> {
695 None
696 }
697
698 fn optional_value(_ast: &Ast, _id: Id<TypeNode>, base: &str, field: &str) -> Self::Expr {
699 plain(Self::selected(
700 inner(Self::member(base, field)),
701 crate::adapter::ada83::VALUE,
702 ))
703 }
704
705 fn present(base: &str, field: &str) -> Self::Expr {
706 plain(Self::selected(
707 inner(Self::member(base, field)),
708 crate::adapter::ada83::PRESENT,
709 ))
710 }
711
712 fn holds_by_reference(
714 ast: &Ast,
715 aggregate: Id<TypeNode>,
716 member_type: Id<TypeNode>,
717 optional: bool,
718 external: bool,
719 ) -> bool {
720 crate::adapter::ada83::held_by_reference(ast, aggregate, member_type, optional, external)
721 }
722
723 fn reference_present(base: &str, field: &str) -> Self::Expr {
725 Self::binary(
726 "!=",
727 Self::member(base, field),
728 plain(ada83::Expr::Literal(Literal::Null)),
729 )
730 }
731
732 fn reference_value(_ast: &Ast, _id: Id<TypeNode>, base: &str, field: &str) -> Self::Expr {
734 plain(ada83::Expr::Deref(Box::new(inner(Self::member(
735 base, field,
736 )))))
737 }
738
739 fn reference_destination(
742 ast: &Ast,
743 id: Id<TypeNode>,
744 base: &str,
745 field: &str,
746 ) -> (Vec<Self::Stmt>, Self::Expr) {
747 let designated = crate::adapter::ada83::reference_designated(ast, id).unwrap_or(id);
748 (
749 Vec::new(),
750 AExpr::ReferenceSlot {
751 place: inner(Self::member(base, field)),
752 mark: Path::single(&crate::adapter::ada83::ada83_type_name(ast, designated)),
753 },
754 )
755 }
756
757 fn reference_absent(base: &str, field: &str) -> Vec<Self::Stmt> {
759 vec![ada83::Stmt::Assign {
760 place: inner(Self::member(base, field)),
761 value: ada83::Expr::Literal(Literal::Null),
762 }]
763 }
764
765 fn set_present(base: &str, field: &str, present: bool) -> Vec<Self::Stmt> {
766 if present {
767 return Vec::new();
768 }
769 vec![ada83::Stmt::Assign {
770 place: inner(Self::member(base, field)),
771 value: ada83::Expr::Aggregate(vec![ada83::Association {
772 choice: Ident::new(crate::adapter::ada83::PRESENT),
773 value: ada83::Expr::Literal(Literal::Bool(false)),
774 }]),
775 }]
776 }
777
778 fn optional_destination(base: &str, field: &str) -> (Vec<Self::Stmt>, Self::Expr) {
779 (
780 Vec::new(),
781 AExpr::OptionalSlot(inner(Self::member(base, field))),
782 )
783 }
784
785 fn binary(op: &'static str, lhs: Self::Expr, rhs: Self::Expr) -> Self::Expr {
789 if op == "=" {
790 return AExpr::Assignment {
791 place: Box::new(lhs),
792 value: inner(rhs),
793 };
794 }
795 if (op == "==" || op == "!=")
796 && (matches!(lhs, AExpr::RuntimeEnum(_)) || matches!(rhs, AExpr::RuntimeEnum(_)))
797 {
798 let call =
809 Self::call_path(Path::new(&[RUNTIME, "\"=\""]), vec![inner(lhs), inner(rhs)]);
810 if op == "!=" {
811 return plain(ada83::Expr::Unary {
812 op: "not",
813 value: Box::new(call),
814 });
815 }
816 return plain(call);
817 }
818 if let Some(name) = bitwise_binary(op) {
819 let rhs = if op == ">>" || op == "<<" {
820 Self::to_natural(inner(rhs))
821 } else {
822 inner(rhs)
823 };
824 return plain(Self::call_path(
825 Self::runtime_path(name),
826 vec![inner(lhs), rhs],
827 ));
828 }
829 plain(ada83::Expr::Binary {
830 op,
831 lhs: Box::new(inner(lhs)),
832 rhs: Box::new(inner(rhs)),
833 })
834 }
835
836 fn unary(op: &'static str, value: Self::Expr) -> Self::Expr {
848 if op == "~" {
849 return plain(Self::call_path(
850 Self::runtime_path("Bits_Not"),
851 vec![inner(value)],
852 ));
853 }
854 plain(ada83::Expr::Unary {
855 op,
856 value: Box::new(inner(value)),
857 })
858 }
859
860 fn paren(value: Self::Expr) -> Self::Expr {
861 value
862 }
863
864 fn cast(type_: Self::Type, value: Self::Expr) -> Self::Expr {
870 if type_.mark == SIGNED_CHAR {
871 return plain(Self::call_path(
872 Self::runtime_path("As_Signed"),
873 vec![inner(value)],
874 ));
875 }
876 if type_.is_bool {
877 if let AExpr::Plain(ada83::Expr::Literal(Literal::Int(text))) = &value {
878 return plain(ada83::Expr::Literal(Literal::Bool(text != "0")));
879 }
880 }
881 plain(ada83::Expr::Convert {
882 mark: mark_path(&type_.mark),
883 value: Box::new(inner(value)),
884 })
885 }
886
887 fn handoff(value: Self::Expr, _form: Handoff) -> Self::Expr {
888 value
889 }
890
891 fn call(callee: &str, args: Vec<Self::Expr>) -> Self::Expr {
892 let arguments: Vec<ada83::Expr> = args.into_iter().map(inner).collect();
893 if callee == "strcmp" {
894 return plain(Self::call_path(Self::runtime_path("Strcmp"), arguments));
895 }
896 plain(Self::call_path(Path::single(callee), arguments))
897 }
898
899 fn runtime(receiver: &str, method: &str, args: Vec<Self::Expr>) -> Self::Expr {
900 let mut arguments: Vec<ada83::Expr> = if RECEIVERLESS.contains(&method) {
901 Vec::new()
902 } else {
903 vec![ada83::Expr::name(receiver)]
904 };
905 arguments.extend(args.into_iter().map(inner));
906 if let Some(call) = Self::narrow_integer(method, &arguments) {
907 return plain(call);
908 }
909 plain(Self::call_path(
910 Self::runtime_path(&Self::operation(method)),
911 arguments,
912 ))
913 }
914
915 fn runtime_static(method: &str, args: Vec<Self::Expr>) -> Self::Expr {
916 plain(Self::call_path(
917 Self::runtime_path(&Self::operation(method)),
918 args.into_iter().map(inner).collect(),
919 ))
920 }
921
922 fn unsigned_less(octets: u8, left: Self::Expr, right: Self::Expr) -> Self::Expr {
945 if octets < 8 {
946 return Self::binary("<", left, right);
947 }
948 Self::runtime_static("u64_less", vec![left, right])
949 }
950
951 fn bit_pattern(source: super::BitPatternSource, value: Self::Expr) -> Self::Expr {
958 match source {
959 super::BitPatternSource::Int { octets } => Self::runtime_static(
960 "bit_pattern_int",
961 vec![value, Self::int(i128::from(octets))],
962 ),
963 super::BitPatternSource::Bool => Self::runtime_static("bit_pattern_bool", vec![value]),
964 super::BitPatternSource::Float32 => {
965 Self::runtime_static("bit_pattern_f32", vec![value])
966 }
967 super::BitPatternSource::Float64 => {
968 Self::runtime_static("bit_pattern_f64_overlay", vec![value])
969 }
970 }
971 }
972
973 fn declare(type_: Self::Type, name: &str, value: Option<Self::Expr>) -> Self::Stmt {
988 let counts = type_.counts
989 && type_.mark == "Long_Integer"
990 && matches!(
991 &value,
992 Some(AExpr::Plain(ada83::Expr::Literal(Literal::Int(_))))
993 );
994 ada83::Stmt::Var(ada83::VarDecl {
995 name: Ident::new(local_name(name)),
996 mark: mark_path(if counts { "Natural" } else { &type_.mark }),
997 constraint: None,
998 value: value.map(inner),
999 })
1000 }
1001
1002 fn perform(value: Self::Expr) -> Self::Stmt {
1003 match value {
1004 AExpr::Assignment { place, value } => match *place {
1005 AExpr::OptionalSlot(field) => ada83::Stmt::Assign {
1006 place: field,
1007 value: Self::engaged(value),
1008 },
1009 AExpr::Discriminant(field) => Self::assign_discriminant(field, value),
1010 other => ada83::Stmt::Assign {
1011 place: inner(other),
1012 value,
1013 },
1014 },
1015 other => ada83::Stmt::Call(inner(other)),
1016 }
1017 }
1018
1019 fn give_back(value: Option<Self::Expr>) -> Self::Stmt {
1020 ada83::Stmt::Return(Some(match value {
1021 Some(value) => inner(value),
1022 None => ada83::Expr::name("v"),
1023 }))
1024 }
1025
1026 fn when(
1027 condition: Self::Expr,
1028 then: Self::Block,
1029 otherwise: Option<Self::Block>,
1030 ) -> Self::Stmt {
1031 ada83::Stmt::If {
1032 condition: inner(condition),
1033 then,
1034 otherwise: otherwise.filter(|body| !body.is_empty()),
1035 }
1036 }
1037
1038 fn count_up(counter: &str, bound: Self::Expr, body: Self::Block) -> Self::Stmt {
1039 ada83::Stmt::For {
1040 counter: Ident::new(local_name(counter)),
1041 low: ada83::Expr::int(0),
1042 high: ada83::Expr::Binary {
1043 op: "-",
1044 lhs: Box::new(Self::to_natural(inner(bound))),
1045 rhs: Box::new(ada83::Expr::int(1)),
1046 },
1047 body,
1048 }
1049 }
1050
1051 fn until(condition: Self::Expr, body: Self::Block) -> Self::Stmt {
1052 ada83::Stmt::While {
1053 condition: inner(condition),
1054 body,
1055 }
1056 }
1057
1058 fn leave() -> Self::Stmt {
1059 ada83::Stmt::Exit
1060 }
1061
1062 fn note(doc: Doc) -> Self::Stmt {
1063 ada83::Stmt::Comment(doc)
1064 }
1065
1066 fn drop_value(value: Self::Expr) -> Self::Stmt {
1070 ada83::Stmt::Call(Self::call_path(
1071 Self::runtime_path("Discard"),
1072 vec![inner(value)],
1073 ))
1074 }
1075
1076 fn mark_used(_name: &str) -> Vec<Self::Stmt> {
1080 Vec::new()
1081 }
1082
1083 fn read_call(
1084 callee: &str,
1085 place: Self::Expr,
1086 _form: Handoff,
1087 behaviour: Self::Expr,
1088 ) -> Self::Stmt {
1089 let decoded = Self::call_path(
1090 Path::single(callee),
1091 vec![ada83::Expr::name("r"), inner(behaviour)],
1092 );
1093 match place {
1094 AExpr::OptionalSlot(field) => ada83::Stmt::Assign {
1095 place: field,
1096 value: Self::engaged(decoded),
1097 },
1098 AExpr::Discriminant(field) => Self::assign_discriminant(field, decoded),
1099 AExpr::ReferenceSlot { place, mark } => ada83::Stmt::Assign {
1102 place,
1103 value: ada83::Expr::New {
1104 mark,
1105 init: ada83::AllocInit::Qualified(Box::new(decoded)),
1106 },
1107 },
1108 other => ada83::Stmt::Assign {
1109 place: inner(other),
1110 value: decoded,
1111 },
1112 }
1113 }
1114
1115 fn read_forward(callee: &str) -> Self::Stmt {
1116 ada83::Stmt::Assign {
1117 place: ada83::Expr::name("v"),
1118 value: Self::call_path(
1119 Path::single(callee),
1120 vec![ada83::Expr::name("r"), ada83::Expr::name("zd_tc")],
1121 ),
1122 }
1123 }
1124
1125 fn block(statements: Vec<Self::Stmt>) -> Self::Block {
1126 statements
1127 }
1128
1129 fn into_statements(block: Self::Block) -> Vec<Self::Stmt> {
1130 block
1131 }
1132
1133 fn make_room(
1134 base: &str,
1135 _element: Self::Type,
1136 count: Self::Expr,
1137 _assigned_whole: bool,
1138 fill: Vec<Self::Stmt>,
1139 ) -> Vec<Self::Stmt> {
1140 let mut out = vec![ada83::Stmt::Assign {
1141 place: ada83::Expr::name(local_name(base)),
1142 value: ada83::Expr::New {
1143 mark: Path::single(OWN_ARRAY),
1144 init: ada83::AllocInit::Range {
1145 low: Box::new(ada83::Expr::int(0)),
1146 high: Box::new(ada83::Expr::Binary {
1147 op: "-",
1148 lhs: Box::new(Self::to_natural(inner(count))),
1149 rhs: Box::new(ada83::Expr::int(1)),
1150 }),
1151 },
1152 },
1153 }];
1154 out.extend(fill);
1155 out
1156 }
1157
1158 fn keep_first(base: &str, count: Self::Expr) -> Vec<Self::Stmt> {
1159 vec![ada83::Stmt::Assign {
1160 place: ada83::Expr::name(local_name(base)),
1161 value: ada83::Expr::New {
1162 mark: Path::single(OWN_ARRAY),
1163 init: ada83::AllocInit::Qualified(Box::new(ada83::Expr::Slice {
1164 value: Box::new(ada83::Expr::Deref(Box::new(ada83::Expr::name(local_name(
1165 base,
1166 ))))),
1167 low: Box::new(ada83::Expr::int(0)),
1168 high: Box::new(ada83::Expr::Binary {
1169 op: "-",
1170 lhs: Box::new(Self::to_natural(inner(count))),
1171 rhs: Box::new(ada83::Expr::int(1)),
1172 }),
1173 })),
1174 },
1175 }]
1176 }
1177
1178 fn sequence_element(
1179 base: &str,
1180 index: Self::Expr,
1181 _element: Self::Type,
1182 ) -> (Vec<Self::Stmt>, Self::Expr, Vec<Self::Stmt>) {
1183 (
1184 Vec::new(),
1185 Self::index(Self::elements(base), index),
1186 Vec::new(),
1187 )
1188 }
1189
1190 fn routine(spec: Routine<Self>) -> Option<Self::Decl> {
1193 let mut params = vec![ada83::Param {
1203 name: Ident::new(if spec.writing { "w" } else { "r" }),
1204 mode: ada83::Mode::In,
1205 type_: Self::runtime_path(if spec.writing {
1206 "Writer_Access"
1207 } else {
1208 "Reader_Access"
1209 }),
1210 }];
1211 if spec.writing {
1212 params.push(ada83::Param {
1213 name: Ident::new("v"),
1214 mode: ada83::Mode::In,
1215 type_: mark_path(&spec.sample.mark),
1216 });
1217 }
1218 for (type_, name) in &spec.extra {
1219 params.push(ada83::Param {
1220 name: Ident::new(local_name(name)),
1221 mode: ada83::Mode::In,
1222 type_: mark_path(&type_.mark),
1223 });
1224 }
1225 let profile = ada83::Subprogram {
1226 doc: spec.doc.clone(),
1227 kind: if spec.writing {
1228 ada83::SubprogramKind::Procedure
1229 } else {
1230 ada83::SubprogramKind::Function
1231 },
1232 name: Ident::new(&spec.name),
1233 params,
1234 result: if spec.writing {
1235 None
1236 } else {
1237 Some(mark_path(&spec.sample.mark))
1238 },
1239 };
1240 let Some(body) = spec.body else {
1241 return Some(ada83::Decl::Subprogram(profile));
1242 };
1243
1244 if spec.writing {
1245 return Some(ada83::Decl::SubprogramBody(ada83::SubprogramBody {
1246 spec: profile,
1247 body,
1248 }));
1249 }
1250
1251 let mut statements = Vec::new();
1252 if spec.sample.is_union && names_mark(&body, OWN_SAMPLE) {
1253 statements.push(ada83::Stmt::Subtype {
1254 name: Ident::new(OWN_SAMPLE),
1255 mark: mark_path(&spec.sample.mark),
1256 });
1257 }
1258 if let Some(array) = &spec.sample.own_array {
1259 if names_mark(&body, OWN_ARRAY) {
1260 statements.push(ada83::Stmt::Subtype {
1261 name: Ident::new(OWN_ARRAY),
1262 mark: Path::single(array),
1263 });
1264 }
1265 }
1266 let defaulter = crate::default_ada83::defaulter_from_decoder(&spec.name);
1267 statements.push(ada83::Stmt::Var(ada83::VarDecl {
1268 name: Ident::new("v"),
1269 mark: mark_path(&spec.sample.mark),
1270 constraint: None,
1271 value: Some(Self::call_path(Path::single(&defaulter), Vec::new())),
1272 }));
1273 let mut body = body;
1274 statements.append(&mut body);
1275 statements.push(ada83::Stmt::Return(Some(ada83::Expr::name("v"))));
1276 Some(ada83::Decl::SubprogramBody(ada83::SubprogramBody {
1277 spec: profile,
1278 body: statements,
1279 }))
1280 }
1281
1282 fn default_into(
1285 ast: &Ast,
1286 id: Id<TypeNode>,
1287 place: Self::Expr,
1288 ) -> Result<Self::Stmt, EncodeError> {
1289 let defaulted = Self::call_path(
1290 Path::single(&crate::default_ada83::defaulter_name(ast, id)),
1291 Vec::new(),
1292 );
1293 Ok(match place {
1294 AExpr::OptionalSlot(field) => ada83::Stmt::Assign {
1295 place: field,
1296 value: Self::engaged(defaulted),
1297 },
1298 AExpr::Discriminant(field) => Self::assign_discriminant(field, defaulted),
1299 other => ada83::Stmt::Assign {
1300 place: inner(other),
1301 value: defaulted,
1302 },
1303 })
1304 }
1305
1306 fn member_default(
1309 ast: &Ast,
1310 node: &MemberNode,
1311 type_: Id<TypeNode>,
1312 place: Self::Expr,
1313 ) -> Result<Vec<Self::Stmt>, EncodeError> {
1314 crate::default_ada83::member_default(ast, node, type_, inner(place))
1315 }
1316
1317 fn enumerator_constant(_ast: &Ast, _id: Id<TypeNode>, enumerator: &str) -> Self::Expr {
1321 plain(ada83::Expr::name(&component_name(enumerator)))
1322 }
1323}
1324
1325fn local_name(text: &str) -> &str {
1330 if text.eq_ignore_ascii_case("zd_wire") {
1331 return "zd_onwire";
1332 }
1333 text
1334}
1335
1336fn names_mark(body: &[ada83::Stmt], mark: &str) -> bool {
1343 body.iter().any(|statement| stmt_names(statement, mark))
1344}
1345
1346fn stmt_names(statement: &ada83::Stmt, mark: &str) -> bool {
1351 match statement {
1352 ada83::Stmt::Null | ada83::Stmt::Exit | ada83::Stmt::Comment(_) => false,
1353 ada83::Stmt::Var(var) => {
1354 path_is(&var.mark, mark)
1355 || var.constraint.as_ref().is_some_and(|e| expr_names(e, mark))
1356 || var.value.as_ref().is_some_and(|e| expr_names(e, mark))
1357 }
1358 ada83::Stmt::Subtype { mark: target, .. } => path_is(target, mark),
1359 ada83::Stmt::Assign { place, value } => expr_names(place, mark) || expr_names(value, mark),
1360 ada83::Stmt::Call(value) => expr_names(value, mark),
1361 ada83::Stmt::Return(value) => value.as_ref().is_some_and(|e| expr_names(e, mark)),
1362 ada83::Stmt::If {
1363 condition,
1364 then,
1365 otherwise,
1366 } => {
1367 expr_names(condition, mark)
1368 || names_mark(then, mark)
1369 || otherwise
1370 .as_ref()
1371 .is_some_and(|body| names_mark(body, mark))
1372 }
1373 ada83::Stmt::For {
1374 low, high, body, ..
1375 } => expr_names(low, mark) || expr_names(high, mark) || names_mark(body, mark),
1376 ada83::Stmt::While { condition, body } => {
1377 expr_names(condition, mark) || names_mark(body, mark)
1378 }
1379 ada83::Stmt::Declare { vars, body } => {
1380 vars.iter().any(|var| {
1381 path_is(&var.mark, mark)
1382 || var.constraint.as_ref().is_some_and(|e| expr_names(e, mark))
1383 || var.value.as_ref().is_some_and(|e| expr_names(e, mark))
1384 }) || names_mark(body, mark)
1385 }
1386 }
1387}
1388
1389fn path_is(path: &Path, mark: &str) -> bool {
1390 path.segments().len() == 1
1391 && path
1392 .segments()
1393 .first()
1394 .is_some_and(|segment| segment.as_str() == mark)
1395}
1396
1397fn expr_names(expr: &ada83::Expr, mark: &str) -> bool {
1402 match expr {
1403 ada83::Expr::Literal(_) => false,
1404 ada83::Expr::Name(path) => path_is(path, mark),
1405 ada83::Expr::Call { name, args } => {
1406 path_is(name, mark) || args.iter().any(|arg| expr_names(arg, mark))
1407 }
1408 ada83::Expr::Negate(value)
1409 | ada83::Expr::Unary { value, .. }
1410 | ada83::Expr::Deref(value) => expr_names(value, mark),
1411 ada83::Expr::Binary { lhs, rhs, .. } => expr_names(lhs, mark) || expr_names(rhs, mark),
1412 ada83::Expr::Selected { value, .. } => expr_names(value, mark),
1413 ada83::Expr::Indexed { value, index } => expr_names(value, mark) || expr_names(index, mark),
1414 ada83::Expr::Slice { value, low, high } => {
1415 expr_names(value, mark) || expr_names(low, mark) || expr_names(high, mark)
1416 }
1417 ada83::Expr::Attribute { value, args, .. } => {
1418 expr_names(value, mark) || args.iter().any(|arg| expr_names(arg, mark))
1419 }
1420 ada83::Expr::Convert {
1421 mark: target,
1422 value,
1423 } => path_is(target, mark) || expr_names(value, mark),
1424 ada83::Expr::Aggregate(parts) => parts.iter().any(|part| expr_names(&part.value, mark)),
1425 ada83::Expr::New { mark: target, init } => {
1426 path_is(target, mark)
1427 || match init {
1428 ada83::AllocInit::Range { low, high } => {
1429 expr_names(low, mark) || expr_names(high, mark)
1430 }
1431 ada83::AllocInit::Qualified(value) => expr_names(value, mark),
1432 }
1433 }
1434 }
1435}