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