1use super::{CodecTarget, Constant, Handle, Handoff, Routine, Scalar};
61use crate::adapter::ada::{ada_holder, ada_map_entry_name, ada_type_name, ada_value_path};
62use crate::default_common::resolve_alias;
63use crate::encode::EncodeError;
64use zerodds_ast::{Ast, MemberNode, PrimitiveKind, TypeKind, TypeNode};
65use zerodds_ast_core::Id;
66use zerodds_lang_cst::ada;
67use zerodds_lang_cst::common::{Doc, Ident, Literal, Path};
68
69#[derive(Debug, Clone, Copy, PartialEq, Eq)]
71pub struct Ada;
72
73const RUNTIME: &str = "Zd_Wire";
75
76const SIGNED_CHAR: &str = "signed char";
81
82const OWN_SAMPLE: &str = "Zd_Sample";
86
87const OWN_ARRAY: &str = "Zd_Own_Array";
90
91#[derive(Debug, Clone, PartialEq, Eq)]
94pub struct AdaType {
95 pub mark: String,
97 pub is_enum: bool,
100 pub is_bool: bool,
103 pub is_union: bool,
105 pub own_array: Option<String>,
108}
109
110impl AdaType {
111 fn bare(mark: &str) -> Self {
112 Self {
113 mark: mark.to_string(),
114 is_enum: false,
115 is_bool: false,
116 is_union: false,
117 own_array: None,
118 }
119 }
120}
121
122#[derive(Debug, Clone)]
126pub enum AExpr {
127 Plain(ada::Expr),
129 OptionalSlot(ada::Expr),
132 Discriminant(ada::Expr),
134 ReferenceSlot {
139 place: ada::Expr,
141 mark: Path,
143 },
144 Assignment {
147 place: Box<AExpr>,
149 value: ada::Expr,
151 },
152}
153
154fn inner(expr: AExpr) -> ada::Expr {
161 match expr {
162 AExpr::Plain(e) | AExpr::OptionalSlot(e) | AExpr::Discriminant(e) => e,
163 AExpr::ReferenceSlot { place, .. } => place,
164 AExpr::Assignment { place, value } => ada::Expr::Binary {
167 op: "=",
168 lhs: Box::new(inner(*place)),
169 rhs: Box::new(value),
170 },
171 }
172}
173
174fn plain(e: ada::Expr) -> AExpr {
175 AExpr::Plain(e)
176}
177
178fn mark_path(mark: &str) -> Path {
180 Path::new(&mark.split('.').collect::<Vec<&str>>())
181}
182
183impl Ada {
184 fn runtime_path(name: &str) -> Path {
186 Path::new(&[RUNTIME, name])
187 }
188
189 fn runtime_constant(name: &str) -> AExpr {
190 plain(ada::Expr::Name(Self::runtime_path(name)))
191 }
192
193 fn operation(method: &str) -> String {
195 ada::ada_case(method)
196 }
197
198 fn selected(value: ada::Expr, name: &str) -> ada::Expr {
199 ada::Expr::Selected {
200 value: Box::new(value),
201 name: Ident::new(name),
202 }
203 }
204
205 fn call_path(path: Path, args: Vec<ada::Expr>) -> ada::Expr {
206 ada::Expr::Call { name: path, args }
207 }
208
209 fn to_natural(value: ada::Expr) -> ada::Expr {
212 ada::Expr::Convert {
213 mark: Path::single("Natural"),
214 value: Box::new(value),
215 }
216 }
217
218 fn engaged(value: ada::Expr) -> ada::Expr {
223 ada::Expr::Aggregate(vec![
224 ada::Association {
225 choice: Ident::new(crate::adapter::ada::PRESENT),
226 value: ada::Expr::Literal(Literal::Bool(true)),
227 },
228 ada::Association {
229 choice: Ident::new(crate::adapter::ada::VALUE),
230 value,
231 },
232 ])
233 }
234
235 fn discriminant_record(place: ada::Expr) -> ada::Expr {
237 match place {
238 ada::Expr::Selected { value, .. } => *value,
239 other => other,
240 }
241 }
242
243 fn assign_discriminant(place: ada::Expr, value: ada::Expr) -> ada::Stmt {
247 ada::Stmt::Declare {
248 vars: vec![ada::VarDecl {
249 name: Ident::new("zd_nd"),
250 mark: Path::single(OWN_SAMPLE),
251 constraint: Some(value),
252 value: None,
253 }],
254 body: vec![ada::Stmt::Assign {
255 place: Self::discriminant_record(place),
256 value: ada::Expr::name("zd_nd"),
257 }],
258 }
259 }
260}
261
262impl CodecTarget for Ada {
263 type Expr = AExpr;
264 type Stmt = ada::Stmt;
265 type Block = Vec<ada::Stmt>;
266 type Type = AdaType;
267 type Decl = ada::Decl;
268
269 fn scalar(kind: Scalar) -> Self::Type {
275 match kind {
276 Scalar::Bool => AdaType {
277 is_bool: true,
278 ..AdaType::bare("Boolean")
279 },
280 Scalar::Char | Scalar::UInt8 => AdaType::bare("Interfaces.Unsigned_8"),
281 Scalar::Int8 => AdaType::bare("Interfaces.Integer_8"),
282 Scalar::Int16 => AdaType::bare("Interfaces.Integer_16"),
283 Scalar::UInt16 => AdaType::bare("Interfaces.Unsigned_16"),
284 Scalar::Int32 => AdaType::bare("Interfaces.Integer_32"),
285 Scalar::UInt32 => AdaType::bare("Interfaces.Unsigned_32"),
286 Scalar::Int64 => AdaType::bare("Interfaces.Integer_64"),
287 Scalar::UInt64 => AdaType::bare("Interfaces.Unsigned_64"),
288 Scalar::Index | Scalar::Size => AdaType::bare("Natural"),
289 Scalar::Float => AdaType::bare("Interfaces.IEEE_Float_32"),
290 Scalar::Double => AdaType::bare("Interfaces.IEEE_Float_64"),
291 Scalar::LongDouble => AdaType::bare("Ada.Strings.Unbounded.Unbounded_String"),
293 }
294 }
295
296 fn named(name: &str) -> Self::Type {
297 AdaType::bare(name)
298 }
299
300 fn nothing() -> Self::Type {
304 AdaType::bare("Zd_No_Type")
305 }
306
307 fn handle(kind: Handle) -> Self::Type {
308 AdaType::bare(match kind {
309 Handle::DHeader => "Zd_Wire.Dheader",
310 Handle::EmHeader => "Zd_Wire.Emheader",
311 Handle::Pid => "Zd_Wire.Pid_Write",
312 Handle::TryConstruct => "Zd_Wire.Try_Construct",
313 Handle::ReaderMark => "Zd_Wire.Reader_Mark",
314 Handle::PidRead => "Zd_Wire.Pid_Read",
315 Handle::EmHeaderRead => "Zd_Wire.Emheader_Read",
316 })
317 }
318
319 fn code_point(value: Self::Expr, _narrow: bool) -> Self::Expr {
324 plain(ada::Expr::Convert {
325 mark: mark_path("Interfaces.Unsigned_32"),
326 value: Box::new(inner(value)),
327 })
328 }
329
330 fn constant(which: Constant) -> Self::Expr {
334 match which {
335 Constant::WcharWidth2 => plain(ada::Expr::int(2)),
336 Constant::WcharWidth4 => plain(ada::Expr::int(4)),
337 Constant::WcharFixed => Self::runtime_constant("Wchar_Fixed"),
338 Constant::WcharGiopLengthPrefixed => {
339 Self::runtime_constant("Wchar_Giop_Length_Prefixed")
340 }
341 Constant::WstringUnitsStream => Self::runtime_constant("Unit_Stream"),
342 Constant::WstringUnitsBigEndianAlways => {
343 Self::runtime_constant("Unit_Big_Endian_Always")
344 }
345 Constant::WstringUnitsByteOrderMark => Self::runtime_constant("Unit_Byte_Order_Mark"),
346 Constant::WstringUnitsHostUnswapped => Self::runtime_constant("Unit_Host_Unswapped"),
347 Constant::WstringSpecification => Self::runtime_constant("Wstr_Octets_Unterminated_2"),
348 Constant::WstringCharacterCount => {
349 Self::runtime_constant("Wstr_Characters_Unterminated_2")
350 }
351 Constant::WstringCharacterCountTerminated => {
352 Self::runtime_constant("Wstr_Characters_Terminated_4")
353 }
354 Constant::WstringSpecificationWideUnits => {
355 Self::runtime_constant("Wstr_Octets_Unterminated_4")
356 }
357 Constant::WstringRosTypeSupport => {
358 Self::runtime_constant("Wstr_Characters_Unterminated_4")
359 }
360 Constant::WstringOctetsTerminated2 => {
361 Self::runtime_constant("Wstr_Octets_Terminated_2")
362 }
363 Constant::WstringOctetsTerminated4 => {
364 Self::runtime_constant("Wstr_Octets_Terminated_4")
365 }
366 Constant::WstringCharactersTerminated2 => {
367 Self::runtime_constant("Wstr_Characters_Terminated_2")
368 }
369 Constant::FixedDeclared => Self::runtime_constant("Fixed_Declared"),
370 Constant::FixedValuePrecision => Self::runtime_constant("Fixed_Value_Precision"),
371 Constant::FixedValueStringDigits => Self::runtime_constant("Fixed_Value_String_Digits"),
372 Constant::ParameterMember => Self::runtime_constant("Role_Member"),
373 Constant::ParameterOptional => Self::runtime_constant("Role_Optional"),
374 Constant::TryConstructDiscard => Self::runtime_constant("Tc_Discard"),
375 Constant::TryConstructTrim => Self::runtime_constant("Tc_Trim"),
376 Constant::TryConstructUseDefault => Self::runtime_constant("Tc_Use_Default"),
377 Constant::StatusOk => Self::runtime_constant("Status_Ok"),
378 Constant::StatusDiscarded => Self::runtime_constant("Status_Discarded"),
379 Constant::StatusImpossibleLength => Self::runtime_constant("Status_Impossible_Length"),
380 Constant::StatusOutOfRange => Self::runtime_constant("Status_Out_Of_Range"),
381 Constant::StatusTruncated => Self::runtime_constant("Status_Truncated"),
382 }
383 }
384
385 fn unsigned_holder(bits: u16) -> Self::Type {
386 AdaType::bare(ada_holder(bits).as_str())
387 }
388
389 fn carries_hdds_axes() -> bool {
395 true
396 }
397
398 fn value_type(ast: &Ast, id: Id<TypeNode>) -> Self::Type {
399 let mark = match ada_value_path(ast, id) {
400 Ok(path) => path
401 .segments()
402 .iter()
403 .map(Ident::as_str)
404 .collect::<Vec<&str>>()
405 .join("."),
406 Err(_) => "Zd_No_Ada_Form".to_string(),
410 };
411 let resolved = resolve_alias(ast, id);
412 let kind = ast.type_(resolved).map(|node| node.kind.clone());
413 AdaType {
414 mark,
415 is_enum: matches!(kind, Ok(TypeKind::Enumeration { .. })),
416 is_bool: matches!(kind, Ok(TypeKind::Primitive(PrimitiveKind::Boolean))),
417 is_union: matches!(kind, Ok(TypeKind::Union { .. })),
418 own_array: match kind {
419 Ok(TypeKind::Sequence { .. } | TypeKind::Map { .. }) => {
420 Some(format!("{}_Array", ada_type_name(ast, resolved)))
421 }
422 _ => None,
423 },
424 }
425 }
426
427 fn type_name(ast: &Ast, id: Id<TypeNode>) -> String {
428 crate::adapter::ada::type_tag(ast, id)
429 }
430
431 fn map_entry_name(ast: &Ast, id: Id<TypeNode>) -> String {
432 ada_map_entry_name(ast, id)
433 }
434
435 fn module_prefix(_ast: &Ast, _id: Id<TypeNode>) -> String {
438 String::new()
439 }
440
441 fn escape(name: &str) -> String {
443 crate::adapter::ada::component_name(name)
444 }
445
446 fn inherited_path(depth: usize) -> Option<String> {
448 Some(format!("{}.", crate::adapter::ada::component_name("parent")).repeat(depth))
449 }
450
451 fn name(text: &str) -> Self::Expr {
454 plain(ada::Expr::name(local_name(text)))
455 }
456
457 fn int(value: i128) -> Self::Expr {
458 plain(ada::Expr::int(value))
459 }
460
461 fn literal(value: Literal) -> Self::Expr {
464 let Literal::Int(text) = &value else {
465 return plain(ada::Expr::Literal(value));
466 };
467 match text.as_str() {
468 "true" => plain(ada::Expr::Literal(Literal::Bool(true))),
469 "false" => plain(ada::Expr::Literal(Literal::Bool(false))),
470 _ => plain(ada::Expr::Literal(value)),
471 }
472 }
473
474 fn wide_int(value: i128) -> Self::Expr {
478 Self::int(value)
479 }
480
481 fn unsigned_int(value: i128) -> Self::Expr {
482 Self::int(value)
483 }
484
485 fn wide_unsigned(value: u64) -> Self::Expr {
486 Self::int(i128::from(value))
487 }
488
489 fn wide_signed(value: i128) -> Self::Expr {
490 Self::int(value)
491 }
492
493 fn member(base: &str, field: &str) -> Self::Expr {
496 if field == "_d" {
497 return AExpr::Discriminant(Self::selected(
498 ada::Expr::name(local_name(base)),
499 crate::adapter::ada::DISCRIMINANT,
500 ));
501 }
502 plain(Self::selected(ada::Expr::name(local_name(base)), field))
503 }
504
505 fn whole(base: &str) -> Self::Expr {
506 plain(ada::Expr::name(local_name(base)))
507 }
508
509 fn field_of(value: Self::Expr, field: &str) -> Self::Expr {
510 plain(Self::selected(inner(value), field))
511 }
512
513 fn header_field(value: Self::Expr, field: &str) -> Self::Expr {
517 let name = if field == "end" {
518 "End_Flag".to_string()
519 } else {
520 ada::ada_case(field)
521 };
522 plain(Self::selected(inner(value), &name))
523 }
524
525 fn index(value: Self::Expr, at: Self::Expr) -> Self::Expr {
526 plain(ada::Expr::Indexed {
527 value: Box::new(inner(value)),
528 index: Box::new(inner(at)),
529 })
530 }
531
532 fn count_of(base: &str, fixed: Option<u64>) -> Self::Expr {
536 match fixed {
537 Some(bound) => plain(ada::Expr::int(i128::from(bound))),
538 None => plain(ada::Expr::Convert {
539 mark: mark_path("Interfaces.Unsigned_32"),
540 value: Box::new(ada::Expr::Attribute {
541 value: Box::new(ada::Expr::Deref(Box::new(ada::Expr::name(local_name(
542 base,
543 ))))),
544 name: Ident::new("Length"),
545 args: Vec::new(),
546 }),
547 }),
548 }
549 }
550
551 fn elements(base: &str) -> Self::Expr {
554 plain(ada::Expr::name(local_name(base)))
555 }
556
557 fn case_member(base: &str, field: &str) -> Self::Expr {
560 Self::member(base, field)
561 }
562
563 fn entry_half(entry: Self::Expr, key: bool) -> Self::Expr {
566 plain(Self::selected(
567 inner(entry),
568 if key {
569 "Key"
570 } else {
571 crate::adapter::ada::VALUE
572 },
573 ))
574 }
575
576 fn absent() -> Self::Expr {
577 plain(ada::Expr::Literal(Literal::Null))
578 }
579
580 fn materialised(_value: Self::Expr) -> Option<Self::Expr> {
583 None
584 }
585
586 fn optional_value(_ast: &Ast, _id: Id<TypeNode>, base: &str, field: &str) -> Self::Expr {
590 plain(Self::selected(
591 inner(Self::member(base, field)),
592 crate::adapter::ada::VALUE,
593 ))
594 }
595
596 fn holds_by_reference(
598 ast: &Ast,
599 aggregate: Id<TypeNode>,
600 member_type: Id<TypeNode>,
601 optional: bool,
602 external: bool,
603 ) -> bool {
604 crate::adapter::ada::held_by_reference(ast, aggregate, member_type, optional, external)
605 }
606
607 fn reference_present(base: &str, field: &str) -> Self::Expr {
609 Self::binary(
610 "!=",
611 Self::member(base, field),
612 plain(ada::Expr::Literal(Literal::Null)),
613 )
614 }
615
616 fn reference_value(_ast: &Ast, _id: Id<TypeNode>, base: &str, field: &str) -> Self::Expr {
618 plain(ada::Expr::Deref(Box::new(inner(Self::member(base, field)))))
619 }
620
621 fn reference_destination(
624 ast: &Ast,
625 id: Id<TypeNode>,
626 base: &str,
627 field: &str,
628 ) -> (Vec<Self::Stmt>, Self::Expr) {
629 let designated = crate::adapter::ada::reference_designated(ast, id).unwrap_or(id);
630 (
631 Vec::new(),
632 AExpr::ReferenceSlot {
633 place: inner(Self::member(base, field)),
634 mark: Path::single(&ada_type_name(ast, designated)),
635 },
636 )
637 }
638
639 fn reference_absent(base: &str, field: &str) -> Vec<Self::Stmt> {
641 vec![ada::Stmt::Assign {
642 place: inner(Self::member(base, field)),
643 value: ada::Expr::Literal(Literal::Null),
644 }]
645 }
646
647 fn present(base: &str, field: &str) -> Self::Expr {
649 plain(Self::selected(
650 inner(Self::member(base, field)),
651 crate::adapter::ada::PRESENT,
652 ))
653 }
654
655 fn set_present(base: &str, field: &str, present: bool) -> Vec<Self::Stmt> {
659 if present {
660 return Vec::new();
661 }
662 vec![ada::Stmt::Assign {
663 place: inner(Self::member(base, field)),
664 value: ada::Expr::Aggregate(vec![ada::Association {
665 choice: Ident::new(crate::adapter::ada::PRESENT),
666 value: ada::Expr::Literal(Literal::Bool(false)),
667 }]),
668 }]
669 }
670
671 fn optional_destination(base: &str, field: &str) -> (Vec<Self::Stmt>, Self::Expr) {
674 (
675 Vec::new(),
676 AExpr::OptionalSlot(inner(Self::member(base, field))),
677 )
678 }
679
680 fn binary(op: &'static str, lhs: Self::Expr, rhs: Self::Expr) -> Self::Expr {
684 if op == "=" {
685 return AExpr::Assignment {
686 place: Box::new(lhs),
687 value: inner(rhs),
688 };
689 }
690 if op == ">>" || op == "<<" {
694 return plain(Self::call_path(
695 Path::new(&[
696 "Interfaces",
697 if op == ">>" {
698 "Shift_Right"
699 } else {
700 "Shift_Left"
701 },
702 ]),
703 vec![inner(lhs), Self::to_natural(inner(rhs))],
704 ));
705 }
706 plain(ada::Expr::Binary {
707 op,
708 lhs: Box::new(inner(lhs)),
709 rhs: Box::new(inner(rhs)),
710 })
711 }
712
713 fn unary(op: &'static str, value: Self::Expr) -> Self::Expr {
714 plain(ada::Expr::Unary {
715 op,
716 value: Box::new(inner(value)),
717 })
718 }
719
720 fn paren(value: Self::Expr) -> Self::Expr {
723 value
724 }
725
726 fn cast(type_: Self::Type, value: Self::Expr) -> Self::Expr {
734 if type_.mark == SIGNED_CHAR {
735 return plain(Self::call_path(
736 Self::runtime_path("As_Signed"),
737 vec![inner(value)],
738 ));
739 }
740 if type_.is_bool {
741 if let AExpr::Plain(ada::Expr::Literal(Literal::Int(text))) = &value {
742 return plain(ada::Expr::Literal(Literal::Bool(text != "0")));
743 }
744 }
745 if type_.is_enum {
746 return plain(ada::Expr::Attribute {
747 value: Box::new(ada::Expr::Name(mark_path(&type_.mark))),
748 name: Ident::new("Enum_Val"),
749 args: vec![inner(value)],
750 });
751 }
752 plain(ada::Expr::Convert {
753 mark: mark_path(&type_.mark),
754 value: Box::new(inner(value)),
755 })
756 }
757
758 fn handoff(value: Self::Expr, _form: Handoff) -> Self::Expr {
761 value
762 }
763
764 fn call(callee: &str, args: Vec<Self::Expr>) -> Self::Expr {
768 let arguments: Vec<ada::Expr> = args.into_iter().map(inner).collect();
769 if callee == "strcmp" {
770 return plain(Self::call_path(Self::runtime_path("Strcmp"), arguments));
771 }
772 plain(Self::call_path(Path::single(callee), arguments))
773 }
774
775 fn runtime(receiver: &str, method: &str, args: Vec<Self::Expr>) -> Self::Expr {
778 let mut arguments = vec![ada::Expr::name(receiver)];
779 arguments.extend(args.into_iter().map(inner));
780 plain(Self::call_path(
781 Self::runtime_path(&Self::operation(method)),
782 arguments,
783 ))
784 }
785
786 fn runtime_static(method: &str, args: Vec<Self::Expr>) -> Self::Expr {
788 plain(Self::call_path(
789 Self::runtime_path(&Self::operation(method)),
790 args.into_iter().map(inner).collect(),
791 ))
792 }
793
794 fn declare(type_: Self::Type, name: &str, value: Option<Self::Expr>) -> Self::Stmt {
804 let counts = type_.mark == "Interfaces.Unsigned_32"
805 && matches!(
806 &value,
807 Some(AExpr::Plain(ada::Expr::Literal(Literal::Int(_))))
808 );
809 ada::Stmt::Var(ada::VarDecl {
810 name: Ident::new(local_name(name)),
811 mark: mark_path(if counts { "Natural" } else { &type_.mark }),
812 constraint: None,
813 value: value.map(inner),
814 })
815 }
816
817 fn perform(value: Self::Expr) -> Self::Stmt {
822 match value {
823 AExpr::Assignment { place, value } => match *place {
824 AExpr::OptionalSlot(field) => ada::Stmt::Assign {
825 place: field,
826 value: Self::engaged(value),
827 },
828 AExpr::Discriminant(field) => Self::assign_discriminant(field, value),
829 other => ada::Stmt::Assign {
830 place: inner(other),
831 value,
832 },
833 },
834 other => ada::Stmt::Call(inner(other)),
835 }
836 }
837
838 fn give_back(value: Option<Self::Expr>) -> Self::Stmt {
840 ada::Stmt::Return(Some(match value {
841 Some(value) => inner(value),
842 None => ada::Expr::name("v"),
843 }))
844 }
845
846 fn when(
847 condition: Self::Expr,
848 then: Self::Block,
849 otherwise: Option<Self::Block>,
850 ) -> Self::Stmt {
851 ada::Stmt::If {
852 condition: inner(condition),
853 then,
854 otherwise: otherwise.filter(|body| !body.is_empty()),
855 }
856 }
857
858 fn count_up(counter: &str, bound: Self::Expr, body: Self::Block) -> Self::Stmt {
862 ada::Stmt::For {
863 counter: Ident::new(local_name(counter)),
864 low: ada::Expr::int(0),
865 high: ada::Expr::Binary {
866 op: "-",
867 lhs: Box::new(Self::to_natural(inner(bound))),
868 rhs: Box::new(ada::Expr::int(1)),
869 },
870 body,
871 }
872 }
873
874 fn until(condition: Self::Expr, body: Self::Block) -> Self::Stmt {
875 ada::Stmt::While {
876 condition: inner(condition),
877 body,
878 }
879 }
880
881 fn leave() -> Self::Stmt {
882 ada::Stmt::Exit
883 }
884
885 fn note(doc: Doc) -> Self::Stmt {
886 ada::Stmt::Comment(doc)
887 }
888
889 fn drop_value(value: Self::Expr) -> Self::Stmt {
893 ada::Stmt::Call(Self::call_path(
894 Self::runtime_path("Discard_U32"),
895 vec![inner(value)],
896 ))
897 }
898
899 fn mark_used(_name: &str) -> Vec<Self::Stmt> {
903 Vec::new()
904 }
905
906 fn read_call(
910 callee: &str,
911 place: Self::Expr,
912 _form: Handoff,
913 behaviour: Self::Expr,
914 ) -> Self::Stmt {
915 let decoded = Self::call_path(
916 Path::single(callee),
917 vec![ada::Expr::name("r"), inner(behaviour)],
918 );
919 match place {
920 AExpr::OptionalSlot(field) => ada::Stmt::Assign {
921 place: field,
922 value: Self::engaged(decoded),
923 },
924 AExpr::Discriminant(field) => Self::assign_discriminant(field, decoded),
925 AExpr::ReferenceSlot { place, mark } => ada::Stmt::Assign {
928 place,
929 value: ada::Expr::New {
930 mark,
931 init: ada::AllocInit::Qualified(Box::new(decoded)),
932 },
933 },
934 other => ada::Stmt::Assign {
935 place: inner(other),
936 value: decoded,
937 },
938 }
939 }
940
941 fn read_forward(callee: &str) -> Self::Stmt {
944 ada::Stmt::Assign {
945 place: ada::Expr::name("v"),
946 value: Self::call_path(
947 Path::single(callee),
948 vec![ada::Expr::name("r"), ada::Expr::name("zd_tc")],
949 ),
950 }
951 }
952
953 fn block(statements: Vec<Self::Stmt>) -> Self::Block {
954 statements
955 }
956
957 fn into_statements(block: Self::Block) -> Vec<Self::Stmt> {
958 block
959 }
960
961 fn make_room(
966 base: &str,
967 _element: Self::Type,
968 count: Self::Expr,
969 _assigned_whole: bool,
970 fill: Vec<Self::Stmt>,
971 ) -> Vec<Self::Stmt> {
972 let mut out = vec![ada::Stmt::Assign {
973 place: ada::Expr::name(local_name(base)),
974 value: ada::Expr::New {
975 mark: Path::single(OWN_ARRAY),
976 init: ada::AllocInit::Range {
977 low: Box::new(ada::Expr::int(0)),
978 high: Box::new(ada::Expr::Binary {
979 op: "-",
980 lhs: Box::new(Self::to_natural(inner(count))),
981 rhs: Box::new(ada::Expr::int(1)),
982 }),
983 },
984 },
985 }];
986 out.extend(fill);
987 out
988 }
989
990 fn keep_first(base: &str, count: Self::Expr) -> Vec<Self::Stmt> {
994 vec![ada::Stmt::Assign {
995 place: ada::Expr::name(local_name(base)),
996 value: ada::Expr::New {
997 mark: Path::single(OWN_ARRAY),
998 init: ada::AllocInit::Qualified(Box::new(ada::Expr::Slice {
999 value: Box::new(ada::Expr::Deref(Box::new(ada::Expr::name(local_name(
1000 base,
1001 ))))),
1002 low: Box::new(ada::Expr::int(0)),
1003 high: Box::new(ada::Expr::Binary {
1004 op: "-",
1005 lhs: Box::new(Self::to_natural(inner(count))),
1006 rhs: Box::new(ada::Expr::int(1)),
1007 }),
1008 })),
1009 },
1010 }]
1011 }
1012
1013 fn sequence_element(
1016 base: &str,
1017 index: Self::Expr,
1018 _element: Self::Type,
1019 ) -> (Vec<Self::Stmt>, Self::Expr, Vec<Self::Stmt>) {
1020 (
1021 Vec::new(),
1022 Self::index(Self::elements(base), index),
1023 Vec::new(),
1024 )
1025 }
1026
1027 fn routine(spec: Routine<Self>) -> Option<Self::Decl> {
1044 let mut params = vec![ada::Param {
1045 name: Ident::new(if spec.writing { "w" } else { "r" }),
1046 mode: ada::Mode::InOut,
1047 type_: Self::runtime_path(if spec.writing { "Writer" } else { "Reader" }),
1048 }];
1049 if spec.writing {
1050 params.push(ada::Param {
1051 name: Ident::new("v"),
1052 mode: ada::Mode::In,
1053 type_: mark_path(&spec.sample.mark),
1054 });
1055 }
1056 for (type_, name) in &spec.extra {
1057 params.push(ada::Param {
1058 name: Ident::new(local_name(name)),
1059 mode: ada::Mode::In,
1060 type_: mark_path(&type_.mark),
1061 });
1062 }
1063 let profile = ada::Subprogram {
1064 doc: spec.doc.clone(),
1065 kind: if spec.writing {
1066 ada::SubprogramKind::Procedure
1067 } else {
1068 ada::SubprogramKind::Function
1069 },
1070 name: Ident::new(&spec.name),
1071 params,
1072 result: if spec.writing {
1073 None
1074 } else {
1075 Some(mark_path(&spec.sample.mark))
1076 },
1077 is_abstract: false,
1078 };
1079 let Some(mut body) = spec.body else {
1080 return Some(ada::Decl::Subprogram(profile));
1081 };
1082
1083 if spec.writing {
1084 if spec.sample.is_enum {
1085 rewrite_enum_holder(&mut body, &spec.sample.mark);
1086 }
1087 return Some(ada::Decl::SubprogramBody(ada::SubprogramBody {
1088 spec: profile,
1089 body,
1090 }));
1091 }
1092
1093 let mut statements = Vec::new();
1097 if spec.sample.is_union && names_mark(&body, OWN_SAMPLE) {
1098 statements.push(ada::Stmt::Subtype {
1099 name: Ident::new(OWN_SAMPLE),
1100 mark: mark_path(&spec.sample.mark),
1101 });
1102 }
1103 if let Some(array) = &spec.sample.own_array {
1104 if names_mark(&body, OWN_ARRAY) {
1105 statements.push(ada::Stmt::Subtype {
1106 name: Ident::new(OWN_ARRAY),
1107 mark: Path::single(array),
1108 });
1109 }
1110 }
1111 let defaulter = crate::default_ada::defaulter_from_decoder(&spec.name);
1112 statements.push(ada::Stmt::Var(ada::VarDecl {
1113 name: Ident::new("v"),
1114 mark: mark_path(&spec.sample.mark),
1115 constraint: None,
1116 value: Some(Self::call_path(Path::single(&defaulter), Vec::new())),
1117 }));
1118 statements.append(&mut body);
1119 statements.push(ada::Stmt::Return(Some(ada::Expr::name("v"))));
1120 Some(ada::Decl::SubprogramBody(ada::SubprogramBody {
1121 spec: profile,
1122 body: statements,
1123 }))
1124 }
1125
1126 fn default_into(
1132 ast: &Ast,
1133 id: Id<TypeNode>,
1134 place: Self::Expr,
1135 ) -> Result<Self::Stmt, EncodeError> {
1136 let defaulted = Self::call_path(
1137 Path::single(&crate::default_ada::defaulter_name(ast, id)),
1138 Vec::new(),
1139 );
1140 Ok(match place {
1141 AExpr::OptionalSlot(field) => ada::Stmt::Assign {
1142 place: field,
1143 value: Self::engaged(defaulted),
1144 },
1145 AExpr::Discriminant(field) => Self::assign_discriminant(field, defaulted),
1146 other => ada::Stmt::Assign {
1147 place: inner(other),
1148 value: defaulted,
1149 },
1150 })
1151 }
1152
1153 fn member_default(
1158 ast: &Ast,
1159 node: &MemberNode,
1160 type_: Id<TypeNode>,
1161 place: Self::Expr,
1162 ) -> Result<Vec<Self::Stmt>, EncodeError> {
1163 crate::default_ada::member_default(ast, node, type_, inner(place))
1164 }
1165
1166 fn enumerator_constant(_ast: &Ast, _id: Id<TypeNode>, enumerator: &str) -> Self::Expr {
1170 plain(ada::Expr::name(&crate::adapter::ada::component_name(
1171 enumerator,
1172 )))
1173 }
1174}
1175
1176fn local_name(text: &str) -> &str {
1188 if text.eq_ignore_ascii_case("zd_wire") {
1189 return "zd_onwire";
1190 }
1191 text
1192}
1193
1194fn names_mark(body: &[ada::Stmt], mark: &str) -> bool {
1202 body.iter().any(|statement| stmt_names(statement, mark))
1203}
1204
1205fn stmt_names(statement: &ada::Stmt, mark: &str) -> bool {
1210 match statement {
1211 ada::Stmt::Null | ada::Stmt::Exit | ada::Stmt::Comment(_) => false,
1212 ada::Stmt::Var(var) => {
1213 path_is(&var.mark, mark)
1214 || var.constraint.as_ref().is_some_and(|e| expr_names(e, mark))
1215 || var.value.as_ref().is_some_and(|e| expr_names(e, mark))
1216 }
1217 ada::Stmt::Subtype { mark: target, .. } => path_is(target, mark),
1218 ada::Stmt::Assign { place, value } => expr_names(place, mark) || expr_names(value, mark),
1219 ada::Stmt::Call(value) => expr_names(value, mark),
1220 ada::Stmt::Return(value) => value.as_ref().is_some_and(|e| expr_names(e, mark)),
1221 ada::Stmt::If {
1222 condition,
1223 then,
1224 otherwise,
1225 } => {
1226 expr_names(condition, mark)
1227 || names_mark(then, mark)
1228 || otherwise
1229 .as_ref()
1230 .is_some_and(|body| names_mark(body, mark))
1231 }
1232 ada::Stmt::For {
1233 low, high, body, ..
1234 } => expr_names(low, mark) || expr_names(high, mark) || names_mark(body, mark),
1235 ada::Stmt::While { condition, body } => {
1236 expr_names(condition, mark) || names_mark(body, mark)
1237 }
1238 ada::Stmt::Declare { vars, body } => {
1239 vars.iter().any(|var| {
1240 path_is(&var.mark, mark)
1241 || var.constraint.as_ref().is_some_and(|e| expr_names(e, mark))
1242 || var.value.as_ref().is_some_and(|e| expr_names(e, mark))
1243 }) || names_mark(body, mark)
1244 }
1245 }
1246}
1247
1248fn path_is(path: &Path, mark: &str) -> bool {
1249 path.segments().len() == 1
1250 && path
1251 .segments()
1252 .first()
1253 .is_some_and(|segment| segment.as_str() == mark)
1254}
1255
1256fn expr_names(expr: &ada::Expr, mark: &str) -> bool {
1261 match expr {
1262 ada::Expr::Literal(_) | ada::Expr::BoxDefault => false,
1263 ada::Expr::Name(path) => path_is(path, mark),
1264 ada::Expr::Call { name, args } => {
1265 path_is(name, mark) || args.iter().any(|arg| expr_names(arg, mark))
1266 }
1267 ada::Expr::Negate(value) | ada::Expr::Unary { value, .. } | ada::Expr::Deref(value) => {
1268 expr_names(value, mark)
1269 }
1270 ada::Expr::Binary { lhs, rhs, .. } => expr_names(lhs, mark) || expr_names(rhs, mark),
1271 ada::Expr::Selected { value, .. } => expr_names(value, mark),
1272 ada::Expr::Indexed { value, index } => expr_names(value, mark) || expr_names(index, mark),
1273 ada::Expr::Slice { value, low, high } => {
1274 expr_names(value, mark) || expr_names(low, mark) || expr_names(high, mark)
1275 }
1276 ada::Expr::Attribute { value, args, .. } => {
1277 expr_names(value, mark) || args.iter().any(|arg| expr_names(arg, mark))
1278 }
1279 ada::Expr::Convert {
1280 mark: target,
1281 value,
1282 } => path_is(target, mark) || expr_names(value, mark),
1283 ada::Expr::Aggregate(parts) => parts.iter().any(|part| expr_names(&part.value, mark)),
1284 ada::Expr::New { mark: target, init } => {
1285 path_is(target, mark)
1286 || match init {
1287 ada::AllocInit::Range { low, high } => {
1288 expr_names(low, mark) || expr_names(high, mark)
1289 }
1290 ada::AllocInit::Qualified(value) => expr_names(value, mark),
1291 }
1292 }
1293 }
1294}
1295
1296fn rewrite_enum_holder(body: &mut [ada::Stmt], mark: &str) {
1308 for statement in body.iter_mut() {
1309 rewrite_stmt(statement, mark);
1310 }
1311}
1312
1313fn rewrite_stmt(statement: &mut ada::Stmt, mark: &str) {
1318 match statement {
1319 ada::Stmt::Null | ada::Stmt::Exit | ada::Stmt::Comment(_) | ada::Stmt::Subtype { .. } => {}
1320 ada::Stmt::Var(var) => {
1321 if let Some(value) = &mut var.value {
1322 rewrite_expr(value, mark);
1323 }
1324 }
1325 ada::Stmt::Assign { place, value } => {
1326 rewrite_expr(place, mark);
1327 rewrite_expr(value, mark);
1328 }
1329 ada::Stmt::Call(value) => rewrite_expr(value, mark),
1330 ada::Stmt::Return(value) => {
1331 if let Some(value) = value {
1332 rewrite_expr(value, mark);
1333 }
1334 }
1335 ada::Stmt::If {
1336 condition,
1337 then,
1338 otherwise,
1339 } => {
1340 rewrite_expr(condition, mark);
1341 rewrite_enum_holder(then, mark);
1342 if let Some(body) = otherwise {
1343 rewrite_enum_holder(body, mark);
1344 }
1345 }
1346 ada::Stmt::For {
1347 low, high, body, ..
1348 } => {
1349 rewrite_expr(low, mark);
1350 rewrite_expr(high, mark);
1351 rewrite_enum_holder(body, mark);
1352 }
1353 ada::Stmt::While { condition, body } => {
1354 rewrite_expr(condition, mark);
1355 rewrite_enum_holder(body, mark);
1356 }
1357 ada::Stmt::Declare { vars, body } => {
1358 for var in vars {
1359 if let Some(value) = &mut var.value {
1360 rewrite_expr(value, mark);
1361 }
1362 }
1363 rewrite_enum_holder(body, mark);
1364 }
1365 }
1366}
1367
1368fn rewrite_expr(expr: &mut ada::Expr, mark: &str) {
1373 if let ada::Expr::Convert {
1374 mark: target,
1375 value,
1376 } = expr
1377 {
1378 let is_holder = target
1379 .segments()
1380 .last()
1381 .is_some_and(|segment| segment.as_str() == "Integer_64");
1382 let is_sample = matches!(value.as_ref(), ada::Expr::Name(path)
1383 if path.segments().len() == 1
1384 && path.segments().first().is_some_and(|s| s.as_str() == "v"));
1385 if is_holder && is_sample {
1386 let sample = core::mem::replace(value.as_mut(), ada::Expr::BoxDefault);
1387 **value = ada::Expr::Attribute {
1388 value: Box::new(ada::Expr::Name(mark_path(mark))),
1389 name: Ident::new("Enum_Rep"),
1390 args: vec![sample],
1391 };
1392 return;
1393 }
1394 }
1395 match expr {
1396 ada::Expr::Literal(_) | ada::Expr::Name(_) | ada::Expr::BoxDefault => {}
1397 ada::Expr::Call { args, .. } => {
1398 for arg in args {
1399 rewrite_expr(arg, mark);
1400 }
1401 }
1402 ada::Expr::Negate(value) | ada::Expr::Unary { value, .. } | ada::Expr::Deref(value) => {
1403 rewrite_expr(value, mark);
1404 }
1405 ada::Expr::Binary { lhs, rhs, .. } => {
1406 rewrite_expr(lhs, mark);
1407 rewrite_expr(rhs, mark);
1408 }
1409 ada::Expr::Selected { value, .. } => rewrite_expr(value, mark),
1410 ada::Expr::Indexed { value, index } => {
1411 rewrite_expr(value, mark);
1412 rewrite_expr(index, mark);
1413 }
1414 ada::Expr::Slice { value, low, high } => {
1415 rewrite_expr(value, mark);
1416 rewrite_expr(low, mark);
1417 rewrite_expr(high, mark);
1418 }
1419 ada::Expr::Attribute { value, args, .. } => {
1420 rewrite_expr(value, mark);
1421 for arg in args {
1422 rewrite_expr(arg, mark);
1423 }
1424 }
1425 ada::Expr::Convert { value, .. } => rewrite_expr(value, mark),
1426 ada::Expr::Aggregate(parts) => {
1427 for part in parts {
1428 rewrite_expr(&mut part.value, mark);
1429 }
1430 }
1431 ada::Expr::New { init, .. } => match init {
1432 ada::AllocInit::Range { low, high } => {
1433 rewrite_expr(low, mark);
1434 rewrite_expr(high, mark);
1435 }
1436 ada::AllocInit::Qualified(value) => rewrite_expr(value, mark),
1437 },
1438 }
1439}