Skip to main content

gaia_assembler/assembler/
mod.rs

1//! Gaia Unified Compiler
2//!
3//! Provides a unified compilation interface supporting multiple target platforms.
4
5use crate::{backends::*, program::GaiaModule};
6use gaia_types::{helpers::CompilationTarget, GaiaErrorKind, *};
7
8/// Gaia Assembler
9pub struct GaiaAssembler {
10    backends: Vec<Box<dyn Backend>>,
11}
12
13impl GaiaAssembler {
14    /// Create a new assembler instance with all available backends.
15    pub fn new() -> Self {
16        #[allow(unused_mut)]
17        let mut backends: Vec<Box<dyn Backend>> = vec![];
18
19        #[cfg(feature = "jvm-assembler")]
20        backends.push(Box::new(JvmBackend {}));
21        #[cfg(feature = "pe-assembler")]
22        backends.push(Box::new(WindowsBackend {}));
23        #[cfg(feature = "wasi-assembler")]
24        backends.push(Box::new(WasiBackend {}));
25        #[cfg(feature = "x86_64-assembler")]
26        backends.push(Box::new(X64Backend {}));
27        #[cfg(feature = "gcn-assembler")]
28        backends.push(Box::new(GcnBackend::new()));
29        #[cfg(feature = "sass-assembler")]
30        backends.push(Box::new(SassBackend::new()));
31        #[cfg(feature = "clr-assembler")]
32        backends.push(Box::new(ClrBackend {}));
33        #[cfg(feature = "elf-assembler")]
34        backends.push(Box::new(ElfBackend {}));
35        #[cfg(feature = "macho-assembler")]
36        backends.push(Box::new(MachoBackend {}));
37        #[cfg(feature = "lua-assembler")]
38        backends.push(Box::new(LuaBackend {}));
39        #[cfg(feature = "llvm-assembler")]
40        backends.push(Box::new(LlvmBackend {}));
41        #[cfg(feature = "msl-assembler")]
42        backends.push(Box::new(MslBackend {}));
43        #[cfg(feature = "spirv-assembler")]
44        backends.push(Box::new(SpirvBackend {}));
45        #[cfg(feature = "python-assembler")]
46        backends.push(Box::new(PythonBackend {}));
47
48        Self { backends }
49    }
50
51    /// Compile a Gaia program for the specified target.
52    pub fn compile(&self, program: &GaiaModule, target: &CompilationTarget) -> Result<GeneratedFiles> {
53        // Prioritize backends matching the host exactly to avoid misselection due to scores.
54        let mut best_backend: Option<&Box<dyn Backend>> = None;
55        let mut best_score = 0.0;
56
57        // Try exact match with the primary target of the backend.
58        if let Some(candidate) = self.backends.iter().find(|b| {
59            let pt = b.primary_target();
60            pt.host == target.host && pt.build == target.build
61        }) {
62            best_backend = Some(candidate);
63            best_score = 100.0; // Exact match priority
64        }
65
66        // If no exact match found, fall back to scoring.
67        if best_backend.is_none() {
68            for backend in &self.backends {
69                let score = backend.match_score(target);
70                if score > best_score {
71                    best_score = score;
72                    best_backend = Some(backend);
73                }
74            }
75        }
76
77        if best_backend.is_none() || best_score <= 0.0 {
78            return Err(GaiaErrorKind::UnsupportedTarget { target: target.clone() }.into());
79        }
80
81        // Create config and pass the target so the backend can output the correct file type.
82        let mut config = crate::config::GaiaConfig::default();
83        config.target = target.clone();
84
85        // Compile using the selected backend.
86        best_backend.unwrap().generate(program, &config)
87    }
88
89    /// Get all available backends.
90    pub fn backends(&self) -> &[Box<dyn Backend>] {
91        &self.backends
92    }
93}
94
95/// Compile to a specific platform.
96pub fn compile_to_platform(program: &GaiaModule, target: CompilationTarget) -> Result<Vec<u8>> {
97    let compiler = GaiaAssembler::new();
98    let generated_files = compiler.compile(program, &target)?;
99
100    // Extract the primary binary file from the generated files.
101    // Usually the first file is the primary output file.
102    if let Some((_, bytes)) = generated_files.files.iter().next() {
103        Ok(bytes.clone())
104    }
105    else {
106        Err(GaiaError::invalid_data("No output files generated"))
107    }
108}