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        #[cfg(feature = "nyar-assembler")]
48        backends.push(Box::new(NyarBackend {}));
49
50        Self { backends }
51    }
52
53    /// Compile a Gaia program for the specified target.
54    pub fn compile(&self, program: &GaiaModule, target: &CompilationTarget) -> Result<GeneratedFiles> {
55        // Prioritize backends matching the host exactly to avoid misselection due to scores.
56        let mut best_backend: Option<&Box<dyn Backend>> = None;
57        let mut best_score = 0.0;
58
59        // Try exact match with the primary target of the backend.
60        if let Some(candidate) = self.backends.iter().find(|b| {
61            let pt = b.primary_target();
62            pt.host == target.host && pt.build == target.build
63        }) {
64            best_backend = Some(candidate);
65            best_score = 100.0; // Exact match priority
66        }
67
68        // If no exact match found, fall back to scoring.
69        if best_backend.is_none() {
70            for backend in &self.backends {
71                let score = backend.match_score(target);
72                if score > best_score {
73                    best_score = score;
74                    best_backend = Some(backend);
75                }
76            }
77        }
78
79        if best_backend.is_none() || best_score <= 0.0 {
80            return Err(GaiaErrorKind::UnsupportedTarget { target: target.clone() }.into());
81        }
82
83        // Create config and pass the target so the backend can output the correct file type.
84        let mut config = crate::config::GaiaConfig::default();
85        config.target = target.clone();
86
87        // Compile using the selected backend.
88        best_backend.unwrap().generate(program, &config)
89    }
90
91    /// Get all available backends.
92    pub fn backends(&self) -> &[Box<dyn Backend>] {
93        &self.backends
94    }
95}
96
97/// Compile to a specific platform.
98pub fn compile_to_platform(program: &GaiaModule, target: CompilationTarget) -> Result<Vec<u8>> {
99    let compiler = GaiaAssembler::new();
100    let generated_files = compiler.compile(program, &target)?;
101
102    // Extract the primary binary file from the generated files.
103    // Usually the first file is the primary output file.
104    if let Some((_, bytes)) = generated_files.files.iter().next() {
105        Ok(bytes.clone())
106    }
107    else {
108        Err(GaiaError::invalid_data("No output files generated"))
109    }
110}