1use etdl_parser::ast::EtlDocument;
37use etdl_parser::asyncapi::AsyncApiRegistry;
38
39pub mod codegen;
40pub mod fault_tree;
41pub mod reliability;
42mod typeck;
43pub mod validate;
44
45pub use codegen::{CodeGenerator, RustCodeGenerator};
46pub use validate::Diagnostic;
47
48pub struct Compiler {
49 pub rust_codegen: RustCodeGenerator,
50}
51
52#[derive(Debug, Clone)]
54pub struct CompilationResult {
55 pub diagnostics: Vec<Diagnostic>,
56 pub rust_output: Option<String>,
57 pub build_manifest: Option<serde_json::Value>,
60}
61
62impl Compiler {
63 pub fn new() -> Self {
64 Compiler {
65 rust_codegen: RustCodeGenerator::new(),
66 }
67 }
68
69 pub fn validate(
73 &self,
74 doc: &EtlDocument,
75 asyncapi_registry: &AsyncApiRegistry,
76 ) -> Vec<Diagnostic> {
77 self.validate_with_base(doc, asyncapi_registry, std::path::Path::new("."))
78 }
79
80 pub fn validate_with_base(
82 &self,
83 doc: &EtlDocument,
84 asyncapi_registry: &AsyncApiRegistry,
85 base_dir: &std::path::Path,
86 ) -> Vec<Diagnostic> {
87 let mut diagnostics = Vec::new();
88
89 validate::validate_document(doc, asyncapi_registry, &mut diagnostics);
90
91 if diagnostics.iter().any(|d| d.is_error()) {
92 return diagnostics;
93 }
94
95 let (resolved_events, _manifest) =
98 reliability::resolve_reliability(doc, base_dir, &mut diagnostics);
99 let overrides: fault_tree::BasicEventOverrides = resolved_events
100 .iter()
101 .map(|r| (r.basic_event.clone(), r.resolved.value))
102 .collect();
103
104 let fault_tree_probs =
105 fault_tree::resolve_fault_trees_with_overrides(doc, &overrides, &mut diagnostics);
106 let resolved_probabilities =
107 validate::resolve_probability_links(doc, &fault_tree_probs, &mut diagnostics);
108
109 validate::validate_probability_sums(doc, &resolved_probabilities, &mut diagnostics);
110
111 if diagnostics.iter().any(|d| d.is_error()) {
112 return diagnostics;
113 }
114
115 typeck::type_check_conditions(doc, asyncapi_registry, &mut diagnostics);
116
117 diagnostics
118 }
119
120 pub fn compile(
121 &self,
122 doc: &EtlDocument,
123 asyncapi_registry: &AsyncApiRegistry,
124 ) -> CompilationResult {
125 self.compile_with_base(doc, asyncapi_registry, std::path::Path::new("."))
126 }
127
128 pub fn compile_with_base(
131 &self,
132 doc: &EtlDocument,
133 asyncapi_registry: &AsyncApiRegistry,
134 base_dir: &std::path::Path,
135 ) -> CompilationResult {
136 let mut diagnostics = self.validate_with_base(doc, asyncapi_registry, base_dir);
137
138 let has_errors = diagnostics.iter().any(|d| d.is_error());
139 if has_errors {
140 return CompilationResult {
141 diagnostics,
142 rust_output: None,
143 build_manifest: None,
144 };
145 }
146
147 let (resolved_events, manifest) =
151 reliability::resolve_reliability(doc, base_dir, &mut diagnostics);
152
153 let overrides: fault_tree::BasicEventOverrides = resolved_events
154 .iter()
155 .map(|r| (r.basic_event.clone(), r.resolved.value))
156 .collect();
157
158 let build_manifest = manifest.as_ref().and_then(|m| serde_json::to_value(m).ok());
159
160 let fault_tree_probs =
161 fault_tree::resolve_fault_trees_with_overrides(doc, &overrides, &mut diagnostics);
162
163 let mut rust_output = String::new();
164 let gen_result = self.rust_codegen.generate_all(
165 doc,
166 &fault_tree_probs,
167 asyncapi_registry,
168 &mut diagnostics,
169 );
170
171 if let Ok(gen_code) = gen_result {
172 rust_output = gen_code;
173 }
174
175 CompilationResult {
176 diagnostics,
177 rust_output: if rust_output.is_empty() {
178 None
179 } else {
180 Some(rust_output)
181 },
182 build_manifest,
183 }
184 }
185}
186
187impl Default for Compiler {
188 fn default() -> Self {
189 Self::new()
190 }
191}