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(target: &chipi_core::config::GenTarget) -> Result<(), Box<dyn std::error::Error>> {
73 let (def, deps) = chipi_core::parser::parse_file_with_deps(Path::new(&target.input))
74 .map_err(|errs| Box::new(chipi_core::error::Errors(errs)) as Box<dyn std::error::Error>)?;
75
76 for dep in &deps {
77 println!("cargo:rerun-if-changed={}", dep.display());
78 }
79
80 let validated = chipi_core::validate::validate(&def)
81 .map_err(|errs| Box::new(chipi_core::error::Errors(errs)) as Box<dyn std::error::Error>)?;
82
83 let backend = chipi_core::backend::get_backend(&target.lang).unwrap();
84 let code = backend.generate(&validated, target)?;
85 std::fs::write(&target.output, code)?;
86
87 if target.format {
88 if let Some(cmd) = backend.formatter_command() {
89 chipi_core::backend::run_formatter(cmd, &target.output);
90 }
91 }
92
93 Ok(())
94}
95
96fn run_lut_target(target: &chipi_core::config::LutTarget) -> Result<(), Box<dyn std::error::Error>> {
97 let (_, deps) = chipi_core::parser::parse_file_with_deps(Path::new(&target.input))
98 .map_err(|errs| Box::new(chipi_core::error::Errors(errs)) as Box<dyn std::error::Error>)?;
99
100 for dep in &deps {
101 println!("cargo:rerun-if-changed={}", dep.display());
102 }
103
104 chipi_core::LutBuilder::run_target(target)
105}
106
107pub fn generate(input: impl Into<String>) -> GenBuilder {
113 GenBuilder {
114 input: input.into(),
115 output: None,
116 type_map: HashMap::new(),
117 dispatch: Dispatch::FnPtrLut,
118 dispatch_overrides: HashMap::new(),
119 format: false,
120 }
121}
122
123pub struct GenBuilder {
125 input: String,
126 output: Option<String>,
127 type_map: HashMap<String, String>,
128 dispatch: Dispatch,
129 dispatch_overrides: HashMap<String, Dispatch>,
130 format: bool,
131}
132
133impl GenBuilder {
134 pub fn type_map(mut self, chipi_type: &str, rust_path: &str) -> Self {
136 self.type_map
137 .insert(chipi_type.to_string(), rust_path.to_string());
138 self
139 }
140
141 pub fn dispatch_default(mut self, dispatch: Dispatch) -> Self {
143 self.dispatch = dispatch;
144 self
145 }
146
147 pub fn dispatch_for(mut self, decoder_name: &str, dispatch: Dispatch) -> Self {
149 self.dispatch_overrides
150 .insert(decoder_name.to_string(), dispatch);
151 self
152 }
153
154 pub fn format(mut self, yes: bool) -> Self {
156 self.format = yes;
157 self
158 }
159
160 pub fn output(mut self, path: impl Into<String>) -> Self {
162 self.output = Some(path.into());
163 self
164 }
165
166 pub fn run(self) -> Result<(), Box<dyn std::error::Error>> {
168 let output = self.output.as_deref().ok_or("output path not set")?;
169 let target = chipi_core::config::GenTarget {
170 input: self.input,
171 lang: "rust".to_string(),
172 output: output.to_string(),
173 format: self.format,
174 dispatch: self.dispatch,
175 dispatch_overrides: self.dispatch_overrides,
176 type_map: self.type_map,
177 lang_options: None,
178 };
179 run_gen_target(&target)
180 }
181}
182
183pub fn lut(input: impl Into<String>) -> LutBuilder {
189 LutBuilder {
190 input: input.into(),
191 output: None,
192 handler_mod: String::new(),
193 ctx_type: String::new(),
194 dispatch: Dispatch::FnPtrLut,
195 groups: HashMap::new(),
196 lut_mod: None,
197 instr_type: None,
198 raw_expr: None,
199 instr_type_output: None,
200 }
201}
202
203pub struct LutBuilder {
205 input: String,
206 output: Option<String>,
207 handler_mod: String,
208 ctx_type: String,
209 dispatch: Dispatch,
210 groups: HashMap<String, Vec<String>>,
211 lut_mod: Option<String>,
212 instr_type: Option<String>,
213 raw_expr: Option<String>,
214 instr_type_output: Option<String>,
215}
216
217impl LutBuilder {
218 pub fn output(mut self, path: impl Into<String>) -> Self {
219 self.output = Some(path.into());
220 self
221 }
222
223 pub fn handler_mod(mut self, m: impl Into<String>) -> Self {
224 self.handler_mod = m.into();
225 self
226 }
227
228 pub fn ctx_type(mut self, t: impl Into<String>) -> Self {
229 self.ctx_type = t.into();
230 self
231 }
232
233 pub fn dispatch(mut self, strategy: Dispatch) -> Self {
234 self.dispatch = strategy;
235 self
236 }
237
238 pub fn group(mut self, name: impl Into<String>, instrs: impl IntoIterator<Item = impl Into<String>>) -> Self {
239 self.groups.insert(name.into(), instrs.into_iter().map(|s| s.into()).collect());
240 self
241 }
242
243 pub fn lut_mod(mut self, path: impl Into<String>) -> Self {
244 self.lut_mod = Some(path.into());
245 self
246 }
247
248 pub fn instr_type(mut self, t: impl Into<String>) -> Self {
249 self.instr_type = Some(t.into());
250 self
251 }
252
253 pub fn raw_expr(mut self, expr: impl Into<String>) -> Self {
254 self.raw_expr = Some(expr.into());
255 self
256 }
257
258 pub fn instr_type_output(mut self, path: impl Into<String>) -> Self {
260 self.instr_type_output = Some(path.into());
261 self
262 }
263
264 pub fn run(self) -> Result<(), Box<dyn std::error::Error>> {
266 let output = self.output.as_deref().ok_or("output path not set")?;
267 let target = chipi_core::config::LutTarget {
268 input: self.input,
269 output: output.to_string(),
270 handler_mod: self.handler_mod,
271 ctx_type: self.ctx_type,
272 dispatch: self.dispatch,
273 groups: self.groups,
274 lut_mod: self.lut_mod,
275 instr_type: self.instr_type,
276 raw_expr: self.raw_expr,
277 instr_type_output: self.instr_type_output,
278 };
279 run_lut_target(&target)
280 }
281}