Skip to main content

vexil_lang/
codegen.rs

1//! # Stability: Tier 1
2//!
3//! Codegen backend trait and shared error type. Implement [`CodegenBackend`]
4//! to add a new code-generation target to `vexilc`.
5
6use std::collections::BTreeMap;
7use std::path::PathBuf;
8
9use crate::ir::CompiledSchema;
10use crate::project::ProjectResult;
11
12/// A pluggable code-generation backend.
13///
14/// Each backend translates compiled Vexil schemas into source code for a
15/// specific target language.  Implement this trait to add support for a new
16/// language.
17///
18/// Backends are used in two modes:
19/// - **Single-file** via [`generate`](CodegenBackend::generate) — for REPL,
20///   quick checks, or single-schema compilation.
21/// - **Project-level** via [`generate_project`](CodegenBackend::generate_project)
22///   — for multi-file projects.  The backend owns cross-file import strategy
23///   and output file layout.
24pub trait CodegenBackend {
25    /// Backend identifier, e.g. `"rust"`, `"typescript"`.
26    fn name(&self) -> &str;
27
28    /// File extension for generated files, e.g. `"rs"`, `"ts"`.
29    fn file_extension(&self) -> &str;
30
31    /// Generate code for a single compiled schema.
32    fn generate(&self, compiled: &CompiledSchema) -> Result<String, CodegenError>;
33
34    /// Generate all files for a multi-file project.
35    ///
36    /// Returns a map from relative output path to file content.
37    /// The backend is responsible for cross-file import statements and
38    /// module-scaffolding files (e.g. `mod.rs`, `index.ts`).
39    fn generate_project(
40        &self,
41        result: &ProjectResult,
42    ) -> Result<BTreeMap<PathBuf, String>, CodegenError>;
43}
44
45/// Errors that can occur during code generation.
46#[derive(Debug, thiserror::Error)]
47pub enum CodegenError {
48    /// The backend does not support a type used in the schema.
49    #[error("unsupported type `{type_name}` in {backend} backend")]
50    UnsupportedType {
51        /// Name of the unsupported type.
52        type_name: String,
53        /// Backend that encountered the error.
54        backend: String,
55    },
56
57    /// A required annotation is missing from the schema.
58    #[error("missing required annotation `{annotation}` ({context})")]
59    MissingAnnotation {
60        /// The annotation that was expected.
61        annotation: String,
62        /// Where it was expected.
63        context: String,
64    },
65
66    /// An I/O error occurred during code generation.
67    #[error("I/O error: {0}")]
68    Io(#[from] std::io::Error),
69
70    /// A backend-specific error not covered by the common variants.
71    #[error("backend error: {0}")]
72    BackendSpecific(Box<dyn std::error::Error + Send + Sync>),
73}