1use core::fmt;
2use std::{borrow::Borrow as _, fmt::Display};
3
4use super::*;
5
6#[derive(Debug, Clone, Copy)]
7pub struct FloatDisplay(pub f64);
8impl fmt::Display for FloatDisplay {
9 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> std::fmt::Result {
10 write!(f, "{:.7e}", self.0)
11 }
12}
13
14pub struct TableFloatDisplay(pub f64);
15impl fmt::Display for TableFloatDisplay {
16 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> std::fmt::Result {
17 if self.0.is_sign_positive() {
18 write!(f, " {: <13.7e}", self.0)
19 } else {
20 write!(f, "{: <14.7e}", self.0)
21 }
22 }
23}
24
25pub struct OptionDispaly<'a, T, F: Fn(&T, &mut fmt::Formatter<'_>) -> fmt::Result>(
26 pub &'a Option<T>,
27 pub F,
28);
29impl<T, F: Fn(&T, &mut fmt::Formatter<'_>) -> fmt::Result> Display for OptionDispaly<'_, T, F> {
30 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> std::fmt::Result {
31 if let Some(t) = self.0 {
32 self.1(t, f)
33 } else {
34 Ok(())
35 }
36 }
37}
38
39pub fn display_wrap<
40 W: fmt::Write,
41 T,
42 I: Iterator<Item = T>,
43 SEP: fmt::Display,
44 F: FnMut(T, &mut W) -> fmt::Result,
45>(
46 f: &mut W,
47 iter: I,
48 mut fmt_one: F,
49 line_sep: SEP,
50 item_sep: char,
51 wrap_size: usize,
52) -> fmt::Result {
53 use itertools::Itertools as _;
54 for mut ts in iter.into_iter().chunks(wrap_size).into_iter() {
55 write!(f, "\n{line_sep}")?;
56 if let Some(first) = ts.next() {
57 fmt_one(first, f)?;
58 for t in ts {
59 write!(f, "{item_sep}")?;
60 fmt_one(t, f)?;
61 }
62 }
63 }
64 Ok(())
65}
66
67pub fn display_inline_res<
68 E: From<fmt::Error>,
69 W: fmt::Write,
70 T,
71 I: Iterator<Item = Result<T, E>>,
72 F: FnMut(T, &mut W) -> fmt::Result,
73>(
74 f: &mut W,
75 iter: I,
76 mut fmt_one: F,
77 sep: char,
78 skip_first_sep: bool,
79) -> Result<(), E> {
80 let mut iter = iter.into_iter();
81 if skip_first_sep {
82 if let Some(first) = iter.next() {
83 fmt_one(first?, f)?;
84 }
85 }
86 for t in iter {
87 write!(f, "{sep}")?;
88 fmt_one(t?, f)?;
89 }
90 Ok(())
91}
92
93pub fn display_inline<
94 W: fmt::Write,
95 T,
96 I: Iterator<Item = T>,
97 F: FnMut(T, &mut W) -> fmt::Result,
98>(
99 f: &mut W,
100 iter: I,
101 mut fmt_one: F,
102 sep: char,
103 skip_first_sep: bool,
104) -> fmt::Result {
105 let mut iter = iter.into_iter();
106 if skip_first_sep {
107 if let Some(first) = iter.next() {
108 fmt_one(first, f)?;
109 }
110 }
111 for t in iter {
112 write!(f, "{sep}")?;
113 fmt_one(t, f)?;
114 }
115 Ok(())
116}
117
118pub fn display_multiline<
119 W: fmt::Write,
120 T,
121 I: Iterator<Item = T>,
122 F: FnMut(T, &mut W) -> fmt::Result,
123>(
124 f: &mut W,
125 iter: I,
126 mut fmt_one: F,
127) -> fmt::Result {
128 for t in iter.into_iter() {
129 writeln!(f)?;
130 fmt_one(t, f)?;
131 }
132 Ok(())
133}
134
135impl fmt::Display for AST<'_> {
136 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> std::fmt::Result {
137 DefaultFmt.ast(self, f)
138 }
139}
140impl fmt::Display for Subckt<'_> {
141 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> std::fmt::Result {
142 DefaultFmt.subckt(self, f)
143 }
144}
145
146#[derive(Debug, Clone, Copy)]
147pub struct DefaultFmt;
148impl SpiceFmt for DefaultFmt {}
149
150pub trait SpiceFmt: Sized {
151 fn value<W: fmt::Write>(&self, t: &ast::Value<'_>, f: &mut W) -> fmt::Result {
152 match t {
153 ast::Value::Num(float) => write!(f, "{}", FloatDisplay(*float)),
154 ast::Value::Expr(expr) => write!(f, "'{expr}'"),
155 }
156 }
157 fn key_value<W: fmt::Write>(&self, t: &ast::KeyValue<'_>, f: &mut W) -> fmt::Result {
158 write!(f, "{}=", t.k)?;
159 self.value(&t.v, f)
160 }
161 fn token<W: fmt::Write>(&self, t: &ast::Token<'_>, f: &mut W) -> fmt::Result {
162 match t {
163 ast::Token::KV(t) => self.key_value(t, f),
164 ast::Token::Value(t) => self.value(t, f),
165 ast::Token::V(name) => write!(f, "V({name})"),
166 ast::Token::I(name) => write!(f, "I({name})"),
167 }
168 }
169 fn data_files<W: fmt::Write>(&self, t: &ast::DataFiles<'_>, f: &mut W) -> fmt::Result {
170 display_multiline(f, t.files.iter(), |file, f| {
171 write!(f, "+ FILE='{}'", file.file)?;
172 display_inline(
173 f,
174 file.pname_col_num.iter(),
175 |pname_col_num, f| write!(f, "{}={}", pname_col_num.pname, pname_col_num.col_num),
176 ' ',
177 false,
178 )
179 })?;
180 write!(
181 f,
182 "{}",
183 OptionDispaly(&t.out, |out, f| write!(f, "\n+ OUT='{out}'")),
184 )
185 }
186 fn data<W: fmt::Write>(&self, t: &ast::Data<'_>, f: &mut W) -> fmt::Result {
187 write!(f, ".DATA {}", t.name)?;
188 match &t.values {
189 ast::DataValues::InlineExpr { params, values } => {
190 write!(f, "\n+",)?;
191 display_inline(f, params.iter(), |t, f| write!(f, "{t}"), ' ', false)?;
192 write!(f, " DATAFORM")?;
193 display_wrap(
194 f,
195 values.iter(),
196 |t, f| self.value(t, f),
197 "+ ",
198 ' ',
199 params.len(),
200 )?;
201 }
202 ast::DataValues::InlineNum { params, values } => {
203 write!(f, "\n+",)?;
204 display_inline(f, params.iter(), |t, f| write!(f, "{t}"), ' ', false)?;
205 display_wrap(
206 f,
207 values.iter(),
208 |float, f| write!(f, "{}", FloatDisplay(*float)),
209 "+ ",
210 ' ',
211 params.len(),
212 )?;
213 }
214 ast::DataValues::MER(t) => {
215 write!(f, " MER")?;
216 self.data_files(t, f)?;
217 }
218 ast::DataValues::LAM(t) => {
219 write!(f, " LAM")?;
220 self.data_files(t, f)?;
221 }
222 }
223 write!(f, "\n.ENDDATA")
224 }
225 fn instance<W: fmt::Write>(&self, t: &instance::Instance<'_>, f: &mut W) -> fmt::Result {
226 write!(f, "{} ", t.name)?;
227 self.instance_ctx(&t.ctx, f)
228 }
229 fn instance_ctx<W: fmt::Write>(&self, t: &instance::InstanceCtx<'_>, f: &mut W) -> fmt::Result {
230 match t {
231 instance::InstanceCtx::Resistor(t) => self.resistor(t, f),
232 instance::InstanceCtx::Capacitor(t) => self.capacitor(t, f),
233 instance::InstanceCtx::Inductor(t) => self.inductor(t, f),
234 instance::InstanceCtx::Voltage(t) => self.voltage(t, f),
235 instance::InstanceCtx::Current(t) => self.current(t, f),
236 instance::InstanceCtx::MOSFET(t) => self.mosfet(t, f),
237 instance::InstanceCtx::BJT(t) => self.bjt(t, f),
238 instance::InstanceCtx::Diode(t) => self.diode(t, f),
239 instance::InstanceCtx::Subckt(t) => self.inst_subckt(t, f),
240 instance::InstanceCtx::Unknown {
241 r#type: _,
242 nodes,
243 params,
244 } => {
245 display_inline(f, nodes.iter(), |t, f| write!(f, "{t}"), ' ', true)?;
246 display_inline(f, params.iter(), |t, f| self.key_value(t, f), ' ', false)
247 }
248 }
249 }
250 fn inst_subckt<W: fmt::Write>(&self, t: &instance::Subckt<'_>, f: &mut W) -> fmt::Result {
251 self.ports(t.nodes.iter().map(|s| s.borrow()), f)?;
252 write!(f, " {}", t.cktname)?;
253 display_inline(f, t.params.iter(), |t, f| self.key_value(t, f), ' ', false)
254 }
255 fn voltage<W: fmt::Write>(&self, t: &instance::Voltage<'_>, f: &mut W) -> fmt::Result {
256 write!(f, "{} {} ", t.n1, t.n2)?;
257 self.voltage_source(&t.source, f)
258 }
259 fn current<W: fmt::Write>(&self, t: &instance::Current<'_>, f: &mut W) -> fmt::Result {
260 write!(f, "{} {} ", t.n1, t.n2)?;
261 self.current_source(&t.source, f)
262 }
263 fn voltage_source<W: fmt::Write>(
264 &self,
265 t: &instance::VoltageSource<'_>,
266 f: &mut W,
267 ) -> fmt::Result {
268 match t {
269 instance::VoltageSource::Params(params) => {
270 display_inline(f, params.iter(), |t, f| self.key_value(t, f), ' ', false)
271 }
272 instance::VoltageSource::Value(t) => self.value(t, f),
273 instance::VoltageSource::PWL(t) => self.pwl(t, f),
274 }
275 }
276 fn current_source<W: fmt::Write>(
277 &self,
278 t: &instance::CurrentSource<'_>,
279 f: &mut W,
280 ) -> fmt::Result {
281 match t {
282 instance::CurrentSource::Params(params) => {
283 display_inline(f, params.iter(), |t, f| self.key_value(t, f), ' ', false)
284 }
285 instance::CurrentSource::Value(t) => self.value(t, f),
286 instance::CurrentSource::PWL(t) => self.pwl(t, f),
287 }
288 }
289 fn time_value_point<W: fmt::Write>(
290 &self,
291 t: &instance::TimeValuePoint<'_>,
292 f: &mut W,
293 ) -> fmt::Result {
294 self.value(&t.time, f)?;
295 write!(f, " ")?;
296 self.value(&t.value, f)
297 }
298 fn pwl<W: fmt::Write>(&self, t: &instance::PWL<'_>, f: &mut W) -> fmt::Result {
299 write!(f, "PWL(",)?;
300 display_wrap(
301 f,
302 t.points.iter(),
303 |t, f| self.time_value_point(t, f),
304 "+ ",
305 ' ',
306 1,
307 )?;
308 write!(f, ")",)
309 }
310 fn resistor<W: fmt::Write>(&self, t: &instance::Resistor<'_>, f: &mut W) -> fmt::Result {
311 write!(f, "{} {} ", t.n1, t.n2)?;
312 self.value(&t.value, f)
313 }
314 fn capacitor<W: fmt::Write>(&self, t: &instance::Capacitor<'_>, f: &mut W) -> fmt::Result {
315 write!(f, "{} {} ", t.n1, t.n2)?;
316 self.value(&t.value, f)
317 }
318 fn inductor<W: fmt::Write>(&self, t: &instance::Inductor<'_>, f: &mut W) -> fmt::Result {
319 write!(f, "{} {} ", t.n1, t.n2)?;
320 self.value(&t.value, f)
321 }
322 fn mosfet<W: fmt::Write>(&self, t: &instance::MOSFET<'_>, f: &mut W) -> fmt::Result {
323 write!(
324 f,
325 "{} {} {}{} {}",
326 t.nd,
327 t.ng,
328 t.ns,
329 OptionDispaly(&t.nb, |nb, f| write!(f, " {nb}")),
330 t.mname,
331 )?;
332 display_inline(f, t.params.iter(), |t, f| self.key_value(t, f), ' ', false)
333 }
334 fn bjt<W: fmt::Write>(&self, t: &instance::BJT<'_>, f: &mut W) -> fmt::Result {
335 write!(
336 f,
337 "{} {} {}{} {}",
338 t.nc,
339 t.nb,
340 t.ne,
341 OptionDispaly(&t.ns, |ns, f| write!(f, " {ns}")),
342 t.mname,
343 )?;
344 display_inline(f, t.params.iter(), |t, f| self.key_value(t, f), ' ', false)
345 }
346 fn diode<W: fmt::Write>(&self, t: &instance::Diode<'_>, f: &mut W) -> fmt::Result {
347 write!(f, "{} {} {}", t.nplus, t.nminus, t.mname,)?;
348 display_inline(f, t.params.iter(), |t, f| self.key_value(t, f), ' ', false)
349 }
350 fn model_type<W: fmt::Write>(&self, t: &ast::ModelType<'_>, f: &mut W) -> fmt::Result {
351 match t {
352 ast::ModelType::AMP => write!(f, "AMP"),
353 ast::ModelType::C => write!(f, "C"),
354 ast::ModelType::CORE => write!(f, "CORE"),
355 ast::ModelType::D => write!(f, "D"),
356 ast::ModelType::L => write!(f, "L"),
357 ast::ModelType::NJF => write!(f, "NJF"),
358 ast::ModelType::NMOS => write!(f, "NMOS"),
359 ast::ModelType::NPN => write!(f, "NPN"),
360 ast::ModelType::OPT => write!(f, "OPT"),
361 ast::ModelType::PJF => write!(f, "PJF"),
362 ast::ModelType::PMOS => write!(f, "PMOS"),
363 ast::ModelType::PNP => write!(f, "PNP"),
364 ast::ModelType::R => write!(f, "R"),
365 ast::ModelType::U => write!(f, "U"),
366 ast::ModelType::W => write!(f, "W"),
367 ast::ModelType::S => write!(f, "S"),
368 ast::ModelType::Unknown(span) => write!(f, "{span}"),
369 }
370 }
371 fn model<W: fmt::Write>(&self, t: &ast::Model<'_>, f: &mut W) -> fmt::Result {
372 write!(f, ".MODEL {} ", t.name)?;
373 self.model_type(&t.model_type, f)?;
374 display_wrap(
375 f,
376 t.params.iter(),
377 |t, f| self.key_value(t, f),
378 "+ ",
379 ' ',
380 4,
381 )
382 }
383 fn ports<'a, W: fmt::Write, I: Iterator<Item = &'a str>>(
384 &self,
385 t: I,
386 f: &mut W,
387 ) -> fmt::Result {
388 display_inline(f, t, |t, f| write!(f, "{t}"), ' ', true)
389 }
390 fn subckt<W: fmt::Write>(&self, t: &Subckt<'_>, f: &mut W) -> fmt::Result {
391 write!(f, ".SUBCKT {} ", t.name)?;
392 self.ports(t.ports.iter().map(|s| s.borrow()), f)?;
393 display_inline(f, t.params.iter(), |t, f| self.key_value(t, f), ' ', false)?;
394 self.ast(&t.ast, f)?;
395 write!(f, "\n.ENDS {}", t.name)
396 }
397 fn unknwon<W: fmt::Write>(&self, t: &ast::Unknwon<'_>, f: &mut W) -> fmt::Result {
398 write!(f, ".{}", t.cmd)?;
399 display_inline(f, t.tokens.iter(), |t, f| self.token(t, f), ' ', false)
400 }
401 fn general_cmd<W: fmt::Write>(&self, t: &ast::GeneralCmd, f: &mut W) -> fmt::Result {
402 _ = (t, f);
403 todo!()
404 }
405 fn general<W: fmt::Write>(&self, t: &ast::General<'_>, f: &mut W) -> fmt::Result {
406 write!(f, ".")?;
407 self.general_cmd(&t.cmd, f)?;
408 display_inline(f, t.tokens.iter(), |t, f| self.token(t, f), ' ', false)
409 }
410 fn ast<W: fmt::Write>(&self, t: &AST<'_>, f: &mut W) -> fmt::Result {
411 if !t.option.is_empty() {
412 write!(f, ".OPTION ",)?;
413 display_wrap(
414 f,
415 t.option.iter(),
416 |option, f| {
417 if let Some(v) = &option.1 {
418 write!(f, "{}=", option.0)?;
419 self.value(v, f)
420 } else {
421 write!(f, "{}", option.0)
422 }
423 },
424 "+ ",
425 ' ',
426 4,
427 )?;
428 }
429 if !t.param.is_empty() {
430 write!(f, "\n.PARAM ",)?;
431 display_wrap(f, t.param.iter(), |t, f| self.key_value(t, f), "+ ", ' ', 4)?;
432 }
433 display_multiline(f, t.model.iter(), |t, f| self.model(t, f))?;
434 display_multiline(f, t.subckt.values(), |t, f| self.subckt(t, f))?;
435 display_multiline(f, t.instance.iter(), |t, f| self.instance(t, f))?;
436 display_multiline(f, t.init_condition.iter(), |ic, f| {
437 write!(f, ".IC V({})=", ic.0)?;
438 self.value(&ic.1, f)?;
439 if let Some(subckt) = &ic.2 {
440 write!(f, " suckt={subckt}")
441 } else {
442 Ok(())
443 }
444 })?;
445 display_multiline(f, t.nodeset.iter(), |ic, f| {
446 write!(f, ".NODESET {}=", ic.0)?;
447 self.value(&ic.1, f)?;
448 if let Some(subckt) = &ic.2 {
449 write!(f, " suckt={subckt}")
450 } else {
451 Ok(())
452 }
453 })?;
454 display_multiline(f, t.data.iter(), |t, f| self.data(t, f))?;
455 display_multiline(f, t.general.iter(), |t, f| self.general(t, f))?;
456 display_multiline(f, t.unknwon.iter(), |t, f| self.unknwon(t, f))?;
457 Ok(())
458 }
459}