Skip to main content

lamina_codegen/
abi.rs

1//! Common ABI trait and utilities for code generation backends.
2//!
3//! This module defines a trait that all ABI implementations must follow,
4//! reducing code duplication and providing a consistent interface.
5
6use lamina_platform::TargetOperatingSystem;
7
8/// Trait defining the common interface for all ABI implementations.
9///
10/// This trait provides a standardized way to interact with platform-specific
11/// ABI details across different architectures. Each backend implements this
12/// trait to provide architecture and OS-specific behavior.
13pub trait Abi {
14    /// Returns the target operating system for this ABI instance.
15    fn target_os(&self) -> TargetOperatingSystem;
16
17    /// Returns the mangled function name with platform-specific prefix.
18    ///
19    /// This method handles platform-specific symbol naming conventions,
20    /// such as the underscore prefix on macOS.
21    fn mangle_function_name(&self, name: &str) -> String;
22
23    /// Maps well-known intrinsic/runtime names to platform symbol stubs.
24    ///
25    /// Returns `None` if the name is not a known intrinsic that needs
26    /// special handling. This allows backends to map internal names
27    /// (like "print") to platform-specific symbols (like "_printf" on macOS).
28    ///
29    /// Default implementation returns `None` for all names, meaning
30    /// no special mapping is needed.
31    fn call_stub(&self, name: &str) -> Option<String> {
32        let _ = name;
33        None
34    }
35}
36
37/// Helper function to mangle function names for macOS (adds underscore prefix).
38///
39/// This is a common pattern used by multiple backends, so we provide
40/// it as a shared utility function.
41pub fn mangle_macos_name(name: &str) -> String {
42    if name == "main" {
43        "_main".to_string()
44    } else {
45        format!("_{}", name)
46    }
47}
48
49/// Helper function to get the platform-specific printf symbol name.
50///
51/// macOS uses leading underscore ("_printf"); Linux, BSD, and Windows use "printf".
52/// Cross-compilation: pass the target OS, not the host.
53pub fn get_printf_symbol(target_os: TargetOperatingSystem) -> &'static str {
54    match target_os {
55        TargetOperatingSystem::MacOS => "_printf",
56        _ => "printf",
57    }
58}
59
60/// Helper function to get the platform-specific malloc symbol name.
61///
62/// macOS uses "_malloc"; Linux, BSD, Windows use "malloc".
63pub fn get_malloc_symbol(target_os: TargetOperatingSystem) -> &'static str {
64    match target_os {
65        TargetOperatingSystem::MacOS => "_malloc",
66        _ => "malloc",
67    }
68}
69
70/// Helper function to get the platform-specific free symbol name.
71///
72/// macOS uses "_free"; Linux, BSD, Windows use "free".
73pub fn get_free_symbol(target_os: TargetOperatingSystem) -> &'static str {
74    match target_os {
75        TargetOperatingSystem::MacOS => "_free",
76        _ => "free",
77    }
78}
79
80/// Helper function to create a common call_stub implementation.
81///
82/// This handles the common pattern of mapping "print", "malloc", and "dealloc"
83/// to their platform-specific symbols. Backends can use this to reduce
84/// duplication in their `call_stub` implementations.
85pub fn common_call_stub(name: &str, target_os: TargetOperatingSystem) -> Option<String> {
86    match name {
87        "print" => Some(get_printf_symbol(target_os).to_string()),
88        "malloc" => Some(get_malloc_symbol(target_os).to_string()),
89        "dealloc" => Some(get_free_symbol(target_os).to_string()),
90        _ => None,
91    }
92}