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}