1use std::{io::Write, vec};
4
5use crate::ast::*;
6
7pub fn print<W: Write>(defs: &[Def], width: usize, out: &mut W) -> std::io::Result<()> {
9 for (i, def) in defs.iter().enumerate() {
10 if i > 0 {
11 writeln!(out)?;
12 }
13 print_node(def, width, out)?;
14 writeln!(out)?;
15 }
16 Ok(())
17}
18
19pub fn print_node<N: ToSExpr, W: Write>(
21 node: &N,
22 width: usize,
23 out: &mut W,
24) -> std::io::Result<()> {
25 let mut printer = Printer::new(out, width);
26 let sexpr = node.to_sexpr();
27 printer.print(&sexpr)
28}
29
30#[derive(Debug, Clone, PartialEq, Eq)]
32pub enum SExpr {
33 Atom(String),
35 Binding(String, Box<SExpr>),
37 List(Vec<SExpr>),
39}
40
41pub trait ToSExpr {
43 fn to_sexpr(&self) -> SExpr;
45}
46
47impl SExpr {
48 fn atom<S: ToString>(atom: S) -> Self {
49 SExpr::Atom(atom.to_string())
50 }
51
52 fn list(items: &[impl ToSExpr]) -> Self {
53 SExpr::List(items.into_iter().map(|i| i.to_sexpr()).collect())
54 }
55
56 fn tagged(tag: &str, items: &[impl ToSExpr]) -> Self {
57 let mut parts = vec![SExpr::atom(tag)];
58 parts.extend(items.iter().map(ToSExpr::to_sexpr));
59 SExpr::List(parts)
60 }
61}
62
63struct Printer<'a, W: Write> {
64 out: &'a mut W,
65 col: usize,
66 indent: usize,
67 width: usize,
68}
69
70#[derive(Clone, Copy, PartialEq, Eq)]
71enum Wrapping {
72 Wrap,
73 SingleLine,
74}
75
76impl<'a, W: Write> Printer<'a, W> {
77 fn new(out: &'a mut W, width: usize) -> Self {
78 Self {
79 out,
80 col: 0,
81 indent: 0,
82 width,
83 }
84 }
85
86 fn print(&mut self, sexpr: &SExpr) -> std::io::Result<()> {
87 self.print_wrapped(sexpr, Wrapping::Wrap)
88 }
89
90 fn print_wrapped(&mut self, sexpr: &SExpr, wrapping: Wrapping) -> std::io::Result<()> {
91 match sexpr {
92 SExpr::Atom(atom) => self.put(atom),
93 SExpr::Binding(name, sexpr) => {
94 self.put(name)?;
95 self.put(" @ ")?;
96 self.print_wrapped(sexpr, wrapping)
97 }
98 SExpr::List(items) => {
99 if wrapping == Wrapping::SingleLine || self.fits(sexpr) {
100 self.put("(")?;
101 for (i, item) in items.iter().enumerate() {
102 if i > 0 {
103 self.put(" ")?;
104 }
105 self.print_wrapped(item, Wrapping::SingleLine)?;
106 }
107 self.put(")")
108 } else {
109 let (first, rest) = items.split_first().expect("non-empty list");
110 self.put("(")?;
111 self.print_wrapped(first, wrapping)?;
112 self.indent += 1;
113 for item in rest {
114 self.nl()?;
115 self.print_wrapped(item, wrapping)?;
116 }
117 self.indent -= 1;
118 self.nl()?;
119 self.put(")")?;
120 Ok(())
121 }
122 }
123 }
124 }
125
126 fn fits(&self, sexpr: &SExpr) -> bool {
128 let Some(mut remaining) = self.width.checked_sub(self.col) else {
129 return false;
130 };
131 let mut stack = vec![sexpr];
132 while let Some(sexpr) = stack.pop() {
133 let consume = match sexpr {
134 SExpr::Atom(atom) => atom.len(),
135 SExpr::Binding(name, inner) => {
136 stack.push(inner);
137 name.len() + 3 }
139 SExpr::List(items) => {
140 stack.extend(items.iter().rev());
141 2 + items.len() - 1 }
143 };
144 if consume > remaining {
145 return false;
146 }
147 remaining -= consume;
148 }
149 true
150 }
151
152 fn put(&mut self, s: &str) -> std::io::Result<()> {
153 write!(self.out, "{s}")?;
154 self.col += s.len();
155 Ok(())
156 }
157
158 fn nl(&mut self) -> std::io::Result<()> {
159 writeln!(self.out)?;
160 self.col = 0;
161 for _ in 0..self.indent {
162 write!(self.out, " ")?;
163 }
164 Ok(())
165 }
166}
167
168impl ToSExpr for Def {
169 fn to_sexpr(&self) -> SExpr {
170 match self {
171 Def::Pragma(_) => unimplemented!("pragmas not supported"),
172 Def::Type(ty) => ty.to_sexpr(),
173 Def::Rule(rule) => rule.to_sexpr(),
174 Def::Extractor(extractor) => extractor.to_sexpr(),
175 Def::Decl(decl) => decl.to_sexpr(),
176 Def::Spec(spec) => spec.to_sexpr(),
177 Def::Model(model) => model.to_sexpr(),
178 Def::Form(form) => form.to_sexpr(),
179 Def::Instantiation(instantiation) => instantiation.to_sexpr(),
180 Def::Extern(ext) => ext.to_sexpr(),
181 Def::Converter(converter) => converter.to_sexpr(),
182 }
183 }
184}
185
186impl ToSExpr for Type {
187 fn to_sexpr(&self) -> SExpr {
188 let Type {
189 name,
190 ty,
191 is_extern,
192 is_nodebug,
193 pos: _,
194 } = self;
195 let mut parts = vec![SExpr::atom("type"), name.to_sexpr()];
196 if *is_extern {
197 parts.push(SExpr::atom("extern"));
198 }
199 if *is_nodebug {
200 parts.push(SExpr::Atom("nodebug".to_string()));
201 }
202 parts.push(ty.to_sexpr());
203 SExpr::List(parts)
204 }
205}
206
207impl ToSExpr for Rule {
208 fn to_sexpr(&self) -> SExpr {
209 let Rule {
210 name,
211 prio,
212 pattern,
213 iflets,
214 expr,
215 pos: _,
216 } = self;
217 let mut parts = vec![SExpr::atom("rule")];
218 if let Some(name) = name {
219 parts.push(name.to_sexpr());
220 }
221 if let Some(prio) = prio {
222 parts.push(SExpr::atom(prio.to_string()));
223 }
224 parts.push(pattern.to_sexpr());
225 parts.extend(iflets.iter().map(ToSExpr::to_sexpr));
226 parts.push(expr.to_sexpr());
227 SExpr::List(parts)
228 }
229}
230
231impl ToSExpr for Extractor {
232 fn to_sexpr(&self) -> SExpr {
233 let Extractor {
234 term,
235 args,
236 template,
237 pos: _,
238 } = self;
239 let mut sig = vec![term.to_sexpr()];
240 sig.extend(args.iter().map(ToSExpr::to_sexpr));
241
242 let mut parts = vec![SExpr::atom("extractor")];
243 parts.push(SExpr::List(sig));
244 parts.push(template.to_sexpr());
245 SExpr::List(parts)
246 }
247}
248
249impl ToSExpr for Decl {
250 fn to_sexpr(&self) -> SExpr {
251 let Decl {
252 term,
253 arg_tys,
254 ret_ty,
255 pure,
256 multi,
257 partial,
258 pos: _,
259 } = self;
260 let mut parts = vec![SExpr::atom("decl")];
261 if *pure {
262 parts.push(SExpr::atom("pure"));
263 }
264 if *multi {
265 parts.push(SExpr::atom("multi"));
266 }
267 if *partial {
268 parts.push(SExpr::atom("partial"));
269 }
270 parts.push(term.to_sexpr());
271 parts.push(SExpr::list(arg_tys));
272 parts.push(ret_ty.to_sexpr());
273 SExpr::List(parts)
274 }
275}
276
277impl ToSExpr for Spec {
278 fn to_sexpr(&self) -> SExpr {
279 let Spec {
280 term,
281 args,
282 provides,
283 requires,
284 } = self;
285 let mut sig = vec![term.to_sexpr()];
286 sig.extend(args.iter().map(ToSExpr::to_sexpr));
287
288 let mut parts = vec![SExpr::atom("spec")];
289 parts.push(SExpr::List(sig));
290 if !provides.is_empty() {
291 parts.push(SExpr::tagged("provide", &self.provides));
292 }
293 if !requires.is_empty() {
294 parts.push(SExpr::tagged("require", &self.requires));
295 }
296 SExpr::List(parts)
297 }
298}
299
300impl ToSExpr for Model {
301 fn to_sexpr(&self) -> SExpr {
302 let Model { name, val } = self;
303 SExpr::List(vec![SExpr::atom("model"), name.to_sexpr(), val.to_sexpr()])
304 }
305}
306
307impl ToSExpr for Form {
308 fn to_sexpr(&self) -> SExpr {
309 let Form {
310 name,
311 signatures,
312 pos: _,
313 } = self;
314 let mut parts = vec![SExpr::atom("form"), name.to_sexpr()];
315 parts.extend(signatures.iter().map(ToSExpr::to_sexpr));
316 SExpr::List(parts)
317 }
318}
319
320impl ToSExpr for Instantiation {
321 fn to_sexpr(&self) -> SExpr {
322 let Instantiation {
323 term,
324 form,
325 signatures,
326 pos: _,
327 } = self;
328 let mut parts = vec![SExpr::atom("instantiate"), term.to_sexpr()];
329 if let Some(form) = form {
330 parts.push(form.to_sexpr());
331 } else {
332 parts.extend(signatures.iter().map(ToSExpr::to_sexpr));
333 }
334 SExpr::List(parts)
335 }
336}
337
338impl ToSExpr for Extern {
339 fn to_sexpr(&self) -> SExpr {
340 match self {
341 Extern::Extractor {
342 term,
343 func,
344 infallible,
345 pos: _,
346 } => {
347 let mut parts = vec![SExpr::atom("extern"), SExpr::atom("extractor")];
348 if *infallible {
349 parts.push(SExpr::atom("infallible"));
350 }
351 parts.push(term.to_sexpr());
352 parts.push(func.to_sexpr());
353 SExpr::List(parts)
354 }
355 Extern::Constructor { term, func, pos: _ } => SExpr::List(vec![
356 SExpr::atom("extern"),
357 SExpr::atom("constructor"),
358 term.to_sexpr(),
359 func.to_sexpr(),
360 ]),
361 Extern::Const { name, ty, pos: _ } => SExpr::List(vec![
362 SExpr::atom("extern"),
363 SExpr::atom("const"),
364 SExpr::atom(format!("${}", name.0)),
365 ty.to_sexpr(),
366 ]),
367 }
368 }
369}
370
371impl ToSExpr for Converter {
372 fn to_sexpr(&self) -> SExpr {
373 let Converter {
374 inner_ty,
375 outer_ty,
376 term,
377 pos: _,
378 } = self;
379 SExpr::List(vec![
380 SExpr::atom("convert"),
381 inner_ty.to_sexpr(),
382 outer_ty.to_sexpr(),
383 term.to_sexpr(),
384 ])
385 }
386}
387
388impl ToSExpr for TypeValue {
389 fn to_sexpr(&self) -> SExpr {
390 match self {
391 TypeValue::Primitive(name, _) => {
392 SExpr::List(vec![SExpr::atom("primitive"), name.to_sexpr()])
393 }
394 TypeValue::Enum(variants, _) => {
395 let mut parts = vec![SExpr::atom("enum")];
396 parts.extend(variants.iter().map(ToSExpr::to_sexpr));
397 SExpr::List(parts)
398 }
399 }
400 }
401}
402
403impl ToSExpr for Variant {
404 fn to_sexpr(&self) -> SExpr {
405 let Variant {
406 name,
407 fields,
408 pos: _,
409 } = self;
410 let mut parts = vec![name.to_sexpr()];
411 parts.extend(fields.iter().map(ToSExpr::to_sexpr));
412 SExpr::List(parts)
413 }
414}
415
416impl ToSExpr for Field {
417 fn to_sexpr(&self) -> SExpr {
418 let Field { name, ty, pos: _ } = self;
419 SExpr::List(vec![name.to_sexpr(), ty.to_sexpr()])
420 }
421}
422
423impl ToSExpr for ModelValue {
424 fn to_sexpr(&self) -> SExpr {
425 match self {
426 ModelValue::TypeValue(mt) => SExpr::List(vec![SExpr::atom("type"), mt.to_sexpr()]),
427 ModelValue::EnumValues(enumerators) => {
428 let mut parts = vec![SExpr::atom("enum")];
429 for (variant, value) in enumerators {
430 parts.push(SExpr::List(vec![variant.to_sexpr(), value.to_sexpr()]));
431 }
432 SExpr::List(parts)
433 }
434 }
435 }
436}
437
438impl ToSExpr for ModelType {
439 fn to_sexpr(&self) -> SExpr {
440 match self {
441 ModelType::Unit => SExpr::atom("Unit"),
442 ModelType::Int => SExpr::atom("Int"),
443 ModelType::Bool => SExpr::atom("Bool"),
444 ModelType::BitVec(Some(size)) => {
445 SExpr::List(vec![SExpr::atom("bv"), SExpr::atom(size)])
446 }
447 ModelType::BitVec(None) => SExpr::List(vec![SExpr::atom("bv")]),
448 }
449 }
450}
451
452impl ToSExpr for Signature {
453 fn to_sexpr(&self) -> SExpr {
454 let Signature {
455 args,
456 ret,
457 canonical,
458 pos: _,
459 } = self;
460 SExpr::List(vec![
461 SExpr::tagged("args", args),
462 SExpr::tagged("ret", std::slice::from_ref(ret)),
463 SExpr::tagged("canon", std::slice::from_ref(canonical)),
464 ])
465 }
466}
467
468impl ToSExpr for SpecExpr {
469 fn to_sexpr(&self) -> SExpr {
470 match self {
471 SpecExpr::ConstInt { val, pos: _ } => SExpr::atom(val),
472 SpecExpr::ConstBitVec { val, width, pos: _ } => SExpr::atom(if *width % 4 == 0 {
473 format!("#x{val:0width$x}", width = *width as usize / 4)
474 } else {
475 format!("#b{val:0width$b}", width = *width as usize)
476 }),
477 SpecExpr::ConstBool { val, pos: _ } => SExpr::atom(if *val { "true" } else { "false" }),
478 SpecExpr::ConstUnit { pos: _ } => SExpr::List(Vec::new()),
479 SpecExpr::Var { var, pos: _ } => var.to_sexpr(),
480 SpecExpr::Op { op, args, pos: _ } => {
481 let mut parts = vec![op.to_sexpr()];
482 parts.extend(args.iter().map(ToSExpr::to_sexpr));
483 SExpr::List(parts)
484 }
485 SpecExpr::Pair { l, r } => SExpr::List(vec![l.to_sexpr(), r.to_sexpr()]),
486 SpecExpr::Enum { name } => SExpr::List(vec![name.to_sexpr()]),
487 }
488 }
489}
490
491impl ToSExpr for SpecOp {
492 fn to_sexpr(&self) -> SExpr {
493 SExpr::atom(match self {
494 SpecOp::Eq => "=",
495 SpecOp::And => "and",
496 SpecOp::Not => "not",
497 SpecOp::Imp => "=>",
498 SpecOp::Or => "or",
499 SpecOp::Lte => "<=",
500 SpecOp::Lt => "<",
501 SpecOp::Gte => ">=",
502 SpecOp::Gt => ">",
503 SpecOp::BVNot => "bvnot",
504 SpecOp::BVAnd => "bvand",
505 SpecOp::BVOr => "bvor",
506 SpecOp::BVXor => "bvxor",
507 SpecOp::BVNeg => "bvneg",
508 SpecOp::BVAdd => "bvadd",
509 SpecOp::BVSub => "bvsub",
510 SpecOp::BVMul => "bvmul",
511 SpecOp::BVUdiv => "bvudiv",
512 SpecOp::BVUrem => "bvurem",
513 SpecOp::BVSdiv => "bvsdiv",
514 SpecOp::BVSrem => "bvsrem",
515 SpecOp::BVShl => "bvshl",
516 SpecOp::BVLshr => "bvlshr",
517 SpecOp::BVAshr => "bvashr",
518 SpecOp::BVSaddo => "bvsaddo",
519 SpecOp::BVUle => "bvule",
520 SpecOp::BVUlt => "bvult",
521 SpecOp::BVUgt => "bvugt",
522 SpecOp::BVUge => "bvuge",
523 SpecOp::BVSlt => "bvslt",
524 SpecOp::BVSle => "bvsle",
525 SpecOp::BVSgt => "bvsgt",
526 SpecOp::BVSge => "bvsge",
527 SpecOp::Rotr => "rotr",
528 SpecOp::Rotl => "rotl",
529 SpecOp::Extract => "extract",
530 SpecOp::ZeroExt => "zero_ext",
531 SpecOp::SignExt => "sign_ext",
532 SpecOp::Concat => "concat",
533 SpecOp::ConvTo => "conv_to",
534 SpecOp::Int2BV => "int2bv",
535 SpecOp::WidthOf => "widthof",
536 SpecOp::If => "if",
537 SpecOp::Switch => "switch",
538 SpecOp::Popcnt => "popcnt",
539 SpecOp::Rev => "rev",
540 SpecOp::Cls => "cls",
541 SpecOp::Clz => "clz",
542 SpecOp::Subs => "subs",
543 SpecOp::BV2Int => "bv2int",
544 SpecOp::LoadEffect => "load_effect",
545 SpecOp::StoreEffect => "store_effect",
546 })
547 }
548}
549
550impl ToSExpr for Pattern {
551 fn to_sexpr(&self) -> SExpr {
552 match self {
553 Pattern::Var {
554 var: Ident(var, _),
555 pos: _,
556 } => SExpr::atom(var.clone()),
557 Pattern::BindPattern {
558 var: Ident(var, _),
559 subpat,
560 pos: _,
561 } => SExpr::Binding(var.clone(), Box::new(subpat.to_sexpr())),
562 Pattern::ConstInt { val, pos: _ } => SExpr::atom(val),
563 Pattern::ConstBool { val, pos: _ } => SExpr::atom(if *val { "true" } else { "false" }),
564 Pattern::ConstPrim { val, pos: _ } => SExpr::atom(format!("${}", val.0)),
565 Pattern::Wildcard { pos: _ } => SExpr::atom("_"),
566 Pattern::Term { sym, args, pos: _ } => {
567 let mut parts = vec![sym.to_sexpr()];
568 parts.extend(args.iter().map(ToSExpr::to_sexpr));
569 SExpr::List(parts)
570 }
571 Pattern::And { subpats, pos: _ } => {
572 let mut parts = vec![SExpr::atom("and")];
573 parts.extend(subpats.iter().map(ToSExpr::to_sexpr));
574 SExpr::List(parts)
575 }
576 Pattern::MacroArg { .. } => unimplemented!("macro arguments are for internal use only"),
577 }
578 }
579}
580
581impl ToSExpr for IfLet {
582 fn to_sexpr(&self) -> SExpr {
583 let IfLet {
584 pattern,
585 expr,
586 pos: _,
587 } = self;
588 SExpr::List(vec![
589 SExpr::atom("if-let"),
590 pattern.to_sexpr(),
591 expr.to_sexpr(),
592 ])
593 }
594}
595
596impl ToSExpr for Expr {
597 fn to_sexpr(&self) -> SExpr {
598 match self {
599 Expr::Term { sym, args, pos: _ } => {
600 let mut parts = vec![sym.to_sexpr()];
601 parts.extend(args.iter().map(ToSExpr::to_sexpr));
602 SExpr::List(parts)
603 }
604 Expr::Var { name, pos: _ } => name.to_sexpr(),
605 Expr::ConstInt { val, pos: _ } => SExpr::atom(val),
606 Expr::ConstBool { val, pos: _ } => SExpr::atom(if *val { "true" } else { "false" }),
607 Expr::ConstPrim { val, pos: _ } => SExpr::atom(format!("${}", val.0)),
608 Expr::Let { defs, body, pos: _ } => {
609 let mut parts = vec![SExpr::atom("let")];
610 parts.push(SExpr::list(&defs));
611 parts.push(body.to_sexpr());
612 SExpr::List(parts)
613 }
614 }
615 }
616}
617
618impl ToSExpr for LetDef {
619 fn to_sexpr(&self) -> SExpr {
620 let LetDef {
621 var,
622 ty,
623 val,
624 pos: _,
625 } = self;
626 SExpr::List(vec![var.to_sexpr(), ty.to_sexpr(), val.to_sexpr()])
627 }
628}
629
630impl ToSExpr for Ident {
631 fn to_sexpr(&self) -> SExpr {
632 let Ident(name, _) = self;
633 SExpr::atom(name.clone())
634 }
635}