1use std::collections::HashMap;
37use std::path::Path;
38
39pub use chipi_core::config::Dispatch;
40
41pub fn run_config(path: impl AsRef<Path>) -> Result<(), Box<dyn std::error::Error>> {
50 let manifest_dir = std::env::var("CARGO_MANIFEST_DIR")
51 .map(std::path::PathBuf::from)
52 .unwrap_or_default();
53 let path = manifest_dir.join(path.as_ref());
54 let mut cfg = chipi_core::config::load_config(&path)?;
55 let base_dir = path.parent().unwrap_or(Path::new("."));
56
57 println!("cargo:rerun-if-changed={}", path.display());
58
59 for target in &mut cfg.targets {
60 chipi_core::config::resolve_gen_paths(target, base_dir);
61 run_gen_target(target)?;
62 }
63
64 for target in &mut cfg.lut {
65 chipi_core::config::resolve_lut_paths(target, base_dir);
66 run_lut_target(target)?;
67 }
68
69 Ok(())
70}
71
72fn run_gen_target(
73 target: &chipi_core::config::GenTarget,
74) -> Result<(), Box<dyn std::error::Error>> {
75 let (def, deps) = chipi_core::parser::parse_file_with_deps(Path::new(&target.input))
76 .map_err(|errs| Box::new(chipi_core::error::Errors(errs)) as Box<dyn std::error::Error>)?;
77
78 for dep in &deps {
79 println!("cargo:rerun-if-changed={}", dep.display());
80 }
81
82 let validated = chipi_core::validate::validate(&def)
83 .map_err(|errs| Box::new(chipi_core::error::Errors(errs)) as Box<dyn std::error::Error>)?;
84
85 let backend = chipi_core::backend::get_backend(&target.lang).unwrap();
86 let code = backend.generate(&validated, target)?;
87 std::fs::write(&target.output, code)?;
88
89 if target.format {
90 if let Some(cmd) = backend.formatter_command() {
91 chipi_core::backend::run_formatter(cmd, &target.output);
92 }
93 }
94
95 Ok(())
96}
97
98fn run_lut_target(
99 target: &chipi_core::config::LutTarget,
100) -> Result<(), Box<dyn std::error::Error>> {
101 let (_, deps) = chipi_core::parser::parse_file_with_deps(Path::new(&target.input))
102 .map_err(|errs| Box::new(chipi_core::error::Errors(errs)) as Box<dyn std::error::Error>)?;
103
104 for dep in &deps {
105 println!("cargo:rerun-if-changed={}", dep.display());
106 }
107
108 chipi_core::LutBuilder::run_target(target)
109}
110
111pub fn generate(input: impl Into<String>) -> GenBuilder {
117 GenBuilder {
118 input: input.into(),
119 output: None,
120 type_map: HashMap::new(),
121 dispatch: Dispatch::FnPtrLut,
122 dispatch_overrides: HashMap::new(),
123 format: false,
124 }
125}
126
127pub struct GenBuilder {
129 input: String,
130 output: Option<String>,
131 type_map: HashMap<String, String>,
132 dispatch: Dispatch,
133 dispatch_overrides: HashMap<String, Dispatch>,
134 format: bool,
135}
136
137impl GenBuilder {
138 pub fn type_map(mut self, chipi_type: &str, rust_path: &str) -> Self {
140 self.type_map
141 .insert(chipi_type.to_string(), rust_path.to_string());
142 self
143 }
144
145 pub fn dispatch_default(mut self, dispatch: Dispatch) -> Self {
147 self.dispatch = dispatch;
148 self
149 }
150
151 pub fn dispatch_for(mut self, decoder_name: &str, dispatch: Dispatch) -> Self {
153 self.dispatch_overrides
154 .insert(decoder_name.to_string(), dispatch);
155 self
156 }
157
158 pub fn format(mut self, yes: bool) -> Self {
160 self.format = yes;
161 self
162 }
163
164 pub fn output(mut self, path: impl Into<String>) -> Self {
166 self.output = Some(path.into());
167 self
168 }
169
170 pub fn run(self) -> Result<(), Box<dyn std::error::Error>> {
172 let output = self.output.as_deref().ok_or("output path not set")?;
173 let target = chipi_core::config::GenTarget {
174 input: self.input,
175 lang: "rust".to_string(),
176 output: output.to_string(),
177 format: self.format,
178 dispatch: self.dispatch,
179 dispatch_overrides: self.dispatch_overrides,
180 type_map: self.type_map,
181 lang_options: None,
182 };
183 run_gen_target(&target)
184 }
185}
186
187pub fn lut(input: impl Into<String>) -> LutBuilder {
193 LutBuilder {
194 input: input.into(),
195 output: None,
196 handler_mod: String::new(),
197 ctx_type: String::new(),
198 dispatch: Dispatch::FnPtrLut,
199 groups: HashMap::new(),
200 lut_mod: None,
201 instr_type: None,
202 raw_expr: None,
203 instr_type_output: None,
204 }
205}
206
207pub struct LutBuilder {
209 input: String,
210 output: Option<String>,
211 handler_mod: String,
212 ctx_type: String,
213 dispatch: Dispatch,
214 groups: HashMap<String, Vec<String>>,
215 lut_mod: Option<String>,
216 instr_type: Option<String>,
217 raw_expr: Option<String>,
218 instr_type_output: Option<String>,
219}
220
221impl LutBuilder {
222 pub fn output(mut self, path: impl Into<String>) -> Self {
223 self.output = Some(path.into());
224 self
225 }
226
227 pub fn handler_mod(mut self, m: impl Into<String>) -> Self {
228 self.handler_mod = m.into();
229 self
230 }
231
232 pub fn ctx_type(mut self, t: impl Into<String>) -> Self {
233 self.ctx_type = t.into();
234 self
235 }
236
237 pub fn dispatch(mut self, strategy: Dispatch) -> Self {
238 self.dispatch = strategy;
239 self
240 }
241
242 pub fn group(
243 mut self,
244 name: impl Into<String>,
245 instrs: impl IntoIterator<Item = impl Into<String>>,
246 ) -> Self {
247 self.groups
248 .insert(name.into(), instrs.into_iter().map(|s| s.into()).collect());
249 self
250 }
251
252 pub fn lut_mod(mut self, path: impl Into<String>) -> Self {
253 self.lut_mod = Some(path.into());
254 self
255 }
256
257 pub fn instr_type(mut self, t: impl Into<String>) -> Self {
258 self.instr_type = Some(t.into());
259 self
260 }
261
262 pub fn raw_expr(mut self, expr: impl Into<String>) -> Self {
263 self.raw_expr = Some(expr.into());
264 self
265 }
266
267 pub fn instr_type_output(mut self, path: impl Into<String>) -> Self {
269 self.instr_type_output = Some(path.into());
270 self
271 }
272
273 pub fn run(self) -> Result<(), Box<dyn std::error::Error>> {
275 let output = self.output.as_deref().ok_or("output path not set")?;
276 let target = chipi_core::config::LutTarget {
277 input: self.input,
278 output: output.to_string(),
279 handler_mod: self.handler_mod,
280 ctx_type: self.ctx_type,
281 dispatch: self.dispatch,
282 groups: self.groups,
283 lut_mod: self.lut_mod,
284 instr_type: self.instr_type,
285 raw_expr: self.raw_expr,
286 instr_type_output: self.instr_type_output,
287 subdecoder_groups: Default::default(),
288 };
289 run_lut_target(&target)
290 }
291}