Skip to main content

chipi_core/
backend.rs

1//! Code generation backends.
2//!
3//! Each backend implements [`CodegenBackend`] to emit source code for a
4//! specific target language. Only the Rust backend exists today; the trait
5//! is the extensibility point for future languages.
6
7pub mod rust;
8
9use crate::config::GenTarget;
10use crate::types::ValidatedDef;
11
12/// Trait for language-specific code generation backends.
13pub trait CodegenBackend {
14    /// Language identifier (e.g., `"rust"`).
15    fn lang(&self) -> &str;
16
17    /// Validate language-specific options from the `lang_options` config field.
18    /// Returns errors for unknown or invalid keys.
19    fn validate_lang_options(&self, options: &toml::Value) -> Result<(), Vec<String>>;
20
21    /// Generate source code from the decoder IR and configuration.
22    fn generate(&self, ir: &ValidatedDef, config: &GenTarget) -> Result<String, CodegenError>;
23
24    /// Optional: command to format the generated source.
25    fn formatter_command(&self) -> Option<&[&str]>;
26}
27
28#[derive(Debug)]
29pub enum CodegenError {
30    Internal(String),
31}
32
33impl std::fmt::Display for CodegenError {
34    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
35        match self {
36            CodegenError::Internal(msg) => write!(f, "codegen error: {}", msg),
37        }
38    }
39}
40
41impl std::error::Error for CodegenError {}
42
43/// Get a backend by language name.
44pub fn get_backend(lang: &str) -> Option<Box<dyn CodegenBackend>> {
45    match lang {
46        "rust" => Some(Box::new(rust::RustBackend)),
47        _ => None,
48    }
49}
50
51/// Run a formatter command on a file. Warns on failure; does not error.
52pub fn run_formatter(cmd: &[&str], path: &str) {
53    let status = std::process::Command::new(cmd[0])
54        .args(&cmd[1..])
55        .arg(path)
56        .status();
57
58    match status {
59        Ok(s) if s.success() => {}
60        Ok(s) => eprintln!("warning: formatter exited with {}", s),
61        Err(e) if e.kind() == std::io::ErrorKind::NotFound => {
62            eprintln!("warning: formatter '{}' not found, skipping", cmd[0]);
63        }
64        Err(e) => eprintln!("warning: failed to run formatter: {}", e),
65    }
66}