1use super::{CodecTarget, Constant, Handle, Handoff, Routine, Scalar};
37use crate::adapter::d::{d_map_entry_name, d_type_name, d_value_type, field_name};
38use crate::encode::EncodeError;
39use zerodds_ast::{Ast, CharWidth, MemberNode, TypeKind, TypeNode};
40use zerodds_ast_core::Id;
41use zerodds_lang_cst::common::{Doc, Ident, Literal};
42use zerodds_lang_cst::d;
43
44#[derive(Debug, Clone, Copy, PartialEq, Eq)]
46pub struct D;
47
48const MAX_TYPE_DEPTH: usize = 64;
50
51const RUNTIME: &str = "zdwire";
53
54const SIGNED_CHAR: &str = "signed char";
57
58#[derive(Debug, Clone)]
61pub enum DExpr {
62 Plain(d::Expr),
64 OptionalSlot(d::Expr),
67 ExternalSlot(d::Expr),
69}
70
71fn inner(expr: DExpr) -> d::Expr {
73 match expr {
74 DExpr::Plain(e) | DExpr::OptionalSlot(e) | DExpr::ExternalSlot(e) => e,
75 }
76}
77
78fn plain(e: d::Expr) -> DExpr {
79 DExpr::Plain(e)
80}
81
82impl D {
83 fn runtime_name(name: &str) -> d::Expr {
85 d::Expr::Dot {
86 value: Box::new(d::Expr::Name(Ident::new(RUNTIME))),
87 name: Ident::new(name),
88 }
89 }
90
91 fn pascal(method: &str) -> String {
96 let mut out = String::new();
97 for segment in method.split('_') {
98 let mut chars = segment.chars();
99 if let Some(first) = chars.next() {
100 out.extend(first.to_uppercase());
101 out.push_str(chars.as_str());
102 }
103 }
104 out
105 }
106
107 fn text(value: &str) -> DExpr {
108 plain(d::Expr::Literal(Literal::Str(value.to_string())))
109 }
110
111 fn runtime_constant(name: &str) -> DExpr {
112 plain(Self::runtime_name(name))
113 }
114
115 fn dot(value: d::Expr, name: &str) -> d::Expr {
116 d::Expr::Dot {
117 value: Box::new(value),
118 name: Ident::new(name),
119 }
120 }
121
122 fn call_expr(func: d::Expr, args: Vec<d::Expr>) -> d::Expr {
123 d::Expr::Call {
124 func: Box::new(func),
125 args,
126 }
127 }
128}
129
130impl CodecTarget for D {
131 type Expr = DExpr;
132 type Stmt = d::Stmt;
133 type Block = Vec<d::Stmt>;
134 type Type = d::Type;
135 type Decl = d::Decl;
136
137 fn scalar(kind: Scalar) -> Self::Type {
143 match kind {
144 Scalar::Bool => d::Type::Primitive(d::Primitive::Bool),
145 Scalar::Char | Scalar::UInt8 => d::Type::Primitive(d::Primitive::UByte),
146 Scalar::Int8 => d::Type::Primitive(d::Primitive::Byte),
147 Scalar::Int16 => d::Type::Primitive(d::Primitive::Short),
148 Scalar::UInt16 => d::Type::Primitive(d::Primitive::UShort),
149 Scalar::Int32 | Scalar::Size => d::Type::Primitive(d::Primitive::Int),
150 Scalar::UInt32 | Scalar::Index => d::Type::Primitive(d::Primitive::UInt),
151 Scalar::Int64 => d::Type::Primitive(d::Primitive::Long),
152 Scalar::UInt64 => d::Type::Primitive(d::Primitive::ULong),
153 Scalar::Float => d::Type::Primitive(d::Primitive::Float),
154 Scalar::Double => d::Type::Primitive(d::Primitive::Double),
155 Scalar::LongDouble => d::Type::Primitive(d::Primitive::String),
157 }
158 }
159
160 fn named(name: &str) -> Self::Type {
161 d::Type::named(name)
162 }
163
164 fn nothing() -> Self::Type {
166 d::Type::Primitive(d::Primitive::Void)
167 }
168
169 fn handle(kind: Handle) -> Self::Type {
171 d::Type::named(match kind {
172 Handle::DHeader => "zdwire.DHeader",
173 Handle::EmHeader => "zdwire.EmHeader",
174 Handle::Pid => "zdwire.Pid",
175 Handle::TryConstruct => "zdwire.TryConstruct",
176 Handle::ReaderMark => "zdwire.ReaderMark",
177 Handle::PidRead => "zdwire.PidRead",
178 Handle::EmHeaderRead => "zdwire.EmHeaderRead",
179 })
180 }
181
182 fn code_point(value: Self::Expr, _narrow: bool) -> Self::Expr {
185 value
186 }
187
188 fn constant(which: Constant) -> Self::Expr {
192 match which {
193 Constant::WcharWidth2 => plain(d::Expr::int(2)),
194 Constant::WcharWidth4 => plain(d::Expr::int(4)),
195 Constant::WcharFixed => Self::text("fixed"),
196 Constant::WcharGiopLengthPrefixed => Self::text("giop-length-prefixed"),
197 Constant::WstringUnitsStream => Self::text("stream"),
198 Constant::WstringUnitsBigEndianAlways => Self::text("big-endian-always"),
199 Constant::WstringUnitsByteOrderMark => Self::text("byte-order-mark"),
200 Constant::WstringUnitsHostUnswapped => Self::text("host-unswapped"),
201 Constant::WstringSpecification => Self::text("specification"),
202 Constant::WstringCharacterCount => Self::text("character-count"),
203 Constant::WstringCharacterCountTerminated => Self::text("character-count-terminated"),
204 Constant::WstringSpecificationWideUnits => Self::text("specification-wide-units"),
205 Constant::WstringRosTypeSupport => Self::text("ros-type-support"),
206 Constant::WstringOctetsTerminated2 => Self::text("octets/terminated/2"),
207 Constant::WstringOctetsTerminated4 => Self::text("octets/terminated/4"),
208 Constant::WstringCharactersTerminated2 => Self::text("characters/terminated/2"),
209 Constant::FixedDeclared => Self::text("declared"),
210 Constant::FixedValuePrecision => Self::text("value-precision"),
211 Constant::FixedValueStringDigits => Self::text("value-string-digits"),
212 Constant::ParameterMember => Self::runtime_constant("ParameterMember"),
213 Constant::ParameterOptional => Self::runtime_constant("ParameterOptional"),
214 Constant::TryConstructDiscard => Self::runtime_constant("TryConstructDiscard"),
215 Constant::TryConstructTrim => Self::runtime_constant("TryConstructTrim"),
216 Constant::TryConstructUseDefault => Self::runtime_constant("TryConstructUseDefault"),
217 Constant::StatusOk => Self::runtime_constant("StatusOk"),
218 Constant::StatusDiscarded => Self::runtime_constant("StatusDiscarded"),
219 Constant::StatusImpossibleLength => Self::runtime_constant("StatusImpossibleLength"),
220 Constant::StatusOutOfRange => Self::runtime_constant("StatusOutOfRange"),
221 Constant::StatusTruncated => Self::runtime_constant("StatusTruncated"),
222 }
223 }
224
225 fn unsigned_holder(bits: u16) -> Self::Type {
228 d::Type::Primitive(crate::adapter::d::d_holder(bits))
229 }
230
231 fn value_type(ast: &Ast, id: Id<TypeNode>) -> Self::Type {
232 #[allow(clippy::manual_unwrap_or_default, clippy::manual_unwrap_or)]
239 match d_value_type(ast, id) {
240 Ok(type_) => type_,
241 Err(_) => d::Type::Primitive(d::Primitive::Void),
242 }
243 }
244
245 fn type_name(ast: &Ast, id: Id<TypeNode>) -> String {
246 type_tag(ast, id, 0)
247 }
248
249 fn map_entry_name(ast: &Ast, id: Id<TypeNode>) -> String {
254 d_map_entry_name(ast, id).unwrap_or_else(|_| format!("ZdUnresolvedEntry{}", id.slot()))
255 }
256
257 fn module_prefix(_ast: &Ast, _id: Id<TypeNode>) -> String {
262 String::new()
263 }
264
265 fn escape(name: &str) -> String {
268 field_name(name)
269 }
270
271 fn inherited_path(depth: usize) -> Option<String> {
273 Some(format!("{}.", field_name("parent")).repeat(depth))
274 }
275
276 fn name(text: &str) -> Self::Expr {
279 plain(d::Expr::Name(Ident::new(text)))
280 }
281
282 fn int(value: i128) -> Self::Expr {
283 plain(d::Expr::int(value))
284 }
285
286 fn literal(value: Literal) -> Self::Expr {
289 let Literal::Int(text) = &value else {
290 return plain(d::Expr::Literal(value));
291 };
292 match text.as_str() {
293 "true" => plain(d::Expr::Literal(Literal::Bool(true))),
294 "false" => plain(d::Expr::Literal(Literal::Bool(false))),
295 _ => plain(d::Expr::Literal(value)),
296 }
297 }
298
299 fn wide_int(value: i128) -> Self::Expr {
318 if value > i128::from(i64::MAX) {
319 return plain(d::Expr::suffixed_int(value, "UL"));
320 }
321 if value == i128::from(i64::MIN) {
322 return plain(d::Expr::Literal(Literal::Int("long.min".to_string())));
323 }
324 if value > i128::from(i32::MAX) || value < i128::from(i32::MIN) {
325 return plain(d::Expr::suffixed_int(value, "L"));
326 }
327 plain(d::Expr::int(value))
328 }
329
330 fn unsigned_int(value: i128) -> Self::Expr {
334 Self::wide_int(value)
335 }
336
337 fn wide_unsigned(value: u64) -> Self::Expr {
341 plain(d::Expr::suffixed_int(i128::from(value), "UL"))
342 }
343
344 fn wide_signed(value: i128) -> Self::Expr {
346 plain(d::Expr::suffixed_int(value, "L"))
347 }
348
349 fn member(base: &str, field: &str) -> Self::Expr {
352 plain(Self::dot(d::Expr::Name(Ident::new(base)), field))
353 }
354
355 fn whole(base: &str) -> Self::Expr {
356 plain(d::Expr::Name(Ident::new(base)))
357 }
358
359 fn field_of(value: Self::Expr, field: &str) -> Self::Expr {
360 plain(Self::dot(inner(value), field))
361 }
362
363 fn header_field(value: Self::Expr, field: &str) -> Self::Expr {
366 plain(Self::dot(inner(value), &Self::pascal(field)))
367 }
368
369 fn index(value: Self::Expr, at: Self::Expr) -> Self::Expr {
370 plain(d::Expr::Index {
371 value: Box::new(inner(value)),
372 index: Box::new(inner(at)),
373 })
374 }
375
376 fn count_of(base: &str, fixed: Option<u64>) -> Self::Expr {
380 match fixed {
381 Some(bound) => plain(d::Expr::int(i128::from(bound))),
382 None => plain(d::Expr::Cast {
383 type_: Box::new(d::Type::Primitive(d::Primitive::UInt)),
384 value: Box::new(Self::dot(d::Expr::Name(Ident::new(base)), "length")),
385 }),
386 }
387 }
388
389 fn elements(base: &str) -> Self::Expr {
391 plain(d::Expr::Name(Ident::new(base)))
392 }
393
394 fn case_member(base: &str, field: &str) -> Self::Expr {
397 Self::member(base, field)
398 }
399
400 fn entry_half(entry: Self::Expr, key: bool) -> Self::Expr {
403 plain(Self::dot(inner(entry), if key { "key" } else { "value" }))
404 }
405
406 fn absent() -> Self::Expr {
407 plain(d::Expr::Literal(Literal::Null))
408 }
409
410 fn materialised(_value: Self::Expr) -> Option<Self::Expr> {
413 None
414 }
415
416 fn optional_value(_ast: &Ast, _id: Id<TypeNode>, base: &str, field: &str) -> Self::Expr {
420 plain(Self::dot(inner(Self::member(base, field)), "get"))
421 }
422
423 fn present(base: &str, field: &str) -> Self::Expr {
425 plain(d::Expr::Unary {
426 op: "!",
427 value: Box::new(Self::dot(inner(Self::member(base, field)), "isNull")),
428 })
429 }
430
431 fn set_present(base: &str, field: &str, present: bool) -> Vec<Self::Stmt> {
435 if present {
436 return Vec::new();
437 }
438 vec![d::Stmt::Expr(Self::call_expr(
439 Self::dot(inner(Self::member(base, field)), "nullify"),
440 Vec::new(),
441 ))]
442 }
443
444 fn optional_destination(base: &str, field: &str) -> (Vec<Self::Stmt>, Self::Expr) {
447 (
448 Vec::new(),
449 DExpr::OptionalSlot(inner(Self::member(base, field))),
450 )
451 }
452
453 fn holds_a_cycle_externally() -> bool {
458 true
459 }
460
461 fn external_value(
464 _ast: &Ast,
465 _id: Id<TypeNode>,
466 base: &str,
467 field: &str,
468 _optional: bool,
469 ) -> Self::Expr {
470 plain(d::Expr::Unary {
471 op: "*",
472 value: Box::new(inner(Self::member(base, field))),
473 })
474 }
475
476 fn external_destination(
479 base: &str,
480 field: &str,
481 _optional: bool,
482 ) -> (Vec<Self::Stmt>, Self::Expr) {
483 (
484 Vec::new(),
485 DExpr::ExternalSlot(inner(Self::member(base, field))),
486 )
487 }
488
489 fn external_case_value(_ast: &Ast, _id: Id<TypeNode>, base: &str, field: &str) -> Self::Expr {
493 plain(d::Expr::Unary {
494 op: "*",
495 value: Box::new(inner(Self::case_member(base, field))),
496 })
497 }
498
499 fn external_case_destination(base: &str, field: &str) -> (Vec<Self::Stmt>, Self::Expr) {
503 (
504 Vec::new(),
505 DExpr::ExternalSlot(inner(Self::case_member(base, field))),
506 )
507 }
508
509 fn external_present(base: &str, field: &str) -> Self::Expr {
512 plain(d::Expr::Binary {
513 op: "!is",
514 lhs: Box::new(inner(Self::member(base, field))),
515 rhs: Box::new(d::Expr::Literal(Literal::Null)),
516 })
517 }
518
519 fn external_set_present(base: &str, field: &str, present: bool) -> Vec<Self::Stmt> {
521 if present {
522 return Vec::new();
523 }
524 vec![d::Stmt::Assign {
525 place: inner(Self::member(base, field)),
526 value: d::Expr::Literal(Literal::Null),
527 }]
528 }
529
530 fn binary(op: &'static str, lhs: Self::Expr, rhs: Self::Expr) -> Self::Expr {
535 plain(d::Expr::Binary {
536 op,
537 lhs: Box::new(inner(lhs)),
538 rhs: Box::new(inner(rhs)),
539 })
540 }
541
542 fn unary(op: &'static str, value: Self::Expr) -> Self::Expr {
543 plain(d::Expr::Unary {
544 op,
545 value: Box::new(inner(value)),
546 })
547 }
548
549 fn paren(value: Self::Expr) -> Self::Expr {
550 plain(d::Expr::Paren(Box::new(inner(value))))
551 }
552
553 fn cast(type_: Self::Type, value: Self::Expr) -> Self::Expr {
559 if type_ == d::Type::named(SIGNED_CHAR) {
560 return plain(d::Expr::Cast {
561 type_: Box::new(d::Type::Primitive(d::Primitive::Byte)),
562 value: Box::new(inner(value)),
563 });
564 }
565 if type_ == d::Type::Primitive(d::Primitive::Bool) {
566 if let DExpr::Plain(d::Expr::Literal(Literal::Int(text))) = &value {
567 return plain(d::Expr::Literal(Literal::Bool(text != "0")));
568 }
569 }
570 plain(d::Expr::Cast {
571 type_: Box::new(type_),
572 value: Box::new(inner(value)),
573 })
574 }
575
576 fn handoff(value: Self::Expr, _form: Handoff) -> Self::Expr {
579 value
580 }
581
582 fn call(callee: &str, args: Vec<Self::Expr>) -> Self::Expr {
587 let arguments: Vec<d::Expr> = args.into_iter().map(inner).collect();
588 if callee == "strcmp" {
589 return plain(Self::call_expr(Self::runtime_name("Strcmp"), arguments));
590 }
591 plain(Self::call_expr(
592 d::Expr::Name(Ident::new(callee)),
593 arguments,
594 ))
595 }
596
597 fn runtime(receiver: &str, method: &str, args: Vec<Self::Expr>) -> Self::Expr {
603 if method == "read_pid" && args.is_empty() {
604 return Self::runtime(
605 receiver,
606 "read_pid_as",
607 vec![Self::constant(Constant::ParameterMember)],
608 );
609 }
610 plain(Self::call_expr(
611 Self::dot(d::Expr::Name(Ident::new(receiver)), &Self::pascal(method)),
612 args.into_iter().map(inner).collect(),
613 ))
614 }
615
616 fn runtime_static(method: &str, args: Vec<Self::Expr>) -> Self::Expr {
620 if method == "pid_is_user_member" {
621 let mut arguments = args.into_iter().map(inner);
622 if let Some(header) = arguments.next() {
623 return plain(Self::call_expr(
624 Self::dot(header, "IsUserMember"),
625 Vec::new(),
626 ));
627 }
628 return plain(Self::call_expr(
632 Self::runtime_name("IsUserMember"),
633 Vec::new(),
634 ));
635 }
636 plain(Self::call_expr(
637 Self::runtime_name(&Self::pascal(method)),
638 args.into_iter().map(inner).collect(),
639 ))
640 }
641
642 fn carries_hdds_axes() -> bool {
648 true
649 }
650
651 fn declare(type_: Self::Type, name: &str, value: Option<Self::Expr>) -> Self::Stmt {
657 d::Stmt::Var {
658 name: Ident::new(name),
659 type_: Some(type_),
660 value: value.map(inner),
661 }
662 }
663
664 fn perform(value: Self::Expr) -> Self::Stmt {
668 if let DExpr::Plain(d::Expr::Binary { op: "=", lhs, rhs }) = value {
669 return d::Stmt::Assign {
670 place: *lhs,
671 value: *rhs,
672 };
673 }
674 d::Stmt::Expr(inner(value))
675 }
676
677 fn give_back(value: Option<Self::Expr>) -> Self::Stmt {
679 d::Stmt::Return(Some(match value {
680 Some(value) => inner(value),
681 None => d::Expr::Name(Ident::new("v")),
682 }))
683 }
684
685 fn when(
686 condition: Self::Expr,
687 then: Self::Block,
688 otherwise: Option<Self::Block>,
689 ) -> Self::Stmt {
690 d::Stmt::If {
691 condition: inner(condition),
692 then,
693 otherwise: otherwise.filter(|body| !body.is_empty()),
694 }
695 }
696
697 fn count_up(counter: &str, bound: Self::Expr, body: Self::Block) -> Self::Stmt {
701 d::Stmt::For {
702 counter: Ident::new(counter),
703 type_: Box::new(d::Type::Primitive(d::Primitive::UInt)),
704 bound: Box::new(inner(bound)),
705 body,
706 }
707 }
708
709 fn until(condition: Self::Expr, body: Self::Block) -> Self::Stmt {
710 d::Stmt::While {
711 condition: inner(condition),
712 body,
713 }
714 }
715
716 fn leave() -> Self::Stmt {
717 d::Stmt::Break
718 }
719
720 fn note(doc: Doc) -> Self::Stmt {
721 d::Stmt::Comment(doc)
722 }
723
724 fn drop_value(value: Self::Expr) -> Self::Stmt {
727 d::Stmt::Expr(d::Expr::Cast {
728 type_: Box::new(d::Type::Primitive(d::Primitive::Void)),
729 value: Box::new(inner(value)),
730 })
731 }
732
733 fn mark_used(name: &str) -> Vec<Self::Stmt> {
736 vec![d::Stmt::Expr(d::Expr::Cast {
737 type_: Box::new(d::Type::Primitive(d::Primitive::Void)),
738 value: Box::new(d::Expr::Name(Ident::new(name))),
739 })]
740 }
741
742 fn read_call(
747 callee: &str,
748 place: Self::Expr,
749 _form: Handoff,
750 behaviour: Self::Expr,
751 ) -> Self::Stmt {
752 let decoded = Self::call_expr(
753 d::Expr::Name(Ident::new(callee)),
754 vec![d::Expr::Name(Ident::new("r")), inner(behaviour)],
755 );
756 match place {
757 DExpr::OptionalSlot(field) => d::Stmt::Assign {
758 place: field,
759 value: Self::call_expr(Self::runtime_name("zdNullable"), vec![decoded]),
760 },
761 DExpr::ExternalSlot(field) => d::Stmt::Assign {
762 place: field,
763 value: Self::call_expr(Self::runtime_name("zdPtr"), vec![decoded]),
764 },
765 DExpr::Plain(place) => d::Stmt::Assign {
766 place,
767 value: decoded,
768 },
769 }
770 }
771
772 fn read_forward(callee: &str) -> Self::Stmt {
774 Self::read_call(
775 callee,
776 Self::whole("v"),
777 Handoff::Value,
778 Self::name("zd_tc"),
779 )
780 }
781
782 fn block(statements: Vec<Self::Stmt>) -> Self::Block {
783 statements
784 }
785
786 fn into_statements(block: Self::Block) -> Vec<Self::Stmt> {
787 block
788 }
789
790 fn make_room(
795 base: &str,
796 element: Self::Type,
797 count: Self::Expr,
798 _assigned_whole: bool,
799 fill: Vec<Self::Stmt>,
800 ) -> Vec<Self::Stmt> {
801 let mut out = vec![d::Stmt::Assign {
802 place: d::Expr::Name(Ident::new(base)),
803 value: d::Expr::NewSlice {
804 element: Box::new(element),
805 length: Box::new(inner(count)),
806 },
807 }];
808 out.extend(fill);
809 out
810 }
811
812 fn keep_first(base: &str, count: Self::Expr) -> Vec<Self::Stmt> {
815 vec![d::Stmt::Assign {
816 place: d::Expr::Name(Ident::new(base)),
817 value: d::Expr::SliceTo {
818 value: Box::new(d::Expr::Name(Ident::new(base))),
819 high: Box::new(inner(count)),
820 },
821 }]
822 }
823
824 fn sequence_element(
827 base: &str,
828 index: Self::Expr,
829 _element: Self::Type,
830 ) -> (Vec<Self::Stmt>, Self::Expr, Vec<Self::Stmt>) {
831 (
832 Vec::new(),
833 Self::index(Self::elements(base), index),
834 Vec::new(),
835 )
836 }
837
838 fn routine(spec: Routine<Self>) -> Option<Self::Decl> {
848 let body = spec.body?;
849 let mut params = vec![d::Param {
850 name: Ident::new(if spec.writing { "w" } else { "r" }),
851 type_: d::Type::named(if spec.writing {
852 "zdwire.Writer"
853 } else {
854 "zdwire.Reader"
855 }),
856 }];
857 if spec.writing {
858 params.push(d::Param {
859 name: Ident::new("v"),
860 type_: spec.sample.clone(),
861 });
862 }
863 for (type_, name) in spec.extra {
864 params.push(d::Param {
865 name: Ident::new(&name),
866 type_,
867 });
868 }
869 let (returns, body) = if spec.writing {
870 (None, body)
871 } else {
872 let defaulter = crate::default_d::defaulter_from_decoder(&spec.name);
876 let mut statements = vec![d::Stmt::Var {
877 name: Ident::new("v"),
878 type_: None,
879 value: Some(Self::call_expr(
880 d::Expr::Name(Ident::new(&defaulter)),
881 Vec::new(),
882 )),
883 }];
884 statements.extend(body);
885 statements.push(d::Stmt::Return(Some(d::Expr::Name(Ident::new("v")))));
886 (Some(spec.sample), statements)
887 };
888 Some(d::Decl::Func(d::FuncDecl {
889 doc: spec.doc,
890 name: Ident::new(&spec.name),
891 params,
892 returns,
893 body,
894 }))
895 }
896
897 fn default_into(
903 ast: &Ast,
904 id: Id<TypeNode>,
905 place: Self::Expr,
906 ) -> Result<Self::Stmt, EncodeError> {
907 let defaulted = Self::call_expr(
908 d::Expr::Name(Ident::new(&crate::default_d::defaulter_name(ast, id))),
909 Vec::new(),
910 );
911 Ok(match place {
916 DExpr::OptionalSlot(field) => d::Stmt::Assign {
917 place: field,
918 value: Self::call_expr(Self::runtime_name("zdNullable"), vec![defaulted]),
919 },
920 DExpr::ExternalSlot(field) => d::Stmt::Assign {
921 place: field,
922 value: Self::call_expr(Self::runtime_name("zdPtr"), vec![defaulted]),
923 },
924 DExpr::Plain(field) => d::Stmt::Assign {
925 place: field,
926 value: defaulted,
927 },
928 })
929 }
930
931 fn member_default(
936 ast: &Ast,
937 node: &MemberNode,
938 type_: Id<TypeNode>,
939 place: Self::Expr,
940 ) -> Result<Vec<Self::Stmt>, EncodeError> {
941 crate::default_d::member_default(ast, node, type_, inner(place))
942 }
943
944 fn enumerator_constant(ast: &Ast, id: Id<TypeNode>, enumerator: &str) -> Self::Expr {
948 plain(d::Expr::Name(Ident::new(&format!(
949 "{}.{}",
950 d_type_name(ast, id),
951 field_name(enumerator)
952 ))))
953 }
954}
955
956fn bound_tag(ast: &Ast, bound: &zerodds_ast::Bound) -> String {
976 match bound.expr() {
977 None => String::new(),
978 Some(expr) => match ast.eval_integral(expr) {
982 Ok(limit) => format!("_b{limit}"),
983 Err(_) => "_bx".to_string(),
987 },
988 }
989}
990
991#[must_use]
998pub fn type_tag(ast: &Ast, id: Id<TypeNode>, depth: usize) -> String {
999 if depth > MAX_TYPE_DEPTH {
1000 return "unresolved".to_string();
1001 }
1002 let node = match ast.type_(id) {
1003 Ok(node) => node,
1004 Err(_) => return "unresolved".to_string(),
1005 };
1006 match &node.kind {
1007 TypeKind::Primitive(kind) => kind.as_str().replace(' ', "_"),
1008 TypeKind::String {
1009 width: CharWidth::Char,
1010 bound,
1011 } => format!("string{}", bound_tag(ast, bound)),
1012 TypeKind::String {
1013 width: CharWidth::WChar,
1014 bound,
1015 } => format!("wstring{}", bound_tag(ast, bound)),
1016 TypeKind::Fixed { digits, scale } => format!("fixed_{digits}_{scale}"),
1017 TypeKind::Sequence { element, bound } => match element.resolved() {
1018 Some(element) => format!(
1019 "seq{}_{}",
1020 bound_tag(ast, bound),
1021 type_tag(ast, element, depth + 1)
1022 ),
1023 None => format!("seq_unresolved{}", bound_tag(ast, bound)),
1024 },
1025 TypeKind::Array { element, dims } => {
1026 let mut name = match element.resolved() {
1027 Some(element) => format!("arr_{}", type_tag(ast, element, depth + 1)),
1028 None => "arr_unresolved".to_string(),
1029 };
1030 for dim in dims {
1031 match ast.eval_integral(*dim) {
1032 Ok(length) => name.push_str(&format!("_{length}")),
1033 Err(_) => name.push_str("_x"),
1037 }
1038 }
1039 name
1040 }
1041 TypeKind::Map { key, value, bound } => {
1042 let half = |half: Option<Id<TypeNode>>| match half {
1043 Some(target) => type_tag(ast, target, depth + 1),
1044 None => "unresolved".to_string(),
1045 };
1046 format!(
1047 "map{}_{}_{}",
1048 bound_tag(ast, bound),
1049 half(key.resolved()),
1050 half(value.resolved())
1051 )
1052 }
1053 TypeKind::Alias { aliased } => match aliased.resolved() {
1057 Some(target) => type_tag(ast, target, depth + 1),
1058 None => "unresolved".to_string(),
1059 },
1060 TypeKind::ValueBox { boxed } => match boxed.resolved() {
1061 Some(target) => format!("box_{}", type_tag(ast, target, depth + 1)),
1062 None => "box_unresolved".to_string(),
1063 },
1064 TypeKind::Structure { .. }
1065 | TypeKind::Union { .. }
1066 | TypeKind::Enumeration { .. }
1067 | TypeKind::Bitmask { .. }
1068 | TypeKind::Bitset { .. }
1069 | TypeKind::Valuetype { .. }
1070 | TypeKind::Native => d_type_name(ast, id),
1071 TypeKind::Any => "any".to_string(),
1072 TypeKind::ValueBase => "valuebase".to_string(),
1073 TypeKind::ObjectRef { .. } => "objectref".to_string(),
1074 TypeKind::AnnotationType { .. } => "annotation".to_string(),
1075 }
1076}