1use super::{CodecTarget, Constant, Handle, Handoff, Routine, Scalar};
48use crate::adapter::ocaml::{
49 ocaml_enumerator_name, ocaml_map_entry_name, ocaml_type_name, ocaml_value_type,
50};
51use crate::encode::EncodeError;
52use zerodds_ast::{Ast, CharWidth, MemberNode, PrimitiveKind, TypeKind, TypeNode};
53use zerodds_ast_core::Id;
54use zerodds_lang_cst::common::{Doc, Literal};
55use zerodds_lang_cst::ocaml::{self, CodeExpr, CodecFn, CodecType, Stmt, ValueKind};
56
57#[derive(Debug, Clone, Copy, PartialEq, Eq)]
59pub struct OCaml;
60
61const MAX_TYPE_DEPTH: usize = 64;
63
64impl OCaml {
65 fn type_(text: &str, kind: ValueKind, default: &str) -> CodecType {
66 CodecType {
67 text: text.to_string(),
68 kind,
69 default: default.to_string(),
70 }
71 }
72
73 fn constant_text(text: &str, kind: ValueKind) -> CodeExpr {
74 CodeExpr::RuntimeConst {
75 text: text.to_string(),
76 kind,
77 }
78 }
79
80 fn policy(text: &str) -> CodeExpr {
81 CodeExpr::TextLit(text.to_string())
82 }
83}
84
85pub fn ocaml_type_text(node: &ocaml::Type) -> String {
89 match node {
90 ocaml::Type::Primitive(primitive) => primitive.as_str().to_string(),
91 ocaml::Type::Named(name) => name.as_str().to_string(),
92 ocaml::Type::Array(element) => format!("{} array", ocaml_type_text(element)),
93 ocaml::Type::Option(inner) => format!("{} option", ocaml_type_text(inner)),
94 ocaml::Type::Tuple(parts) => {
95 let rendered: Vec<String> = parts.iter().map(ocaml_type_text).collect();
96 format!("({})", rendered.join(" * "))
97 }
98 ocaml::Type::Qualified { module, name } => {
99 let mut out = String::new();
100 for segment in module {
101 out.push_str(segment.as_str());
102 out.push('.');
103 }
104 out.push_str(name.as_str());
105 out
106 }
107 }
108}
109
110pub fn kind_of(ast: &Ast, id: Id<TypeNode>, depth: usize) -> ValueKind {
116 if depth > MAX_TYPE_DEPTH {
117 return ValueKind::Aggregate;
118 }
119 let Ok(node) = ast.type_(id) else {
120 return ValueKind::Aggregate;
121 };
122 match &node.kind {
123 TypeKind::Primitive(kind) => match kind {
124 PrimitiveKind::Boolean => ValueKind::Bool,
125 PrimitiveKind::Octet
126 | PrimitiveKind::UInt8
127 | PrimitiveKind::Char
128 | PrimitiveKind::Int8
129 | PrimitiveKind::Int16
130 | PrimitiveKind::UInt16
131 | PrimitiveKind::WChar => ValueKind::Int,
132 PrimitiveKind::Int32 => ValueKind::Int32,
133 PrimitiveKind::UInt32 | PrimitiveKind::Int64 => ValueKind::Int64,
134 PrimitiveKind::UInt64 | PrimitiveKind::Float128 => ValueKind::Text,
135 PrimitiveKind::Float32 | PrimitiveKind::Float64 => ValueKind::Float,
136 },
137 TypeKind::String { .. } | TypeKind::Fixed { .. } => ValueKind::Text,
138 TypeKind::Enumeration { .. } => ValueKind::Enum(ocaml_type_name(ast, id)),
139 TypeKind::Bitmask { .. } => {
140 if ast.effective_bit_bound(id) <= 32 {
141 ValueKind::Int32
142 } else {
143 ValueKind::Int64
144 }
145 }
146 TypeKind::Alias { aliased } => aliased.resolved().map_or(ValueKind::Aggregate, |target| {
147 kind_of(ast, target, depth + 1)
148 }),
149 _ if depth > 8 => ValueKind::Aggregate,
155 TypeKind::Sequence { element, .. } => {
156 element.resolved().map_or(ValueKind::Aggregate, |target| {
157 ValueKind::ArrayOf(Box::new(kind_of(ast, target, depth + 1)))
158 })
159 }
160 TypeKind::Array { element, dims } => match element.resolved() {
161 Some(target) => {
162 let mut kind = kind_of(ast, target, depth + 1);
163 for _ in dims {
164 kind = ValueKind::ArrayOf(Box::new(kind));
165 }
166 kind
167 }
168 None => ValueKind::Aggregate,
169 },
170 TypeKind::Map { key, value, .. } => {
171 let half = |half: Option<Id<TypeNode>>| {
172 half.map_or(ValueKind::Aggregate, |target| {
173 kind_of(ast, target, depth + 1)
174 })
175 };
176 ValueKind::ArrayOf(Box::new(ValueKind::RecordOf(vec![
177 ("key".to_string(), half(key.resolved())),
178 ("value".to_string(), half(value.resolved())),
179 ])))
180 }
181 TypeKind::Structure { .. } | TypeKind::Valuetype { .. } => {
182 let mut fields = Vec::new();
183 if let Some(base) = crate::adapter::c::struct_base(ast, id) {
185 fields.push((ocaml::lower_ident("parent"), kind_of(ast, base, depth + 1)));
186 }
187 for member in ast.members_of(id).iter().copied() {
188 let Ok(member_node) = ast.member(member) else {
189 continue;
190 };
191 let Some(target) = member_node.type_.resolved() else {
192 continue;
193 };
194 let mut kind = kind_of(ast, target, depth + 1);
195 if member_node.facets.is_optional() {
196 kind = ValueKind::OptionOf(Box::new(kind));
197 }
198 fields.push((ocaml::lower_ident(&member_node.name), kind));
199 }
200 ValueKind::RecordOf(fields)
201 }
202 TypeKind::Union { discriminator, .. } => {
203 let mut fields = Vec::new();
204 if let Some(disc) = discriminator.resolved() {
205 fields.push(("_d".to_string(), kind_of(ast, disc, depth + 1)));
206 }
207 for case in ast.cases_of(id) {
208 let Ok(case_node) = ast.case(*case) else {
209 continue;
210 };
211 let Ok(member) = ast.member(case_node.member) else {
212 continue;
213 };
214 let Some(target) = member.type_.resolved() else {
215 continue;
216 };
217 fields.push((
218 ocaml::lower_ident(&member.name),
219 ValueKind::OptionOf(Box::new(kind_of(ast, target, depth + 1))),
220 ));
221 }
222 ValueKind::RecordOf(fields)
223 }
224 TypeKind::Bitset { .. } => {
225 let mut fields = Vec::new();
226 for field in &ast.all_bitfields_of(id) {
227 let Ok(field_node) = ast.bitfield(*field) else {
228 continue;
229 };
230 let Some(field_name) = field_node.name.as_ref() else {
231 continue;
232 };
233 let kind = match crate::adapter::ocaml::ocaml_holder(field_node.bits) {
234 ocaml::Primitive::Int32 => ValueKind::Int32,
235 ocaml::Primitive::Int64 => ValueKind::Int64,
236 _ => ValueKind::Int,
237 };
238 fields.push((ocaml::lower_ident(field_name), kind));
239 }
240 ValueKind::RecordOf(fields)
241 }
242 _ => ValueKind::Aggregate,
243 }
244}
245
246pub fn default_of(ast: &Ast, id: Id<TypeNode>) -> String {
252 match kind_of(ast, id, 0) {
253 ValueKind::Bool => "false".to_string(),
254 ValueKind::Int => "0".to_string(),
255 ValueKind::Int32 => "0l".to_string(),
256 ValueKind::Int64 => "0L".to_string(),
257 ValueKind::Float => "0.0".to_string(),
258 ValueKind::Text => "\"\"".to_string(),
259 _ => format!("{} ()", crate::default_ocaml::defaulter_name(ast, id)),
260 }
261}
262
263impl CodecTarget for OCaml {
264 type Expr = CodeExpr;
265 type Stmt = Stmt;
266 type Block = Vec<Stmt>;
267 type Type = CodecType;
268 type Decl = CodecFn;
269
270 fn scalar(kind: Scalar) -> Self::Type {
279 match kind {
280 Scalar::Bool => Self::type_("bool", ValueKind::Bool, "false"),
281 Scalar::Char
282 | Scalar::Int8
283 | Scalar::UInt8
284 | Scalar::Int16
285 | Scalar::UInt16
286 | Scalar::UInt32
287 | Scalar::Index
288 | Scalar::Size => Self::type_("int", ValueKind::Int, "0"),
289 Scalar::Int32 => Self::type_("int32", ValueKind::Int32, "0l"),
290 Scalar::Int64 => Self::type_("int64", ValueKind::Int64, "0L"),
291 Scalar::UInt64 => Self::type_(ocaml::UNSIGNED_HOLDER, ValueKind::Int64, "0L"),
296 Scalar::Float | Scalar::Double => Self::type_("float", ValueKind::Float, "0.0"),
297 Scalar::LongDouble => Self::type_("string", ValueKind::Text, "\"0.0\""),
298 }
299 }
300
301 fn named(name: &str) -> Self::Type {
305 Self::type_(name, ValueKind::Aggregate, "zd_unsupported_default")
306 }
307
308 fn nothing() -> Self::Type {
309 Self::type_("unit", ValueKind::UnitValue, "()")
310 }
311
312 fn handle(kind: Handle) -> Self::Type {
315 match kind {
316 Handle::DHeader => Self::type_(
317 "Zdwire.dheader",
318 ValueKind::Handle("dheader"),
319 "Zdwire.no_dheader ()",
320 ),
321 Handle::EmHeader => Self::type_(
322 "Zdwire.emheader",
323 ValueKind::Handle("emheader"),
324 "Zdwire.emheader_none",
325 ),
326 Handle::Pid => Self::type_("Zdwire.pid", ValueKind::Handle("pid"), "Zdwire.pid_none"),
327 Handle::TryConstruct => Self::type_(
328 "Zdwire.try_construct",
329 ValueKind::Handle("try_construct"),
330 "Zdwire.Discard",
331 ),
332 Handle::ReaderMark => Self::type_(
333 "Zdwire.reader_mark",
334 ValueKind::Handle("reader_mark"),
335 "Zdwire.mark_none",
336 ),
337 Handle::PidRead => Self::type_(
338 "Zdwire.pid_read",
339 ValueKind::Handle("pid_read"),
340 "Zdwire.pid_read_none",
341 ),
342 Handle::EmHeaderRead => Self::type_(
343 "Zdwire.emheader_read",
344 ValueKind::Handle("emheader_read"),
345 "Zdwire.emheader_read_none",
346 ),
347 }
348 }
349
350 fn code_point(value: Self::Expr, _narrow: bool) -> Self::Expr {
353 value
354 }
355
356 fn constant(which: Constant) -> Self::Expr {
362 match which {
363 Constant::WcharWidth2 => CodeExpr::Int(2),
364 Constant::WcharWidth4 => CodeExpr::Int(4),
365 Constant::WcharFixed => Self::policy("fixed"),
366 Constant::WcharGiopLengthPrefixed => Self::policy("giop-length-prefixed"),
367 Constant::WstringUnitsStream => Self::policy("stream"),
368 Constant::WstringUnitsBigEndianAlways => Self::policy("big-endian-always"),
369 Constant::WstringUnitsByteOrderMark => Self::policy("byte-order-mark"),
370 Constant::WstringUnitsHostUnswapped => Self::policy("host-unswapped"),
371 Constant::WstringSpecification => Self::policy("specification"),
372 Constant::WstringCharacterCount => Self::policy("character-count"),
373 Constant::WstringCharacterCountTerminated => Self::policy("character-count-terminated"),
374 Constant::WstringSpecificationWideUnits => Self::policy("specification-wide-units"),
375 Constant::WstringRosTypeSupport => Self::policy("ros-type-support"),
376 Constant::WstringOctetsTerminated2 => Self::policy("octets/terminated/2"),
377 Constant::WstringOctetsTerminated4 => Self::policy("octets/terminated/4"),
378 Constant::WstringCharactersTerminated2 => Self::policy("characters/terminated/2"),
379 Constant::FixedDeclared => Self::policy("declared"),
380 Constant::FixedValuePrecision => Self::policy("value-precision"),
381 Constant::FixedValueStringDigits => Self::policy("value-string-digits"),
382 Constant::ParameterMember => {
383 Self::constant_text("Zdwire.Role_member", ValueKind::Handle("role"))
384 }
385 Constant::ParameterOptional => {
386 Self::constant_text("Zdwire.Role_optional", ValueKind::Handle("role"))
387 }
388 Constant::TryConstructDiscard => {
389 Self::constant_text("Zdwire.Discard", ValueKind::Handle("try_construct"))
390 }
391 Constant::TryConstructTrim => {
392 Self::constant_text("Zdwire.Trim", ValueKind::Handle("try_construct"))
393 }
394 Constant::TryConstructUseDefault => {
395 Self::constant_text("Zdwire.Use_default", ValueKind::Handle("try_construct"))
396 }
397 Constant::StatusOk => Self::constant_text("Zdwire.St_ok", ValueKind::Handle("status")),
398 Constant::StatusDiscarded => {
399 Self::constant_text("Zdwire.St_discarded", ValueKind::Handle("status"))
400 }
401 Constant::StatusImpossibleLength => {
402 Self::constant_text("Zdwire.St_impossible_length", ValueKind::Handle("status"))
403 }
404 Constant::StatusOutOfRange => {
405 Self::constant_text("Zdwire.St_out_of_range", ValueKind::Handle("status"))
406 }
407 Constant::StatusTruncated => {
408 Self::constant_text("Zdwire.St_truncated", ValueKind::Handle("status"))
409 }
410 }
411 }
412
413 fn unsigned_less(_octets: u8, left: Self::Expr, right: Self::Expr) -> Self::Expr {
417 CodeExpr::Static {
418 method: "u64_less".to_string(),
419 args: vec![left, right],
420 }
421 }
422
423 fn carries_hdds_axes() -> bool {
433 true
434 }
435
436 fn unsigned_holder(bits: u16) -> Self::Type {
438 match crate::adapter::ocaml::ocaml_holder(bits) {
439 ocaml::Primitive::Int32 => Self::type_("int32", ValueKind::Int32, "0l"),
440 ocaml::Primitive::Int64 => Self::type_("int64", ValueKind::Int64, "0L"),
441 _ => Self::type_("int", ValueKind::Int, "0"),
442 }
443 }
444
445 fn value_type(ast: &Ast, id: Id<TypeNode>) -> Self::Type {
446 let text = match ocaml_value_type(ast, id) {
447 Ok(type_) => ocaml_type_text(&type_),
448 Err(_) => "zd_no_ocaml_form".to_string(),
452 };
453 CodecType {
454 text,
455 kind: kind_of(ast, id, 0),
456 default: default_of(ast, id),
457 }
458 }
459
460 fn type_name(ast: &Ast, id: Id<TypeNode>) -> String {
461 type_tag(ast, id, 0)
462 }
463
464 fn map_entry_name(ast: &Ast, id: Id<TypeNode>) -> String {
465 ocaml_map_entry_name(ast, id)
466 }
467
468 fn map_entry_type(ast: &Ast, id: Id<TypeNode>) -> Self::Type {
472 let name = ocaml_map_entry_name(ast, id);
473 let default = match ast.type_(id).map(|node| node.kind.clone()) {
474 Ok(TypeKind::Map { key, value, .. }) => match (key.resolved(), value.resolved()) {
475 (Some(key), Some(value)) => format!(
476 "({{ key = {}; value = {} }} : {name})",
477 default_of(ast, key),
478 default_of(ast, value)
479 ),
480 _ => "zd_unsupported_default".to_string(),
481 },
482 _ => "zd_unsupported_default".to_string(),
483 };
484 CodecType {
485 text: name,
486 kind: ValueKind::Aggregate,
487 default,
488 }
489 }
490
491 fn module_prefix(_ast: &Ast, _id: Id<TypeNode>) -> String {
494 String::new()
495 }
496
497 fn escape(name: &str) -> String {
498 ocaml::lower_ident(name)
499 }
500
501 fn inherited_path(depth: usize) -> Option<String> {
503 Some(format!("{}.", ocaml::lower_ident("parent")).repeat(depth))
504 }
505
506 fn name(text: &str) -> Self::Expr {
509 CodeExpr::Name(text.to_string())
510 }
511
512 fn int(value: i128) -> Self::Expr {
513 CodeExpr::Int(value)
514 }
515
516 fn wide_int(value: i128) -> Self::Expr {
519 CodeExpr::Int(value)
520 }
521
522 fn unsigned_int(value: i128) -> Self::Expr {
524 CodeExpr::Int(value)
525 }
526
527 #[allow(clippy::cast_possible_wrap)]
530 fn wide_unsigned(value: u64) -> Self::Expr {
531 CodeExpr::Int64Lit(value as i64)
532 }
533
534 #[allow(clippy::cast_possible_truncation)]
535 fn wide_signed(value: i128) -> Self::Expr {
536 CodeExpr::Int64Lit(value as i64)
537 }
538
539 fn literal(value: Literal) -> Self::Expr {
542 match value {
543 Literal::Int(text) => match text.as_str() {
544 "true" => CodeExpr::BoolLit(true),
545 "false" => CodeExpr::BoolLit(false),
546 other => other
547 .parse::<i128>()
548 .map_or_else(|_| CodeExpr::TextLit(other.to_string()), CodeExpr::Int),
549 },
550 Literal::Bool(flag) => CodeExpr::BoolLit(flag),
551 Literal::Str(text) => CodeExpr::TextLit(text),
552 Literal::Float(text) => CodeExpr::FloatLit(text),
553 Literal::Char(ch) => CodeExpr::Int(i128::from(u32::from(ch))),
554 Literal::Bytes(_) | Literal::Null => CodeExpr::Absent,
555 }
556 }
557
558 fn call(callee: &str, args: Vec<Self::Expr>) -> Self::Expr {
561 if callee == "strcmp" {
562 return CodeExpr::Static {
563 method: "strcmp".to_string(),
564 args,
565 };
566 }
567 CodeExpr::Call {
568 callee: callee.to_string(),
569 args,
570 }
571 }
572
573 fn runtime(receiver: &str, method: &str, args: Vec<Self::Expr>) -> Self::Expr {
577 if method == "read_pid" && args.is_empty() {
582 return Self::runtime(
583 receiver,
584 "read_pid_as",
585 vec![Self::constant(Constant::ParameterMember)],
586 );
587 }
588 let receiver = if receiver == "r" { "r" } else { "w" };
589 CodeExpr::Runtime {
590 receiver,
591 method: method.to_string(),
592 args,
593 }
594 }
595
596 fn runtime_static(method: &str, args: Vec<Self::Expr>) -> Self::Expr {
598 CodeExpr::Static {
599 method: method.to_string(),
600 args,
601 }
602 }
603
604 fn member(base: &str, field: &str) -> Self::Expr {
605 CodeExpr::Member {
606 base: base.to_string(),
607 field: field.to_string(),
608 case: false,
609 }
610 }
611
612 fn whole(base: &str) -> Self::Expr {
613 CodeExpr::Whole(base.to_string())
614 }
615
616 fn field_of(value: Self::Expr, field: &str) -> Self::Expr {
617 CodeExpr::HeaderField {
618 value: Box::new(value),
619 field: field.to_string(),
620 }
621 }
622
623 fn index(value: Self::Expr, at: Self::Expr) -> Self::Expr {
624 CodeExpr::Index {
625 base: Box::new(value),
626 index: Box::new(at),
627 }
628 }
629
630 fn count_of(base: &str, fixed: Option<u64>) -> Self::Expr {
631 match fixed {
632 Some(bound) => CodeExpr::Int(i128::from(bound)),
633 None => CodeExpr::CountOf(base.to_string()),
634 }
635 }
636
637 fn elements(base: &str) -> Self::Expr {
638 CodeExpr::Elements(base.to_string())
639 }
640
641 fn case_member(base: &str, field: &str) -> Self::Expr {
644 CodeExpr::Member {
645 base: base.to_string(),
646 field: field.to_string(),
647 case: true,
648 }
649 }
650
651 fn entry_half(entry: Self::Expr, key: bool) -> Self::Expr {
652 CodeExpr::EntryHalf {
653 entry: Box::new(entry),
654 key,
655 }
656 }
657
658 fn absent() -> Self::Expr {
659 CodeExpr::Absent
660 }
661
662 fn materialised(_value: Self::Expr) -> Option<Self::Expr> {
665 None
666 }
667
668 fn optional_value(_ast: &Ast, _id: Id<TypeNode>, base: &str, field: &str) -> Self::Expr {
671 CodeExpr::OptionGet(Box::new(Self::member(base, field)))
672 }
673
674 fn present(base: &str, field: &str) -> Self::Expr {
676 CodeExpr::IsSome {
677 base: base.to_string(),
678 field: field.to_string(),
679 }
680 }
681
682 fn set_present(base: &str, field: &str, present: bool) -> Vec<Self::Stmt> {
685 if present {
686 return Vec::new();
687 }
688 vec![Stmt::Assign {
689 place: Self::member(base, field),
690 value: CodeExpr::Absent,
691 }]
692 }
693
694 fn clear_union_cases(base: &str, fields: &[String]) -> Vec<Self::Stmt> {
698 fields
699 .iter()
700 .flat_map(|field| Self::set_present(base, field, false))
701 .collect()
702 }
703
704 fn optional_destination(base: &str, field: &str) -> (Vec<Self::Stmt>, Self::Expr) {
706 (
707 Vec::new(),
708 CodeExpr::OptionSlot {
709 base: base.to_string(),
710 field: field.to_string(),
711 },
712 )
713 }
714
715 fn binary(op: &'static str, lhs: Self::Expr, rhs: Self::Expr) -> Self::Expr {
716 CodeExpr::Binary {
717 op,
718 lhs: Box::new(lhs),
719 rhs: Box::new(rhs),
720 }
721 }
722
723 fn unary(op: &'static str, value: Self::Expr) -> Self::Expr {
724 CodeExpr::Unary {
725 op,
726 value: Box::new(value),
727 }
728 }
729
730 fn paren(value: Self::Expr) -> Self::Expr {
731 CodeExpr::Paren(Box::new(value))
732 }
733
734 fn cast(type_: Self::Type, value: Self::Expr) -> Self::Expr {
738 CodeExpr::Convert {
739 target: type_,
740 value: Box::new(value),
741 }
742 }
743
744 fn handoff(value: Self::Expr, _form: Handoff) -> Self::Expr {
746 value
747 }
748
749 fn declare(type_: Self::Type, name: &str, value: Option<Self::Expr>) -> Self::Stmt {
753 Stmt::Let {
754 type_,
755 name: name.to_string(),
756 value,
757 }
758 }
759
760 fn perform(value: Self::Expr) -> Self::Stmt {
764 if let CodeExpr::Binary { op: "=", lhs, rhs } = value {
765 return Stmt::Assign {
766 place: *lhs,
767 value: *rhs,
768 };
769 }
770 Stmt::Perform(value)
771 }
772
773 fn give_back(_value: Option<Self::Expr>) -> Self::Stmt {
777 Stmt::Return
778 }
779
780 fn when(
781 condition: Self::Expr,
782 then: Self::Block,
783 otherwise: Option<Self::Block>,
784 ) -> Self::Stmt {
785 Stmt::When {
786 condition,
787 then,
788 otherwise: otherwise.filter(|body| !body.is_empty()),
789 }
790 }
791
792 fn count_up(counter: &str, bound: Self::Expr, body: Self::Block) -> Self::Stmt {
793 Stmt::For {
794 counter: counter.to_string(),
795 bound,
796 body,
797 }
798 }
799
800 fn until(condition: Self::Expr, body: Self::Block) -> Self::Stmt {
801 Stmt::While { condition, body }
802 }
803
804 fn leave() -> Self::Stmt {
807 Stmt::Leave
808 }
809
810 fn note(doc: Doc) -> Self::Stmt {
811 Stmt::Note(doc)
812 }
813
814 fn drop_value(value: Self::Expr) -> Self::Stmt {
816 Stmt::Discard(value)
817 }
818
819 fn mark_used(name: &str) -> Vec<Self::Stmt> {
822 vec![Stmt::Discard(CodeExpr::Name(name.to_string()))]
823 }
824
825 fn read_call(
828 callee: &str,
829 place: Self::Expr,
830 _form: Handoff,
831 behaviour: Self::Expr,
832 ) -> Self::Stmt {
833 Stmt::ReadInto {
834 callee: callee.to_string(),
835 place,
836 behaviour,
837 }
838 }
839
840 fn read_forward(callee: &str) -> Self::Stmt {
842 Stmt::ReadInto {
843 callee: callee.to_string(),
844 place: CodeExpr::Whole("v".to_string()),
845 behaviour: CodeExpr::Name("zd_tc".to_string()),
846 }
847 }
848
849 fn block(statements: Vec<Self::Stmt>) -> Self::Block {
850 statements
851 }
852
853 fn into_statements(block: Self::Block) -> Vec<Self::Stmt> {
854 block
855 }
856
857 fn make_room(
863 base: &str,
864 element: Self::Type,
865 count: Self::Expr,
866 _assigned_whole: bool,
867 fill: Vec<Self::Stmt>,
868 ) -> Vec<Self::Stmt> {
869 let mut out = vec![Stmt::Alloc {
870 base: base.to_string(),
871 element,
872 count,
873 }];
874 out.extend(fill);
875 out
876 }
877
878 fn keep_first(base: &str, count: Self::Expr) -> Vec<Self::Stmt> {
880 vec![Stmt::KeepFirst {
881 base: base.to_string(),
882 count,
883 }]
884 }
885
886 fn sequence_element(
889 base: &str,
890 index: Self::Expr,
891 _element: Self::Type,
892 ) -> (Vec<Self::Stmt>, Self::Expr, Vec<Self::Stmt>) {
893 (
894 Vec::new(),
895 Self::index(Self::elements(base), index),
896 Vec::new(),
897 )
898 }
899
900 fn storage(type_: Self::Type, name: &str) -> Self::Stmt {
904 if type_.text.starts_with("zd_map_entry_") {
905 return Stmt::Scratch {
906 name: name.to_string(),
907 };
908 }
909 Stmt::Let {
910 type_,
911 name: name.to_string(),
912 value: None,
913 }
914 }
915
916 fn routine(spec: Routine<Self>) -> Option<Self::Decl> {
922 let body = spec.body?;
923 let defaulter = if spec.writing {
924 None
925 } else {
926 Some(crate::default_ocaml::defaulter_from_decoder(&spec.name))
927 };
928 Some(CodecFn {
929 doc: spec.doc,
930 name: spec.name,
931 sample: spec.sample,
932 reading: !spec.writing,
933 defaulter,
934 extra: spec.extra,
935 body,
936 })
937 }
938
939 fn default_into(
945 ast: &Ast,
946 id: Id<TypeNode>,
947 place: Self::Expr,
948 ) -> Result<Self::Stmt, EncodeError> {
949 Ok(Stmt::Assign {
950 place,
951 value: CodeExpr::Call {
952 callee: crate::default_ocaml::defaulter_name(ast, id),
953 args: Vec::new(),
954 },
955 })
956 }
957
958 fn member_default(
963 ast: &Ast,
964 node: &MemberNode,
965 type_: Id<TypeNode>,
966 place: Self::Expr,
967 ) -> Result<Vec<Self::Stmt>, EncodeError> {
968 crate::default_ocaml::member_default(ast, node, type_, place)
969 }
970
971 fn enumerator_constant(ast: &Ast, id: Id<TypeNode>, enumerator: &str) -> Self::Expr {
974 CodeExpr::Construct(ocaml_enumerator_name(ast, id, enumerator))
975 }
976}
977
978fn bound_tag(ast: &Ast, bound: &zerodds_ast::Bound) -> String {
998 match bound.expr() {
999 None => String::new(),
1000 Some(expr) => match ast.eval_integral(expr) {
1004 Ok(limit) => format!("_b{limit}"),
1005 Err(_) => "_bx".to_string(),
1009 },
1010 }
1011}
1012
1013#[must_use]
1024pub fn type_tag(ast: &Ast, id: Id<TypeNode>, depth: usize) -> String {
1025 if depth > MAX_TYPE_DEPTH {
1026 return "unresolved".to_string();
1027 }
1028 let node = match ast.type_(id) {
1029 Ok(node) => node,
1030 Err(_) => return "unresolved".to_string(),
1031 };
1032 match &node.kind {
1033 TypeKind::Primitive(kind) => kind.as_str().replace(' ', "_"),
1034 TypeKind::String {
1035 width: CharWidth::Char,
1036 bound,
1037 } => format!("string{}", bound_tag(ast, bound)),
1038 TypeKind::String {
1039 width: CharWidth::WChar,
1040 bound,
1041 } => format!("wstring{}", bound_tag(ast, bound)),
1042 TypeKind::Fixed { digits, scale } => format!("fixed_{digits}_{scale}"),
1043 TypeKind::Sequence { element, bound } => match element.resolved() {
1044 Some(element) => format!(
1045 "seq{}_{}",
1046 bound_tag(ast, bound),
1047 type_tag(ast, element, depth + 1)
1048 ),
1049 None => format!("seq_unresolved{}", bound_tag(ast, bound)),
1050 },
1051 TypeKind::Array { element, dims } => {
1052 let mut name = match element.resolved() {
1053 Some(element) => format!("arr_{}", type_tag(ast, element, depth + 1)),
1054 None => "arr_unresolved".to_string(),
1055 };
1056 for dim in dims {
1057 match ast.eval_integral(*dim) {
1058 Ok(length) => name.push_str(&format!("_{length}")),
1059 Err(_) => name.push_str("_x"),
1060 }
1061 }
1062 name
1063 }
1064 TypeKind::Map { key, value, bound } => {
1065 let half = |half: Option<Id<TypeNode>>| match half {
1066 Some(target) => type_tag(ast, target, depth + 1),
1067 None => "unresolved".to_string(),
1068 };
1069 format!(
1070 "map{}_{}_{}",
1071 bound_tag(ast, bound),
1072 half(key.resolved()),
1073 half(value.resolved())
1074 )
1075 }
1076 TypeKind::Alias { aliased } => match aliased.resolved() {
1077 Some(target) => type_tag(ast, target, depth + 1),
1078 None => "unresolved".to_string(),
1079 },
1080 TypeKind::ValueBox { boxed } => match boxed.resolved() {
1081 Some(target) => format!("box_{}", type_tag(ast, target, depth + 1)),
1082 None => "box_unresolved".to_string(),
1083 },
1084 TypeKind::Structure { .. }
1085 | TypeKind::Union { .. }
1086 | TypeKind::Enumeration { .. }
1087 | TypeKind::Bitmask { .. }
1088 | TypeKind::Bitset { .. }
1089 | TypeKind::Valuetype { .. }
1090 | TypeKind::Native => ocaml_type_name(ast, id),
1091 TypeKind::Any => "any".to_string(),
1092 TypeKind::ValueBase => "valuebase".to_string(),
1093 TypeKind::ObjectRef { .. } => "objectref".to_string(),
1094 TypeKind::AnnotationType { .. } => "annotation".to_string(),
1095 }
1096}