use super::{CodecTarget, Constant, Handle, Handoff, Routine, Scalar};
use crate::adapter::swift::{
property_name, swift_holder, swift_map_entry_name, swift_type_name, swift_value_type,
};
use crate::encode::EncodeError;
use zerodds_ast::{Ast, CharWidth, MemberNode, TypeKind, TypeNode};
use zerodds_ast_core::Id;
use zerodds_lang_cst::common::{Doc, Ident, Literal};
use zerodds_lang_cst::swift;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Swift;
const MAX_TYPE_DEPTH: usize = 64;
const SIGNED_CHAR: &str = "signed char";
#[derive(Debug, Clone)]
pub enum SwiftExpr {
Plain(swift::Expr),
BranchSlot(swift::Expr),
ExternalSlot(swift::Expr),
AppendSlot(swift::Expr),
Assign(Box<SwiftExpr>, Box<swift::Expr>),
}
fn inner(expr: SwiftExpr) -> swift::Expr {
match expr {
SwiftExpr::Plain(e) | SwiftExpr::ExternalSlot(e) | SwiftExpr::AppendSlot(e) => e,
SwiftExpr::BranchSlot(e) => swift::Expr::ForceUnwrap(Box::new(e)),
SwiftExpr::Assign(place, value) => swift::Expr::Binary {
op: "=",
lhs: Box::new(inner(*place)),
rhs: value,
},
}
}
fn plain(e: swift::Expr) -> SwiftExpr {
SwiftExpr::Plain(e)
}
impl Swift {
fn camel(method: &str) -> String {
let mut out = String::new();
for (index, segment) in method.split('_').enumerate() {
let mut chars = segment.chars();
match chars.next() {
Some(first) if index > 0 => {
out.extend(first.to_uppercase());
out.push_str(chars.as_str());
}
Some(first) => {
out.push(first);
out.push_str(chars.as_str());
}
None => {}
}
}
out
}
fn free_name(method: &str) -> String {
let mut out = String::from("zd");
for segment in method.split('_') {
let mut chars = segment.chars();
if let Some(first) = chars.next() {
out.extend(first.to_uppercase());
out.push_str(chars.as_str());
}
}
out
}
fn runtime_method_throws(method: &str) -> bool {
!matches!(
method,
"reader_position"
| "reader_remaining"
| "reader_status"
| "reader_refuse"
| "reader_clear_discard"
| "reader_save"
| "reader_restore"
| "finish_pid_read"
| "trim_utf8"
| "trim_utf16"
| "position"
| "finish"
| "write_bool"
| "write_u8"
| "write_i8"
| "write_char"
| "write_i16"
| "write_u16"
| "write_i32"
| "write_u32"
| "write_i64"
| "write_u64"
| "write_f32"
| "write_f64"
| "write_string"
| "write_u16_little"
| "write_u16_big"
| "write_u32_little"
| "write_u32_big"
| "write_dheader"
| "begin_packed_element"
| "finish_packed_element"
| "reader_begin_packed_element"
| "reader_finish_packed_element"
| "read_u16_little"
| "read_u16_big"
| "read_u32_little"
| "read_u32_big"
)
}
fn take_try(expr: swift::Expr) -> (swift::Expr, bool) {
match expr {
swift::Expr::Try(inner) => (*inner, true),
other => (other, false),
}
}
fn maybe_try(expr: swift::Expr, throws: bool) -> SwiftExpr {
if throws {
plain(swift::Expr::Try(Box::new(expr)))
} else {
plain(expr)
}
}
fn text(value: &str) -> SwiftExpr {
plain(swift::Expr::Literal(Literal::Str(value.to_string())))
}
fn dotted(base: &str, name: &str) -> SwiftExpr {
plain(swift::Expr::Member {
value: Box::new(swift::Expr::Name(Ident::new(base))),
name: Ident::new(name),
})
}
fn invoke(receiver: Option<swift::Expr>, name: &str, args: Vec<swift::Expr>) -> swift::Expr {
swift::Expr::Invoke {
receiver: receiver.map(Box::new),
name: Ident::new(name),
args: args
.into_iter()
.map(|value| swift::Argument { label: None, value })
.collect(),
}
}
fn convert(type_: swift::Type, value: swift::Expr) -> swift::Expr {
Self::invoke(
None,
"zdTo",
vec![swift::Expr::TypeSelf(Box::new(type_)), value],
)
}
fn assemble_assign(place: SwiftExpr, value: swift::Expr) -> swift::Stmt {
match place {
SwiftExpr::Plain(p) | SwiftExpr::BranchSlot(p) => {
swift::Stmt::Assign { place: p, value }
}
SwiftExpr::ExternalSlot(p) => swift::Stmt::Assign {
place: p,
value: Self::invoke(None, "ZdExternal", vec![value]),
},
SwiftExpr::AppendSlot(base) => {
swift::Stmt::Expr(Self::invoke(Some(base), "append", vec![value]))
}
SwiftExpr::Assign(next, first) => {
let _ = first;
Self::assemble_assign(*next, value)
}
}
}
}
impl CodecTarget for Swift {
type Expr = SwiftExpr;
type Stmt = swift::Stmt;
type Block = Vec<swift::Stmt>;
type Type = swift::Type;
type Decl = swift::Decl;
fn scalar(kind: Scalar) -> Self::Type {
match kind {
Scalar::Bool => swift::Type::Primitive(swift::Primitive::Bool),
Scalar::Char | Scalar::UInt8 => swift::Type::Primitive(swift::Primitive::UInt8),
Scalar::Int8 => swift::Type::Primitive(swift::Primitive::Int8),
Scalar::Int16 => swift::Type::Primitive(swift::Primitive::Int16),
Scalar::UInt16 => swift::Type::Primitive(swift::Primitive::UInt16),
Scalar::Int32 => swift::Type::Primitive(swift::Primitive::Int32),
Scalar::UInt32 | Scalar::Index => swift::Type::Primitive(swift::Primitive::UInt32),
Scalar::Int64 => swift::Type::Primitive(swift::Primitive::Int64),
Scalar::UInt64 => swift::Type::Primitive(swift::Primitive::UInt64),
Scalar::Float => swift::Type::Primitive(swift::Primitive::Float),
Scalar::Double => swift::Type::Primitive(swift::Primitive::Double),
Scalar::LongDouble => swift::Type::Primitive(swift::Primitive::String),
Scalar::Size => swift::Type::named("Int"),
}
}
fn named(name: &str) -> Self::Type {
swift::Type::named(name)
}
fn nothing() -> Self::Type {
swift::Type::named("Void")
}
fn handle(kind: Handle) -> Self::Type {
swift::Type::named(match kind {
Handle::DHeader => "ZdDHeader",
Handle::EmHeader => "ZdEmHeader",
Handle::Pid => "ZdPid",
Handle::TryConstruct => "ZdTryConstruct",
Handle::ReaderMark => "ZdReaderMark",
Handle::PidRead => "ZdPidRead",
Handle::EmHeaderRead => "ZdEmHeaderRead",
})
}
fn code_point(value: Self::Expr, _narrow: bool) -> Self::Expr {
value
}
fn constant(which: Constant) -> Self::Expr {
match which {
Constant::WcharWidth2 => plain(swift::Expr::int(2)),
Constant::WcharWidth4 => plain(swift::Expr::int(4)),
Constant::WcharFixed => Self::text("fixed"),
Constant::WcharGiopLengthPrefixed => Self::text("giop-length-prefixed"),
Constant::WstringUnitsStream => Self::text("stream"),
Constant::WstringUnitsBigEndianAlways => Self::text("big-endian-always"),
Constant::WstringUnitsByteOrderMark => Self::text("byte-order-mark"),
Constant::WstringUnitsHostUnswapped => Self::text("host-unswapped"),
Constant::WstringSpecification => Self::text("specification"),
Constant::WstringCharacterCount => Self::text("character-count"),
Constant::WstringCharacterCountTerminated => Self::text("character-count-terminated"),
Constant::WstringSpecificationWideUnits => Self::text("specification-wide-units"),
Constant::WstringRosTypeSupport => Self::text("ros-type-support"),
Constant::WstringOctetsTerminated2 => Self::text("octets/terminated/2"),
Constant::WstringOctetsTerminated4 => Self::text("octets/terminated/4"),
Constant::WstringCharactersTerminated2 => Self::text("characters/terminated/2"),
Constant::FixedDeclared => Self::text("declared"),
Constant::FixedValuePrecision => Self::text("value-precision"),
Constant::FixedValueStringDigits => Self::text("value-string-digits"),
Constant::ParameterMember => Self::dotted("ZdParameterRole", "member"),
Constant::ParameterOptional => Self::dotted("ZdParameterRole", "optional"),
Constant::TryConstructDiscard => Self::dotted("ZdTryConstruct", "discard"),
Constant::TryConstructTrim => Self::dotted("ZdTryConstruct", "trim"),
Constant::TryConstructUseDefault => Self::dotted("ZdTryConstruct", "useDefault"),
Constant::StatusOk => Self::dotted("ZdStatus", "ok"),
Constant::StatusDiscarded => Self::dotted("ZdStatus", "discarded"),
Constant::StatusImpossibleLength => Self::dotted("ZdStatus", "impossibleLength"),
Constant::StatusOutOfRange => Self::dotted("ZdStatus", "outOfRange"),
Constant::StatusTruncated => Self::dotted("ZdStatus", "truncated"),
}
}
fn unsigned_holder(bits: u16) -> Self::Type {
swift::Type::Primitive(swift_holder(bits))
}
fn value_type(ast: &Ast, id: Id<TypeNode>) -> Self::Type {
swift_value_type(ast, id).unwrap_or_else(|_| swift::Type::named("ZdNoSwiftForm"))
}
fn type_name(ast: &Ast, id: Id<TypeNode>) -> String {
type_tag(ast, id, 0)
}
fn map_entry_name(ast: &Ast, id: Id<TypeNode>) -> String {
swift_map_entry_name(ast, id).unwrap_or_else(|_| format!("ZdUnresolvedEntry{}", id.slot()))
}
fn module_prefix(_ast: &Ast, _id: Id<TypeNode>) -> String {
String::new()
}
fn escape(name: &str) -> String {
property_name(name)
}
fn inherited_path(depth: usize) -> Option<String> {
Some(format!("{}.", property_name("parent")).repeat(depth))
}
fn name(text: &str) -> Self::Expr {
plain(swift::Expr::Name(Ident::new(text)))
}
fn int(value: i128) -> Self::Expr {
plain(swift::Expr::int(value))
}
fn literal(value: Literal) -> Self::Expr {
let Literal::Int(text) = &value else {
return plain(swift::Expr::Literal(value));
};
match text.as_str() {
"true" => plain(swift::Expr::Literal(Literal::Bool(true))),
"false" => plain(swift::Expr::Literal(Literal::Bool(false))),
_ => plain(swift::Expr::Literal(value)),
}
}
fn wide_int(value: i128) -> Self::Expr {
if value > i128::from(i64::MAX) {
return plain(swift::Expr::Paren(Box::new(swift::Expr::Binary {
op: "as",
lhs: Box::new(swift::Expr::int(value)),
rhs: Box::new(swift::Expr::Name(Ident::new("UInt64"))),
})));
}
plain(swift::Expr::int(value))
}
fn unsigned_int(value: i128) -> Self::Expr {
Self::wide_int(value)
}
fn wide_unsigned(value: u64) -> Self::Expr {
plain(swift::Expr::Literal(Literal::Int(format!("{value}"))))
}
fn wide_signed(value: i128) -> Self::Expr {
plain(swift::Expr::Literal(Literal::Int(format!("{value}"))))
}
fn member(base: &str, field: &str) -> Self::Expr {
Self::dotted(base, field)
}
fn whole(base: &str) -> Self::Expr {
plain(swift::Expr::Name(Ident::new(base)))
}
fn field_of(value: Self::Expr, field: &str) -> Self::Expr {
plain(swift::Expr::Member {
value: Box::new(inner(value)),
name: Ident::new(field),
})
}
fn header_field(value: Self::Expr, field: &str) -> Self::Expr {
plain(swift::Expr::Member {
value: Box::new(inner(value)),
name: Ident::new(&Self::camel(field)),
})
}
fn index(value: Self::Expr, at: Self::Expr) -> Self::Expr {
plain(swift::Expr::Index {
value: Box::new(inner(value)),
index: Box::new(Self::invoke(None, "Int", vec![inner(at)])),
})
}
fn count_of(base: &str, fixed: Option<u64>) -> Self::Expr {
match fixed {
Some(bound) => plain(swift::Expr::int(i128::from(bound))),
None => plain(Self::invoke(
None,
"UInt32",
vec![swift::Expr::Member {
value: Box::new(swift::Expr::Name(Ident::new(base))),
name: Ident::new("count"),
}],
)),
}
}
fn elements(base: &str) -> Self::Expr {
plain(swift::Expr::Name(Ident::new(base)))
}
fn case_member(base: &str, field: &str) -> Self::Expr {
SwiftExpr::BranchSlot(swift::Expr::Member {
value: Box::new(swift::Expr::Name(Ident::new(base))),
name: Ident::new(field),
})
}
fn entry_half(entry: Self::Expr, key: bool) -> Self::Expr {
plain(swift::Expr::Member {
value: Box::new(inner(entry)),
name: Ident::new(if key { "key" } else { "value" }),
})
}
fn absent() -> Self::Expr {
plain(swift::Expr::Literal(Literal::Null))
}
fn materialised(_value: Self::Expr) -> Option<Self::Expr> {
None
}
fn optional_value(_ast: &Ast, _id: Id<TypeNode>, base: &str, field: &str) -> Self::Expr {
plain(swift::Expr::ForceUnwrap(Box::new(inner(Self::member(
base, field,
)))))
}
fn present(base: &str, field: &str) -> Self::Expr {
plain(swift::Expr::Binary {
op: "!=",
lhs: Box::new(inner(Self::member(base, field))),
rhs: Box::new(swift::Expr::Literal(Literal::Null)),
})
}
fn set_present(base: &str, field: &str, present: bool) -> Vec<Self::Stmt> {
if present {
return Vec::new();
}
vec![swift::Stmt::Assign {
place: inner(Self::member(base, field)),
value: swift::Expr::Literal(Literal::Null),
}]
}
fn clear_union_cases(base: &str, fields: &[String]) -> Vec<Self::Stmt> {
fields
.iter()
.flat_map(|field| Self::set_present(base, field, false))
.collect()
}
fn optional_destination(base: &str, field: &str) -> (Vec<Self::Stmt>, Self::Expr) {
(Vec::new(), Self::member(base, field))
}
fn holds_a_cycle_externally() -> bool {
true
}
fn external_value(
_ast: &Ast,
_id: Id<TypeNode>,
base: &str,
field: &str,
optional: bool,
) -> Self::Expr {
let member = inner(Self::member(base, field));
let boxed = if optional {
swift::Expr::ForceUnwrap(Box::new(member))
} else {
member
};
plain(swift::Expr::Member {
value: Box::new(boxed),
name: Ident::new("value"),
})
}
fn external_destination(
base: &str,
field: &str,
_optional: bool,
) -> (Vec<Self::Stmt>, Self::Expr) {
(
Vec::new(),
SwiftExpr::ExternalSlot(inner(Self::member(base, field))),
)
}
fn external_present(base: &str, field: &str) -> Self::Expr {
Self::present(base, field)
}
fn external_set_present(base: &str, field: &str, present: bool) -> Vec<Self::Stmt> {
Self::set_present(base, field, present)
}
fn external_case_value(_ast: &Ast, _id: Id<TypeNode>, base: &str, field: &str) -> Self::Expr {
plain(swift::Expr::Member {
value: Box::new(inner(Self::case_member(base, field))),
name: Ident::new("value"),
})
}
fn external_case_destination(base: &str, field: &str) -> (Vec<Self::Stmt>, Self::Expr) {
(
Vec::new(),
SwiftExpr::ExternalSlot(inner_place(Self::case_member(base, field))),
)
}
fn binary(op: &'static str, lhs: Self::Expr, rhs: Self::Expr) -> Self::Expr {
if op == "=" {
return SwiftExpr::Assign(Box::new(lhs), Box::new(inner(rhs)));
}
let (lhs, lhs_throws) = Self::take_try(inner(lhs));
let (rhs, rhs_throws) = Self::take_try(inner(rhs));
let combined = swift::Expr::Binary {
op,
lhs: Box::new(lhs),
rhs: Box::new(rhs),
};
Self::maybe_try(combined, lhs_throws || rhs_throws)
}
fn unary(op: &'static str, value: Self::Expr) -> Self::Expr {
let (value, throws) = Self::take_try(inner(value));
let combined = swift::Expr::Unary {
op,
value: Box::new(value),
};
Self::maybe_try(combined, throws)
}
fn paren(value: Self::Expr) -> Self::Expr {
let (value, throws) = Self::take_try(inner(value));
let combined = swift::Expr::Paren(Box::new(value));
Self::maybe_try(combined, throws)
}
fn cast(type_: Self::Type, value: Self::Expr) -> Self::Expr {
if type_ == swift::Type::named(SIGNED_CHAR) {
return plain(swift::Expr::Invoke {
receiver: None,
name: Ident::new("Int8"),
args: vec![swift::Argument {
label: Some(Ident::new("bitPattern")),
value: inner(value),
}],
});
}
if type_ == swift::Type::Primitive(swift::Primitive::Bool) {
if let SwiftExpr::Plain(swift::Expr::Literal(Literal::Int(text))) = &value {
return plain(swift::Expr::Literal(Literal::Bool(text != "0")));
}
}
plain(Self::convert(type_, inner(value)))
}
fn bool_less(left: Self::Expr, right: Self::Expr) -> Self::Expr {
let (left, left_throws) = Self::take_try(inner(left));
let (right, right_throws) = Self::take_try(inner(right));
let combined = swift::Expr::Binary {
op: "&&",
lhs: Box::new(swift::Expr::Paren(Box::new(swift::Expr::Binary {
op: "==",
lhs: Box::new(left),
rhs: Box::new(swift::Expr::Literal(Literal::Bool(false))),
}))),
rhs: Box::new(right),
};
Self::maybe_try(combined, left_throws || right_throws)
}
fn enumerator_ordinal(ast: &Ast, id: Id<TypeNode>, value: Self::Expr) -> Self::Expr {
if !super::resolves_to_enumeration(ast, id) {
return value;
}
let (value, throws) = Self::take_try(inner(value));
Self::maybe_try(
swift::Expr::Member {
value: Box::new(value),
name: Ident::new("rawValue"),
},
throws,
)
}
fn handoff(value: Self::Expr, _form: Handoff) -> Self::Expr {
plain(inner(value))
}
fn call(callee: &str, args: Vec<Self::Expr>) -> Self::Expr {
let arguments: Vec<swift::Expr> = args.into_iter().map(inner).collect();
if callee == "strcmp" {
return plain(Self::invoke(None, "zdStrcmp", arguments));
}
plain(swift::Expr::Try(Box::new(Self::invoke(
None, callee, arguments,
))))
}
fn runtime(receiver: &str, method: &str, args: Vec<Self::Expr>) -> Self::Expr {
let invoke = Self::invoke(
Some(swift::Expr::Name(Ident::new(receiver))),
&Self::camel(method),
args.into_iter().map(inner).collect(),
);
Self::maybe_try(invoke, Self::runtime_method_throws(method))
}
fn carries_hdds_axes() -> bool {
true
}
fn runtime_static(method: &str, args: Vec<Self::Expr>) -> Self::Expr {
plain(Self::invoke(
None,
&Self::free_name(method),
args.into_iter().map(inner).collect(),
))
}
fn declare(type_: Self::Type, name: &str, value: Option<Self::Expr>) -> Self::Stmt {
swift::Stmt::Var {
name: Ident::new(name),
type_: Some(type_),
value: value.map(inner),
}
}
fn perform(value: Self::Expr) -> Self::Stmt {
if let SwiftExpr::Assign(place, value) = value {
return Self::assemble_assign(*place, *value);
}
swift::Stmt::Expr(inner(value))
}
fn give_back(value: Option<Self::Expr>) -> Self::Stmt {
swift::Stmt::Return(Some(match value {
Some(value) => inner(value),
None => swift::Expr::Name(Ident::new("v")),
}))
}
fn when(
condition: Self::Expr,
then: Self::Block,
otherwise: Option<Self::Block>,
) -> Self::Stmt {
swift::Stmt::If {
condition: inner(condition),
then,
otherwise: otherwise.filter(|body| !body.is_empty()),
}
}
fn count_up(counter: &str, bound: Self::Expr, body: Self::Block) -> Self::Stmt {
swift::Stmt::ForRange {
counter: Ident::new(counter),
bound: inner(bound),
body,
}
}
fn until(condition: Self::Expr, body: Self::Block) -> Self::Stmt {
swift::Stmt::While {
condition: inner(condition),
body,
}
}
fn leave() -> Self::Stmt {
swift::Stmt::Break
}
fn note(doc: Doc) -> Self::Stmt {
swift::Stmt::Comment(doc)
}
fn drop_value(value: Self::Expr) -> Self::Stmt {
swift::Stmt::Assign {
place: swift::Expr::Name(Ident::new("_")),
value: inner(value),
}
}
fn mark_used(name: &str) -> Vec<Self::Stmt> {
vec![swift::Stmt::Assign {
place: swift::Expr::Name(Ident::new("_")),
value: swift::Expr::Name(Ident::new(name)),
}]
}
fn read_call(
callee: &str,
place: Self::Expr,
_form: Handoff,
behaviour: Self::Expr,
) -> Self::Stmt {
let decoded = swift::Expr::Try(Box::new(Self::invoke(
None,
callee,
vec![swift::Expr::Name(Ident::new("r")), inner(behaviour)],
)));
Self::assemble_assign(place, decoded)
}
fn read_forward(callee: &str) -> Self::Stmt {
Self::read_call(
callee,
Self::whole("v"),
Handoff::Value,
Self::name("zd_tc"),
)
}
fn block(statements: Vec<Self::Stmt>) -> Self::Block {
statements
}
fn into_statements(block: Self::Block) -> Vec<Self::Stmt> {
block
}
fn make_room(
base: &str,
element: Self::Type,
count: Self::Expr,
assigned_whole: bool,
fill: Vec<Self::Stmt>,
) -> Vec<Self::Stmt> {
let count = inner(count);
if assigned_whole {
let mut out = vec![
swift::Stmt::Assign {
place: swift::Expr::Name(Ident::new(base)),
value: swift::Expr::ArrayLit(Vec::new()),
},
swift::Stmt::Expr(Self::invoke(
Some(swift::Expr::Name(Ident::new(base))),
"reserveCapacity",
vec![Self::invoke(None, "Int", vec![count])],
)),
];
out.extend(fill);
return out;
}
let repeated = match &element {
swift::Type::Named(name) => {
Self::invoke(None, &format!("zd_def_{}", name.as_str()), Vec::new())
}
_ => Self::invoke(None, "zd_def_unsupported_room", Vec::new()),
};
let mut out = vec![swift::Stmt::Assign {
place: swift::Expr::Name(Ident::new(base)),
value: swift::Expr::RepeatingArray {
element: Box::new(element),
repeated: Box::new(repeated),
count: Box::new(Self::invoke(None, "Int", vec![count])),
},
}];
out.extend(fill);
out
}
fn keep_first(base: &str, count: Self::Expr) -> Vec<Self::Stmt> {
vec![swift::Stmt::Assign {
place: swift::Expr::Name(Ident::new(base)),
value: Self::invoke(
None,
"Array",
vec![Self::invoke(
Some(swift::Expr::Name(Ident::new(base))),
"prefix",
vec![Self::invoke(None, "Int", vec![inner(count)])],
)],
),
}]
}
fn sequence_element(
base: &str,
_index: Self::Expr,
_element: Self::Type,
) -> (Vec<Self::Stmt>, Self::Expr, Vec<Self::Stmt>) {
(
Vec::new(),
SwiftExpr::AppendSlot(swift::Expr::Name(Ident::new(base))),
Vec::new(),
)
}
fn storage(type_: Self::Type, name: &str) -> Self::Stmt {
match &type_ {
swift::Type::Named(type_name) => swift::Stmt::Var {
name: Ident::new(name),
type_: None,
value: Some(Self::invoke(
None,
&format!("zd_def_{}", type_name.as_str()),
Vec::new(),
)),
},
_ => swift::Stmt::Var {
name: Ident::new(name),
type_: Some(type_),
value: None,
},
}
}
fn routine(spec: Routine<Self>) -> Option<Self::Decl> {
let body = spec.body?;
let underscore = |name: &str, type_: swift::Type| swift::Param {
label: Ident::new("_"),
internal_name: Some(Ident::new(name)),
type_,
};
let mut params = vec![underscore(
if spec.writing { "w" } else { "r" },
swift::Type::named(if spec.writing { "ZdWriter" } else { "ZdReader" }),
)];
if spec.writing {
params.push(underscore("v", spec.sample.clone()));
}
for (type_, name) in spec.extra {
params.push(underscore(&name, type_));
}
let (returns, body) = if spec.writing {
(None, body)
} else {
let defaulter = crate::default_swift::defaulter_from_decoder(&spec.name);
let mut statements = vec![swift::Stmt::Var {
name: Ident::new("v"),
type_: None,
value: Some(Self::invoke(None, &defaulter, Vec::new())),
}];
statements.extend(body);
statements.push(swift::Stmt::Return(Some(swift::Expr::Name(Ident::new(
"v",
)))));
(Some(spec.sample), statements)
};
Some(swift::Decl::Func(swift::FuncDecl {
doc: spec.doc,
visibility: zerodds_lang_cst::common::Visibility::Public,
name: Ident::new(&spec.name),
params,
throws: true,
returns,
body,
}))
}
fn bitmask_value(ast: &Ast, id: Id<TypeNode>, value: Self::Expr) -> Self::Expr {
let holder = swift::Type::Primitive(swift_holder(ast.effective_bit_bound(id)));
plain(swift::Expr::Invoke {
receiver: None,
name: Ident::new(&swift_type_name(ast, id)),
args: vec![swift::Argument {
label: Some(Ident::new("rawValue")),
value: Self::convert(holder, inner(value)),
}],
})
}
fn default_into(
ast: &Ast,
id: Id<TypeNode>,
place: Self::Expr,
) -> Result<Self::Stmt, EncodeError> {
let defaulted = Self::invoke(
None,
&crate::default_swift::defaulter_name(ast, id),
Vec::new(),
);
Ok(Self::assemble_assign(place, defaulted))
}
fn member_default(
ast: &Ast,
node: &MemberNode,
type_: Id<TypeNode>,
place: Self::Expr,
) -> Result<Vec<Self::Stmt>, EncodeError> {
crate::default_swift::member_default(ast, node, type_, inner_place(place))
}
fn enumerator_constant(ast: &Ast, id: Id<TypeNode>, enumerator: &str) -> Self::Expr {
plain(swift::Expr::Member {
value: Box::new(swift::Expr::Name(Ident::new(&swift_type_name(ast, id)))),
name: Ident::new(&property_name(enumerator)),
})
}
}
fn inner_place(expr: SwiftExpr) -> swift::Expr {
match expr {
SwiftExpr::Plain(e)
| SwiftExpr::BranchSlot(e)
| SwiftExpr::ExternalSlot(e)
| SwiftExpr::AppendSlot(e) => e,
SwiftExpr::Assign(place, _) => inner_place(*place),
}
}
fn bound_tag(ast: &Ast, bound: &zerodds_ast::Bound) -> String {
match bound.expr() {
None => String::new(),
Some(expr) => match ast.eval_integral(expr) {
Ok(limit) => format!("_b{limit}"),
Err(_) => "_bx".to_string(),
},
}
}
#[must_use]
pub fn type_tag(ast: &Ast, id: Id<TypeNode>, depth: usize) -> String {
if depth > MAX_TYPE_DEPTH {
return "unresolved".to_string();
}
let node = match ast.type_(id) {
Ok(node) => node,
Err(_) => return "unresolved".to_string(),
};
match &node.kind {
TypeKind::Primitive(kind) => kind.as_str().replace(' ', "_"),
TypeKind::String {
width: CharWidth::Char,
bound,
} => format!("string{}", bound_tag(ast, bound)),
TypeKind::String {
width: CharWidth::WChar,
bound,
} => format!("wstring{}", bound_tag(ast, bound)),
TypeKind::Fixed { digits, scale } => format!("fixed_{digits}_{scale}"),
TypeKind::Sequence { element, bound } => match element.resolved() {
Some(element) => format!(
"seq{}_{}",
bound_tag(ast, bound),
type_tag(ast, element, depth + 1)
),
None => format!("seq_unresolved{}", bound_tag(ast, bound)),
},
TypeKind::Array { element, dims } => {
let mut name = match element.resolved() {
Some(element) => format!("arr_{}", type_tag(ast, element, depth + 1)),
None => "arr_unresolved".to_string(),
};
for dim in dims {
match ast.eval_integral(*dim) {
Ok(length) => name.push_str(&format!("_{length}")),
Err(_) => name.push_str("_x"),
}
}
name
}
TypeKind::Map { key, value, bound } => {
let half = |half: Option<Id<TypeNode>>| match half {
Some(target) => type_tag(ast, target, depth + 1),
None => "unresolved".to_string(),
};
format!(
"map{}_{}_{}",
bound_tag(ast, bound),
half(key.resolved()),
half(value.resolved())
)
}
TypeKind::Alias { aliased } => match aliased.resolved() {
Some(target) => type_tag(ast, target, depth + 1),
None => "unresolved".to_string(),
},
TypeKind::ValueBox { boxed } => match boxed.resolved() {
Some(target) => format!("box_{}", type_tag(ast, target, depth + 1)),
None => "box_unresolved".to_string(),
},
TypeKind::Structure { .. }
| TypeKind::Union { .. }
| TypeKind::Enumeration { .. }
| TypeKind::Bitmask { .. }
| TypeKind::Bitset { .. }
| TypeKind::Valuetype { .. }
| TypeKind::Native => swift_type_name(ast, id).replace('`', ""),
TypeKind::Any => "any".to_string(),
TypeKind::ValueBase => "valuebase".to_string(),
TypeKind::ObjectRef { .. } => "objectref".to_string(),
TypeKind::AnnotationType { .. } => "annotation".to_string(),
}
}