use crate::core::config::Language;
use crate::core::ir::{ApiSurface, FunctionDef, TypeRef};
use crate::docs::formatting::{IdentifierPosition, report_identifier_violation};
use crate::docs::naming::{func_name, to_camel_case, type_name};
use crate::docs::rust_types::rust_param_type;
use crate::docs::type_mapping::doc_type;
use heck::ToSnakeCase;
pub(crate) fn render_python_fn_sig(func: &FunctionDef, ffi_prefix: &str) -> String {
let name = func_name(&func.name, Language::Python, ffi_prefix);
report_identifier_violation(
&name,
Language::Python,
IdentifierPosition::Declaration,
"a function signature",
);
let params: Vec<String> = func
.params
.iter()
.map(|p| {
let pname = p.name.to_snake_case();
let pty = doc_type(&p.ty, Language::Python, ffi_prefix);
if p.optional {
format!("{pname}: {pty} = None")
} else {
format!("{pname}: {pty}")
}
})
.collect();
let ret = doc_type(&func.return_type, Language::Python, ffi_prefix);
format!("def {}({}) -> {}", name, params.join(", "), ret)
}
pub(crate) fn render_typescript_fn_sig(func: &FunctionDef, ffi_prefix: &str) -> String {
let name = func_name(&func.name, Language::Node, ffi_prefix);
report_identifier_violation(
&name,
Language::Node,
IdentifierPosition::Declaration,
"a function signature",
);
let params: Vec<String> = func
.params
.iter()
.map(|p| {
let pname = to_camel_case(&p.name);
let pty = doc_type(&p.ty, Language::Node, ffi_prefix);
if p.optional {
format!("{pname}?: {pty}")
} else {
format!("{pname}: {pty}")
}
})
.collect();
let ret = doc_type(&func.return_type, Language::Node, ffi_prefix);
if func.is_async {
format!("function {}({}): Promise<{}>", name, params.join(", "), ret)
} else {
format!("function {}({}): {}", name, params.join(", "), ret)
}
}
pub(crate) fn go_return_type(return_type: &TypeRef, ret: String) -> String {
if matches!(return_type, TypeRef::Named(_)) {
format!("*{ret}")
} else {
ret
}
}
pub(crate) fn render_go_fn_sig(func: &FunctionDef, ffi_prefix: &str) -> String {
let name = func_name(&func.name, Language::Go, ffi_prefix);
report_identifier_violation(
&name,
Language::Go,
IdentifierPosition::Declaration,
"a function signature",
);
let params: Vec<String> = func
.params
.iter()
.map(|p| {
let pname = to_camel_case(&p.name);
let pty = doc_type(&p.ty, Language::Go, ffi_prefix);
format!("{pname} {pty}")
})
.collect();
let ret = go_return_type(&func.return_type, doc_type(&func.return_type, Language::Go, ffi_prefix));
if func.error_type.is_some() {
if ret.is_empty() {
format!("func {}({}) error", name, params.join(", "))
} else {
format!("func {}({}) ({}, error)", name, params.join(", "), ret)
}
} else if ret.is_empty() {
format!("func {}({})", name, params.join(", "))
} else {
format!("func {}({}) {}", name, params.join(", "), ret)
}
}
pub(crate) fn render_java_fn_sig(func: &FunctionDef, ffi_prefix: &str, crate_name: &str) -> String {
let name = func_name(&func.name, Language::Java, ffi_prefix);
report_identifier_violation(
&name,
Language::Java,
IdentifierPosition::Member,
"a function signature",
);
let ret = doc_type(&func.return_type, Language::Java, ffi_prefix);
let params: Vec<String> = func
.params
.iter()
.map(|p| {
let pname = to_camel_case(&p.name);
let pty = doc_type(&p.ty, Language::Java, ffi_prefix);
format!("{pty} {pname}")
})
.collect();
let throws = format!(
" throws {}",
crate::backends::java::naming::exception_class_name(crate_name)
);
format!("public static {} {}({}){}", ret, name, params.join(", "), throws)
}
pub(crate) fn render_ruby_fn_sig(func: &FunctionDef) -> String {
let name = func_name(&func.name, Language::Ruby, "");
report_identifier_violation(
&name,
Language::Ruby,
IdentifierPosition::Member,
"a function signature",
);
let params: Vec<String> = func
.params
.iter()
.map(|p| {
let pname = p.name.to_snake_case();
if p.optional { format!("{pname}: nil") } else { pname }
})
.collect();
format!("def self.{}({})", name, params.join(", "))
}
pub(crate) fn render_c_fn_sig(func: &FunctionDef, ffi_prefix: &str) -> String {
let name = crate::codegen::c_consumer::free_function_symbol(&ffi_prefix.to_snake_case(), &func.name);
let ret = doc_type(&func.return_type, Language::Ffi, ffi_prefix);
let params: Vec<String> = func
.params
.iter()
.map(|p| {
let pname = p.name.to_snake_case();
let pty = doc_type(&p.ty, Language::Ffi, ffi_prefix);
format!("{pty} {pname}")
})
.collect();
let ret_str = match &func.return_type {
TypeRef::Unit if func.error_type.is_some() => "int32_t".to_string(),
TypeRef::Unit => "void".to_string(),
_ => ret,
};
format!("{} {}({});", ret_str, name, params.join(", "))
}
pub(crate) fn render_php_fn_sig(func: &FunctionDef, ffi_prefix: &str) -> String {
let name = func_name(&func.name, Language::Php, ffi_prefix);
report_identifier_violation(&name, Language::Php, IdentifierPosition::Member, "a function signature");
let params: Vec<String> = func
.params
.iter()
.map(|p| {
let pname = format!("${}", to_camel_case(&p.name));
let pty = doc_type(&p.ty, Language::Php, ffi_prefix);
if p.optional {
format!("?{pty} {pname} = null")
} else {
format!("{pty} {pname}")
}
})
.collect();
let ret = doc_type(&func.return_type, Language::Php, ffi_prefix);
format!("public static function {}({}): {}", name, params.join(", "), ret)
}
pub(crate) fn render_elixir_fn_sig(func: &FunctionDef) -> String {
let name = func_name(&func.name, Language::Elixir, "");
report_identifier_violation(
&name,
Language::Elixir,
IdentifierPosition::Declaration,
"a function signature",
);
let params: Vec<String> = func.params.iter().map(|p| p.name.to_snake_case()).collect();
format!(
"@spec {}({}) :: {{:ok, term()}} | {{:error, term()}}\ndef {}({})",
name,
params.join(", "),
name,
params.join(", ")
)
}
pub(crate) fn render_r_fn_sig(func: &FunctionDef) -> String {
let name = func_name(&func.name, Language::R, "");
let params: Vec<String> = func
.params
.iter()
.map(|p| {
let pname = p.name.to_snake_case();
if p.optional { format!("{pname} = NULL") } else { pname }
})
.collect();
format!("{}({})", name, params.join(", "))
}
pub(crate) fn render_csharp_fn_sig(func: &FunctionDef, ffi_prefix: &str) -> String {
let name = func_name(&func.name, Language::Csharp, ffi_prefix);
report_identifier_violation(
&name,
Language::Csharp,
IdentifierPosition::Member,
"a function signature",
);
let ret = doc_type(&func.return_type, Language::Csharp, ffi_prefix);
let params: Vec<String> = func
.params
.iter()
.map(|p| {
let pname = to_camel_case(&p.name);
let pty = doc_type(&p.ty, Language::Csharp, ffi_prefix);
if p.optional {
format!("{pty}? {pname} = null")
} else {
format!("{pty} {pname}")
}
})
.collect();
if func.is_async {
let async_name = crate::docs::naming::csharp_async_member_name(&name, true);
let task_ret = if ret == "void" {
"Task".to_string()
} else {
format!("Task<{ret}>")
};
format!("public static async {} {}({})", task_ret, async_name, params.join(", "))
} else {
format!("public static {} {}({})", ret, name, params.join(", "))
}
}
pub(crate) fn render_rust_fn_sig(func: &FunctionDef, ffi_prefix: &str) -> String {
let name = func.name.to_snake_case();
let params: Vec<String> = func
.params
.iter()
.map(|p| format!("{}: {}", p.name.to_snake_case(), rust_param_type(p, ffi_prefix)))
.collect();
let ret = doc_type(&func.return_type, Language::Rust, ffi_prefix);
let error_part = if let Some(err) = &func.error_type {
let err_ty = type_name(err, Language::Rust, ffi_prefix);
if ret == "()" {
format!(" -> Result<(), {err_ty}>")
} else {
format!(" -> Result<{ret}, {err_ty}>")
}
} else if ret == "()" {
String::new()
} else {
format!(" -> {ret}")
};
if func.is_async {
format!("pub async fn {}({}){}", name, params.join(", "), error_part)
} else {
format!("pub fn {}({}){}", name, params.join(", "), error_part)
}
}
pub(crate) fn render_kotlin_fn_sig(func: &FunctionDef, ffi_prefix: &str) -> String {
let name = func_name(&func.name, Language::Kotlin, ffi_prefix);
report_identifier_violation(
&name,
Language::Kotlin,
IdentifierPosition::Declaration,
"a function signature",
);
let ret = doc_type(&func.return_type, Language::Kotlin, ffi_prefix);
let params: Vec<String> = func
.params
.iter()
.map(|p| {
let pname = to_camel_case(&p.name);
let pty = doc_type(&p.ty, Language::Kotlin, ffi_prefix);
if p.optional {
format!("{pname}: {pty}? = null")
} else {
format!("{pname}: {pty}")
}
})
.collect();
let throws = func
.error_type
.as_ref()
.map(|e| format!("@Throws({}::class)\n", type_name(e, Language::Kotlin, ffi_prefix)))
.unwrap_or_default();
let ret_part = if ret == "Unit" {
String::new()
} else {
format!(": {ret}")
};
format!("{throws}fun {name}({}){ret_part}", params.join(", "))
}
pub(crate) fn render_swift_fn_sig(func: &FunctionDef, ffi_prefix: &str) -> String {
let name = func_name(&func.name, Language::Swift, ffi_prefix);
report_identifier_violation(
&name,
Language::Swift,
IdentifierPosition::Member,
"a function signature",
);
let ret = doc_type(&func.return_type, Language::Swift, ffi_prefix);
let params: Vec<String> = func
.params
.iter()
.map(|p| {
let pname = to_camel_case(&p.name);
let pty = doc_type(&p.ty, Language::Swift, ffi_prefix);
if p.optional {
format!("{pname}: {pty}? = nil")
} else {
format!("{pname}: {pty}")
}
})
.collect();
let throws = if func.error_type.is_some() { " throws" } else { "" };
let ret_part = if ret == "Void" {
String::new()
} else {
format!(" -> {ret}")
};
format!("public static func {name}({}){throws}{ret_part}", params.join(", "))
}
pub(crate) fn render_dart_fn_sig(func: &FunctionDef, ffi_prefix: &str) -> String {
let name = func_name(&func.name, Language::Dart, ffi_prefix);
report_identifier_violation(
&name,
Language::Dart,
IdentifierPosition::Declaration,
"a function signature",
);
let ret = doc_type(&func.return_type, Language::Dart, ffi_prefix);
let required: Vec<String> = func
.params
.iter()
.filter(|p| !p.optional)
.map(|p| {
let pname = to_camel_case(&p.name);
let pty = doc_type(&p.ty, Language::Dart, ffi_prefix);
format!("{pty} {pname}")
})
.collect();
let optional: Vec<String> = func
.params
.iter()
.filter(|p| p.optional)
.map(|p| {
let pname = to_camel_case(&p.name);
let pty = doc_type(&p.ty, Language::Dart, ffi_prefix);
format!("{pty}? {pname}")
})
.collect();
let params_str = match (required.is_empty(), optional.is_empty()) {
(_, true) => required.join(", "),
(true, false) => format!("{{{}}}", optional.join(", ")),
(false, false) => format!("{}, {{{}}}", required.join(", "), optional.join(", ")),
};
let future_ret = if ret == "void" {
"Future<void>".to_string()
} else {
format!("Future<{ret}>")
};
format!("{future_ret} {name}({params_str})")
}
pub(crate) fn render_zig_fn_sig(func: &FunctionDef, ffi_prefix: &str, api: &ApiSurface) -> String {
let name = func_name(&func.name, Language::Zig, ffi_prefix);
report_identifier_violation(
&name,
Language::Zig,
IdentifierPosition::Declaration,
"a function signature",
);
let ret = crate::backends::zig::zig_boundary_return_type(&func.return_type, api);
let params: Vec<String> = func
.params
.iter()
.map(|p| {
let pname = p.name.to_snake_case();
let pty = crate::backends::zig::zig_boundary_param_type(&p.ty, p.optional, api);
format!("{pname}: {pty}")
})
.collect();
let ret_str = if let Some(err) = &func.error_type {
let err_ty = type_name(err, Language::Zig, ffi_prefix);
if ret == "void" {
format!("{err_ty}!void")
} else {
format!("{err_ty}!{ret}")
}
} else {
ret
};
format!("pub fn {name}({}) {ret_str}", params.join(", "))
}