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