1use super::{BitPatternSource, CodecTarget, Constant, Handle, Handoff, Routine, Scalar};
24use crate::adapter::c::{c_codec_tag, c_holder, c_map_entry_name, c_value_type, module_prefix};
25use crate::encode::EncodeError;
26use zerodds_ast::{Ast, MemberNode, TypeNode};
27use zerodds_ast_core::Id;
28use zerodds_lang_cst::c;
29use zerodds_lang_cst::common::{Doc, Ident, Literal};
30
31#[derive(Debug, Clone, Copy, PartialEq, Eq)]
33pub struct C;
34
35impl C {
36 const PREFIX: &'static str = "zdw_";
38}
39
40impl CodecTarget for C {
41 type Expr = c::Expr;
42 type Stmt = c::Statement;
43 type Block = c::Block;
44 type Type = c::Type;
45 type Decl = c::Decl;
46
47 fn scalar(kind: Scalar) -> Self::Type {
50 c::Type::Primitive(match kind {
51 Scalar::Index => c::Primitive::UInt32,
52 Scalar::Size => c::Primitive::Size,
53 Scalar::Bool => c::Primitive::Bool,
54 Scalar::Char => c::Primitive::Char,
55 Scalar::Int8 => c::Primitive::Int8,
56 Scalar::Int16 => c::Primitive::Int16,
57 Scalar::Int32 => c::Primitive::Int32,
58 Scalar::Int64 => c::Primitive::Int64,
59 Scalar::UInt8 => c::Primitive::UInt8,
60 Scalar::UInt16 => c::Primitive::UInt16,
61 Scalar::UInt32 => c::Primitive::UInt32,
62 Scalar::UInt64 => c::Primitive::UInt64,
63 Scalar::Float => c::Primitive::Float,
64 Scalar::Double => c::Primitive::Double,
65 Scalar::LongDouble => c::Primitive::LongDouble,
66 })
67 }
68
69 fn named(name: &str) -> Self::Type {
70 c::Type::Named(Ident::new(name))
71 }
72
73 fn nothing() -> Self::Type {
74 c::Type::Void
75 }
76
77 fn handle(kind: Handle) -> Self::Type {
79 c::Type::Named(Ident::new(match kind {
80 Handle::DHeader => "zdw_dheader",
81 Handle::EmHeader => "zdw_emheader",
82 Handle::Pid => "zdw_pid",
83 Handle::TryConstruct => "zdw_try_construct",
84 Handle::ReaderMark => "zdw_reader_mark",
85 Handle::PidRead => "zdw_pid_read",
86 Handle::EmHeaderRead => "zdw_emheader_read",
87 }))
88 }
89
90 fn unsigned_holder(bits: u16) -> Self::Type {
91 c::Type::Primitive(c_holder(bits))
92 }
93
94 fn code_point(value: Self::Expr, narrow: bool) -> Self::Expr {
97 let inner = if narrow {
98 c::Expr::Cast {
99 type_: Box::new(c::Type::Primitive(c::Primitive::UInt8)),
100 value: Box::new(value),
101 }
102 } else {
103 value
104 };
105 c::Expr::Cast {
106 type_: Box::new(c::Type::Primitive(c::Primitive::UInt32)),
107 value: Box::new(inner),
108 }
109 }
110
111 fn constant(which: Constant) -> Self::Expr {
113 c::Expr::Name(Ident::new(match which {
114 Constant::WcharWidth2 => "ZDW_WCHAR_WIDTH_2",
115 Constant::WcharWidth4 => "ZDW_WCHAR_WIDTH_4",
116 Constant::WcharFixed => "ZDW_WCHAR_FIXED",
117 Constant::WcharGiopLengthPrefixed => "ZDW_WCHAR_GIOP_LENGTH_PREFIXED",
118 Constant::WstringUnitsStream => "ZDW_WSTRING_UNITS_STREAM",
119 Constant::WstringUnitsBigEndianAlways => "ZDW_WSTRING_UNITS_BIG_ENDIAN_ALWAYS",
120 Constant::WstringUnitsByteOrderMark => "ZDW_WSTRING_UNITS_BYTE_ORDER_MARK",
121 Constant::WstringUnitsHostUnswapped => "ZDW_WSTRING_UNITS_HOST_UNSWAPPED",
122 Constant::WstringSpecification => "ZDW_WSTRING_SPECIFICATION",
123 Constant::WstringCharacterCount => "ZDW_WSTRING_CHARACTER_COUNT",
124 Constant::WstringCharacterCountTerminated => "ZDW_WSTRING_CHARACTER_COUNT_TERMINATED",
125 Constant::WstringSpecificationWideUnits => "ZDW_WSTRING_SPECIFICATION_WIDE_UNITS",
126 Constant::WstringRosTypeSupport => "ZDW_WSTRING_ROS_TYPE_SUPPORT",
127 Constant::WstringOctetsTerminated2 => "ZDW_WSTRING_OCTETS_TERMINATED_2",
128 Constant::WstringOctetsTerminated4 => "ZDW_WSTRING_OCTETS_TERMINATED_4",
129 Constant::WstringCharactersTerminated2 => "ZDW_WSTRING_CHARACTERS_TERMINATED_2",
130 Constant::FixedDeclared => "ZDW_FIXED_DECLARED",
131 Constant::FixedValuePrecision => "ZDW_FIXED_VALUE_PRECISION",
132 Constant::FixedValueStringDigits => "ZDW_FIXED_VALUE_STRING_DIGITS",
133 Constant::ParameterMember => "ZDW_PARAM_MEMBER",
134 Constant::ParameterOptional => "ZDW_PARAM_OPTIONAL",
135 Constant::TryConstructDiscard => "ZDW_TC_DISCARD",
136 Constant::TryConstructTrim => "ZDW_TC_TRIM",
137 Constant::TryConstructUseDefault => "ZDW_TC_USE_DEFAULT",
138 Constant::StatusOk => "ZDW_OK",
139 Constant::StatusDiscarded => "ZDW_DISCARDED",
140 Constant::StatusImpossibleLength => "ZDW_IMPOSSIBLE_LENGTH",
141 Constant::StatusOutOfRange => "ZDW_OUT_OF_RANGE",
142 Constant::StatusTruncated => "ZDW_TRUNCATED",
143 }))
144 }
145
146 fn bit_pattern(source: BitPatternSource, value: Self::Expr) -> Self::Expr {
156 let value = match (&source, value) {
157 (BitPatternSource::Int { .. }, c::Expr::Cast { value, .. }) => c::Expr::Cast {
158 type_: Box::new(c::Type::Primitive(c::Primitive::UInt64)),
159 value,
160 },
161 (_, other) => other,
162 };
163 match source {
164 BitPatternSource::Int { octets } => Self::runtime_static(
165 "bit_pattern_int",
166 vec![value, Self::int(i128::from(octets))],
167 ),
168 BitPatternSource::Bool => Self::runtime_static("bit_pattern_bool", vec![value]),
169 BitPatternSource::Float32 => Self::runtime_static("bit_pattern_f32", vec![value]),
170 BitPatternSource::Float64 => Self::runtime_static("bit_pattern_f64", vec![value]),
171 }
172 }
173
174 fn runtime_static(method: &str, args: Vec<Self::Expr>) -> Self::Expr {
177 c::Expr::Call {
178 callee: Box::new(c::Expr::Name(Ident::new(&format!(
179 "{}{method}",
180 Self::PREFIX
181 )))),
182 args,
183 }
184 }
185
186 fn name(text: &str) -> Self::Expr {
189 c::Expr::Name(Ident::new(text))
190 }
191
192 fn int(value: i128) -> Self::Expr {
193 c::Expr::Literal(Literal::int(value))
194 }
195
196 fn literal(value: Literal) -> Self::Expr {
197 c::Expr::Literal(value)
198 }
199
200 fn call(callee: &str, args: Vec<Self::Expr>) -> Self::Expr {
201 c::Expr::Call {
202 callee: Box::new(c::Expr::Name(Ident::new(callee))),
203 args,
204 }
205 }
206
207 fn runtime(receiver: &str, method: &str, args: Vec<Self::Expr>) -> Self::Expr {
208 let mut all = vec![c::Expr::Name(Ident::new(receiver))];
209 all.extend(args);
210 c::Expr::Call {
211 callee: Box::new(c::Expr::Name(Ident::new(&format!(
212 "{}{method}",
213 Self::PREFIX
214 )))),
215 args: all,
216 }
217 }
218
219 fn carries_hdds_axes() -> bool {
224 true
225 }
226
227 fn member(base: &str, field: &str) -> Self::Expr {
228 c::Expr::Arrow {
229 value: Box::new(c::Expr::Name(Ident::new(base))),
230 name: Ident::new(field),
231 }
232 }
233
234 fn whole(base: &str) -> Self::Expr {
235 c::Expr::Deref(Box::new(c::Expr::Name(Ident::new(base))))
236 }
237
238 fn wide_int(value: i128) -> Self::Expr {
253 let text = if value > i128::from(i64::MAX) {
254 format!("UINT64_C({value})")
255 } else if value == i128::from(i64::MIN) {
256 zerodds_lang_render::c::integer_text(value)
257 } else if value > i128::from(i32::MAX) || value < i128::from(i32::MIN) {
258 format!("INT64_C({value})")
259 } else {
260 format!("{value}")
261 };
262 c::Expr::Literal(Literal::Int(text))
263 }
264
265 fn field_of(value: Self::Expr, field: &str) -> Self::Expr {
266 c::Expr::Member {
267 value: Box::new(value),
268 name: Ident::new(field),
269 }
270 }
271
272 fn index(value: Self::Expr, at: Self::Expr) -> Self::Expr {
273 c::Expr::Index {
274 value: Box::new(value),
275 index: Box::new(at),
276 }
277 }
278
279 fn count_of(base: &str, fixed: Option<u64>) -> Self::Expr {
282 match fixed {
283 Some(bound) => c::Expr::Literal(Literal::int(i128::from(bound))),
284 None => Self::member(base, "_length"),
285 }
286 }
287
288 fn binary(op: &'static str, lhs: Self::Expr, rhs: Self::Expr) -> Self::Expr {
289 c::Expr::Binary {
290 op,
291 lhs: Box::new(lhs),
292 rhs: Box::new(rhs),
293 }
294 }
295
296 fn unary(op: &'static str, value: Self::Expr) -> Self::Expr {
297 c::Expr::Unary {
298 op,
299 value: Box::new(value),
300 }
301 }
302
303 fn paren(value: Self::Expr) -> Self::Expr {
304 c::Expr::Paren(Box::new(value))
305 }
306
307 fn cast(type_: Self::Type, value: Self::Expr) -> Self::Expr {
308 c::Expr::Cast {
309 type_: Box::new(type_),
310 value: Box::new(value),
311 }
312 }
313
314 fn handoff(value: Self::Expr, form: Handoff) -> Self::Expr {
326 match (form, value) {
327 (Handoff::Array, value) => value,
328 (Handoff::Value, c::Expr::Deref(inner)) => *inner,
329 (Handoff::Value, value) => c::Expr::AddressOf(Box::new(value)),
330 }
331 }
332
333 fn declare(type_: Self::Type, name: &str, value: Option<Self::Expr>) -> Self::Stmt {
336 c::Statement::Declare {
337 type_,
338 name: Ident::new(name),
339 value,
340 }
341 }
342
343 fn perform(value: Self::Expr) -> Self::Stmt {
344 c::Statement::Expr(value)
345 }
346
347 fn give_back(value: Option<Self::Expr>) -> Self::Stmt {
348 c::Statement::Return(value)
349 }
350
351 fn when(
352 condition: Self::Expr,
353 then: Self::Block,
354 otherwise: Option<Self::Block>,
355 ) -> Self::Stmt {
356 c::Statement::If {
357 condition,
358 then,
359 otherwise,
360 }
361 }
362
363 fn count_up(counter: &str, bound: Self::Expr, body: Self::Block) -> Self::Stmt {
373 c::Statement::For {
374 init: Box::new(c::Statement::Declare {
375 type_: c::Type::Primitive(c::Primitive::UInt32),
376 name: Ident::new(counter),
377 value: Some(c::Expr::Literal(Literal::int(0))),
378 }),
379 condition: c::Expr::Binary {
380 op: "<",
381 lhs: Box::new(c::Expr::Name(Ident::new(counter))),
382 rhs: Box::new(bound),
383 },
384 step: c::Expr::Binary {
385 op: "=",
386 lhs: Box::new(c::Expr::Name(Ident::new(counter))),
387 rhs: Box::new(c::Expr::Binary {
388 op: "+",
389 lhs: Box::new(c::Expr::Name(Ident::new(counter))),
390 rhs: Box::new(c::Expr::Literal(Literal::int(1))),
391 }),
392 },
393 body,
394 }
395 }
396
397 fn until(condition: Self::Expr, body: Self::Block) -> Self::Stmt {
398 c::Statement::While { condition, body }
399 }
400
401 fn leave() -> Self::Stmt {
402 c::Statement::Break
403 }
404
405 fn note(doc: Doc) -> Self::Stmt {
406 c::Statement::Comment(doc)
407 }
408
409 fn make_room(
418 base: &str,
419 element: Self::Type,
420 count: Self::Expr,
421 _assigned_whole: bool,
425 fill: Vec<Self::Stmt>,
426 ) -> Vec<Self::Stmt> {
427 let field = |name: &str| Self::member(base, name);
428 let assign = |place: c::Expr, value: c::Expr| {
429 c::Statement::Expr(c::Expr::Binary {
430 op: "=",
431 lhs: Box::new(place),
432 rhs: Box::new(value),
433 })
434 };
435 let mut guarded = vec![
436 assign(
437 field("_buffer"),
438 c::Expr::Cast {
439 type_: Box::new(c::Type::Pointer(Box::new(element.clone()))),
440 value: Box::new(Self::runtime(
441 "r",
442 "reader_alloc",
443 vec![c::Expr::Binary {
444 op: "*",
445 lhs: Box::new(c::Expr::Cast {
446 type_: Box::new(c::Type::Primitive(c::Primitive::Size)),
447 value: Box::new(count.clone()),
448 }),
449 rhs: Box::new(c::Expr::SizeOf(Box::new(element))),
450 }],
451 )),
452 },
453 ),
454 c::Statement::If {
455 condition: c::Expr::Binary {
456 op: "==",
457 lhs: Box::new(field("_buffer")),
458 rhs: Box::new(Self::absent()),
459 },
460 then: c::Block {
461 statements: vec![c::Statement::Return(None)],
462 },
463 otherwise: None,
464 },
465 ];
466 guarded.extend(fill);
467 vec![
469 assign(field("_maximum"), count.clone()),
470 assign(field("_release"), c::Expr::Literal(Literal::Bool(false))),
471 assign(field("_length"), count.clone()),
472 assign(field("_buffer"), Self::absent()),
473 c::Statement::If {
474 condition: c::Expr::Binary {
475 op: ">",
476 lhs: Box::new(count),
477 rhs: Box::new(c::Expr::Literal(Literal::Int("0u".to_string()))),
478 },
479 then: c::Block {
480 statements: guarded,
481 },
482 otherwise: None,
483 },
484 ]
485 }
486
487 fn present(base: &str, field: &str) -> Self::Expr {
490 c::Expr::Binary {
491 op: "!=",
492 lhs: Box::new(Self::member(base, field)),
493 rhs: Box::new(Self::absent()),
494 }
495 }
496
497 fn inherited_path(depth: usize) -> Option<String> {
500 Some(format!("{}.", crate::adapter::c::PARENT).repeat(depth))
501 }
502
503 fn set_present(base: &str, field: &str, present: bool) -> Vec<Self::Stmt> {
507 if present {
508 return Vec::new();
509 }
510 vec![c::Statement::Expr(c::Expr::Binary {
511 op: "=",
512 lhs: Box::new(Self::member(base, field)),
513 rhs: Box::new(Self::absent()),
514 })]
515 }
516
517 fn optionals_are_pointers() -> bool {
520 true
521 }
522
523 fn refuse_unset_external(present: Self::Expr) -> Vec<Self::Stmt> {
525 vec![c::Statement::If {
526 condition: c::Expr::Unary {
527 op: "!",
528 value: Box::new(c::Expr::Paren(Box::new(present))),
529 },
530 then: c::Block {
531 statements: vec![
532 c::Statement::Expr(Self::runtime(
533 "w",
534 "writer_refuse",
535 vec![c::Expr::Name(Ident::new("ZDW_UNSET_EXTERNAL"))],
536 )),
537 c::Statement::Return(None),
538 ],
539 },
540 otherwise: None,
541 }]
542 }
543
544 fn case_member(base: &str, field: &str) -> Self::Expr {
545 c::Expr::Member {
546 value: Box::new(Self::member(base, "_u")),
547 name: Ident::new(field),
548 }
549 }
550
551 fn entry_half(entry: Self::Expr, key: bool) -> Self::Expr {
552 c::Expr::Member {
553 value: Box::new(entry),
554 name: Ident::new(if key { "key" } else { "value" }),
555 }
556 }
557
558 fn optional_value(_ast: &Ast, _id: Id<TypeNode>, base: &str, field: &str) -> Self::Expr {
559 Self::member(base, field)
560 }
561
562 fn sequence_element(
565 base: &str,
566 index: Self::Expr,
567 _element: Self::Type,
568 ) -> (Vec<Self::Stmt>, Self::Expr, Vec<Self::Stmt>) {
569 (
570 Vec::new(),
571 Self::index(Self::elements(base), index),
572 Vec::new(),
573 )
574 }
575
576 fn keep_first(base: &str, count: Self::Expr) -> Vec<Self::Stmt> {
579 vec![c::Statement::Expr(c::Expr::Binary {
580 op: "=",
581 lhs: Box::new(Self::count_of(base, None)),
582 rhs: Box::new(count),
583 })]
584 }
585
586 fn optional_destination(base: &str, field: &str) -> (Vec<Self::Stmt>, Self::Expr) {
591 (Vec::new(), Self::member(base, field))
592 }
593
594 fn externals_are_pointers() -> bool {
605 true
606 }
607
608 fn behind_indirection(_ast: &Ast, _id: Id<TypeNode>, place: Self::Expr) -> Self::Expr {
609 c::Expr::Deref(Box::new(place))
610 }
611
612 fn make_indirection(
626 ast: &Ast,
627 id: Id<TypeNode>,
628 place: Self::Expr,
629 ) -> (Vec<Self::Stmt>, Self::Expr) {
630 let held = Self::value_type(ast, id);
631 let made = c::Statement::Expr(c::Expr::Binary {
632 op: "=",
633 lhs: Box::new(place.clone()),
634 rhs: Box::new(c::Expr::Cast {
635 type_: Box::new(c::Type::Pointer(Box::new(held.clone()))),
636 value: Box::new(Self::runtime(
637 "r",
638 "reader_alloc",
639 vec![c::Expr::SizeOf(Box::new(held))],
640 )),
641 }),
642 });
643 let guard = c::Statement::If {
644 condition: c::Expr::Binary {
645 op: "==",
646 lhs: Box::new(place.clone()),
647 rhs: Box::new(Self::absent()),
648 },
649 then: c::Block {
650 statements: vec![c::Statement::Return(None)],
651 },
652 otherwise: None,
653 };
654 (vec![made, guard], c::Expr::Deref(Box::new(place)))
655 }
656
657 fn elements(base: &str) -> Self::Expr {
658 Self::member(base, "_buffer")
659 }
660
661 fn absent() -> Self::Expr {
662 c::Expr::Name(Ident::new("NULL"))
663 }
664
665 fn materialised(value: Self::Expr) -> Option<Self::Expr> {
668 Some(c::Expr::Binary {
669 op: "!=",
670 lhs: Box::new(value),
671 rhs: Box::new(Self::absent()),
672 })
673 }
674
675 fn block(statements: Vec<Self::Stmt>) -> Self::Block {
676 c::Block { statements }
677 }
678
679 fn into_statements(block: Self::Block) -> Vec<Self::Stmt> {
680 block.statements
681 }
682
683 fn routine(spec: Routine<Self>) -> Option<Self::Decl> {
689 let stream = c::Param {
690 type_: c::Type::Pointer(Box::new(c::Type::Named(Ident::new(if spec.writing {
691 "zdw_writer"
692 } else {
693 "zdw_reader"
694 })))),
695 name: Some(Ident::new(if spec.writing { "w" } else { "r" })),
696 };
697 let constant = |type_: c::Type| {
701 if spec.writing {
702 c::Type::Const(Box::new(type_))
703 } else {
704 type_
705 }
706 };
707 let value = match spec.held {
712 Handoff::Array => constant(spec.sample),
713 Handoff::Value => c::Type::Pointer(Box::new(constant(spec.sample))),
714 };
715 let mut params = vec![
716 stream,
717 c::Param {
718 type_: value,
719 name: Some(Ident::new("v")),
720 },
721 ];
722 params.extend(spec.extra.into_iter().map(|(type_, name)| c::Param {
723 type_,
724 name: Some(Ident::new(&name)),
725 }));
726 Some(c::Decl::Function(c::Function {
727 doc: spec.doc,
728 is_static: true,
729 is_inline: false,
730 is_maybe_unused: spec.tolerate_unused,
731 returns: c::Type::Void,
732 name: Ident::new(&spec.name),
733 params,
734 body: spec.body,
735 }))
736 }
737
738 fn value_type(ast: &Ast, id: Id<TypeNode>) -> Self::Type {
741 c_value_type(ast, id)
742 }
743
744 fn type_name(ast: &Ast, id: Id<TypeNode>) -> String {
752 c_codec_tag(ast, id)
753 }
754
755 fn escape(name: &str) -> String {
756 c::escape_keyword(name)
757 }
758
759 fn map_entry_name(ast: &Ast, id: Id<TypeNode>) -> String {
760 c_map_entry_name(ast, id)
761 }
762
763 fn enumerator_constant(ast: &Ast, id: Id<TypeNode>, name: &str) -> Self::Expr {
768 Self::name(&enumerator_constant_name(ast, id, name))
769 }
770
771 fn module_prefix(ast: &Ast, id: Id<TypeNode>) -> String {
772 module_prefix(ast, id)
773 }
774
775 fn default_into(
779 ast: &Ast,
780 id: Id<TypeNode>,
781 place: Self::Expr,
782 ) -> Result<Self::Stmt, EncodeError> {
783 Ok(crate::default_c::default_into(ast, id, place))
784 }
785
786 fn member_default(
787 ast: &Ast,
788 node: &MemberNode,
789 type_: Id<TypeNode>,
790 place: Self::Expr,
791 ) -> Result<Vec<Self::Stmt>, EncodeError> {
792 crate::default_c::member_default(ast, node, type_, place)
793 }
794}
795
796#[must_use]
802pub fn runtime_function(method: &str) -> String {
803 format!("{}{method}", C::PREFIX)
804}
805
806pub(crate) fn enumerator_constant_name(ast: &Ast, id: Id<TypeNode>, name: &str) -> String {
812 format!("{}{}", module_prefix(ast, id), c::escape_keyword(name))
813}