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 rec,
259 pos: _,
260 } = self;
261 let mut parts = vec![SExpr::atom("decl")];
262 if *pure {
263 parts.push(SExpr::atom("pure"));
264 }
265 if *multi {
266 parts.push(SExpr::atom("multi"));
267 }
268 if *partial {
269 parts.push(SExpr::atom("partial"));
270 }
271 if *rec {
272 parts.push(SExpr::atom("rec"));
273 }
274 parts.push(term.to_sexpr());
275 parts.push(SExpr::list(arg_tys));
276 parts.push(ret_ty.to_sexpr());
277 SExpr::List(parts)
278 }
279}
280
281impl ToSExpr for Spec {
282 fn to_sexpr(&self) -> SExpr {
283 let Spec {
284 term,
285 args,
286 provides,
287 requires,
288 } = self;
289 let mut sig = vec![term.to_sexpr()];
290 sig.extend(args.iter().map(ToSExpr::to_sexpr));
291
292 let mut parts = vec![SExpr::atom("spec")];
293 parts.push(SExpr::List(sig));
294 if !provides.is_empty() {
295 parts.push(SExpr::tagged("provide", &self.provides));
296 }
297 if !requires.is_empty() {
298 parts.push(SExpr::tagged("require", &self.requires));
299 }
300 SExpr::List(parts)
301 }
302}
303
304impl ToSExpr for Model {
305 fn to_sexpr(&self) -> SExpr {
306 let Model { name, val } = self;
307 SExpr::List(vec![SExpr::atom("model"), name.to_sexpr(), val.to_sexpr()])
308 }
309}
310
311impl ToSExpr for Form {
312 fn to_sexpr(&self) -> SExpr {
313 let Form {
314 name,
315 signatures,
316 pos: _,
317 } = self;
318 let mut parts = vec![SExpr::atom("form"), name.to_sexpr()];
319 parts.extend(signatures.iter().map(ToSExpr::to_sexpr));
320 SExpr::List(parts)
321 }
322}
323
324impl ToSExpr for Instantiation {
325 fn to_sexpr(&self) -> SExpr {
326 let Instantiation {
327 term,
328 form,
329 signatures,
330 pos: _,
331 } = self;
332 let mut parts = vec![SExpr::atom("instantiate"), term.to_sexpr()];
333 if let Some(form) = form {
334 parts.push(form.to_sexpr());
335 } else {
336 parts.extend(signatures.iter().map(ToSExpr::to_sexpr));
337 }
338 SExpr::List(parts)
339 }
340}
341
342impl ToSExpr for Extern {
343 fn to_sexpr(&self) -> SExpr {
344 match self {
345 Extern::Extractor {
346 term,
347 func,
348 infallible,
349 pos: _,
350 } => {
351 let mut parts = vec![SExpr::atom("extern"), SExpr::atom("extractor")];
352 if *infallible {
353 parts.push(SExpr::atom("infallible"));
354 }
355 parts.push(term.to_sexpr());
356 parts.push(func.to_sexpr());
357 SExpr::List(parts)
358 }
359 Extern::Constructor { term, func, pos: _ } => SExpr::List(vec![
360 SExpr::atom("extern"),
361 SExpr::atom("constructor"),
362 term.to_sexpr(),
363 func.to_sexpr(),
364 ]),
365 Extern::Const { name, ty, pos: _ } => SExpr::List(vec![
366 SExpr::atom("extern"),
367 SExpr::atom("const"),
368 SExpr::atom(format!("${}", name.0)),
369 ty.to_sexpr(),
370 ]),
371 }
372 }
373}
374
375impl ToSExpr for Converter {
376 fn to_sexpr(&self) -> SExpr {
377 let Converter {
378 inner_ty,
379 outer_ty,
380 term,
381 pos: _,
382 } = self;
383 SExpr::List(vec![
384 SExpr::atom("convert"),
385 inner_ty.to_sexpr(),
386 outer_ty.to_sexpr(),
387 term.to_sexpr(),
388 ])
389 }
390}
391
392impl ToSExpr for TypeValue {
393 fn to_sexpr(&self) -> SExpr {
394 match self {
395 TypeValue::Primitive(name, _) => {
396 SExpr::List(vec![SExpr::atom("primitive"), name.to_sexpr()])
397 }
398 TypeValue::Enum(variants, _) => {
399 let mut parts = vec![SExpr::atom("enum")];
400 parts.extend(variants.iter().map(ToSExpr::to_sexpr));
401 SExpr::List(parts)
402 }
403 }
404 }
405}
406
407impl ToSExpr for Variant {
408 fn to_sexpr(&self) -> SExpr {
409 let Variant {
410 name,
411 fields,
412 pos: _,
413 } = self;
414 let mut parts = vec![name.to_sexpr()];
415 parts.extend(fields.iter().map(ToSExpr::to_sexpr));
416 SExpr::List(parts)
417 }
418}
419
420impl ToSExpr for Field {
421 fn to_sexpr(&self) -> SExpr {
422 let Field { name, ty, pos: _ } = self;
423 SExpr::List(vec![name.to_sexpr(), ty.to_sexpr()])
424 }
425}
426
427impl ToSExpr for ModelValue {
428 fn to_sexpr(&self) -> SExpr {
429 match self {
430 ModelValue::TypeValue(mt) => SExpr::List(vec![SExpr::atom("type"), mt.to_sexpr()]),
431 ModelValue::EnumValues(enumerators) => {
432 let mut parts = vec![SExpr::atom("enum")];
433 for (variant, value) in enumerators {
434 parts.push(SExpr::List(vec![variant.to_sexpr(), value.to_sexpr()]));
435 }
436 SExpr::List(parts)
437 }
438 }
439 }
440}
441
442impl ToSExpr for ModelType {
443 fn to_sexpr(&self) -> SExpr {
444 match self {
445 ModelType::Unit => SExpr::atom("Unit"),
446 ModelType::Int => SExpr::atom("Int"),
447 ModelType::Bool => SExpr::atom("Bool"),
448 ModelType::BitVec(Some(size)) => {
449 SExpr::List(vec![SExpr::atom("bv"), SExpr::atom(size)])
450 }
451 ModelType::BitVec(None) => SExpr::List(vec![SExpr::atom("bv")]),
452 }
453 }
454}
455
456impl ToSExpr for Signature {
457 fn to_sexpr(&self) -> SExpr {
458 let Signature {
459 args,
460 ret,
461 canonical,
462 pos: _,
463 } = self;
464 SExpr::List(vec![
465 SExpr::tagged("args", args),
466 SExpr::tagged("ret", std::slice::from_ref(ret)),
467 SExpr::tagged("canon", std::slice::from_ref(canonical)),
468 ])
469 }
470}
471
472impl ToSExpr for SpecExpr {
473 fn to_sexpr(&self) -> SExpr {
474 match self {
475 SpecExpr::ConstInt { val, pos: _ } => SExpr::atom(val),
476 SpecExpr::ConstBitVec { val, width, pos: _ } => SExpr::atom(if *width % 4 == 0 {
477 format!("#x{val:0width$x}", width = *width as usize / 4)
478 } else {
479 format!("#b{val:0width$b}", width = *width as usize)
480 }),
481 SpecExpr::ConstBool { val, pos: _ } => SExpr::atom(if *val { "true" } else { "false" }),
482 SpecExpr::ConstUnit { pos: _ } => SExpr::List(Vec::new()),
483 SpecExpr::Var { var, pos: _ } => var.to_sexpr(),
484 SpecExpr::Op { op, args, pos: _ } => {
485 let mut parts = vec![op.to_sexpr()];
486 parts.extend(args.iter().map(ToSExpr::to_sexpr));
487 SExpr::List(parts)
488 }
489 SpecExpr::Pair { l, r } => SExpr::List(vec![l.to_sexpr(), r.to_sexpr()]),
490 SpecExpr::Enum { name } => SExpr::List(vec![name.to_sexpr()]),
491 }
492 }
493}
494
495impl ToSExpr for SpecOp {
496 fn to_sexpr(&self) -> SExpr {
497 SExpr::atom(match self {
498 SpecOp::Eq => "=",
499 SpecOp::And => "and",
500 SpecOp::Not => "not",
501 SpecOp::Imp => "=>",
502 SpecOp::Or => "or",
503 SpecOp::Lte => "<=",
504 SpecOp::Lt => "<",
505 SpecOp::Gte => ">=",
506 SpecOp::Gt => ">",
507 SpecOp::BVNot => "bvnot",
508 SpecOp::BVAnd => "bvand",
509 SpecOp::BVOr => "bvor",
510 SpecOp::BVXor => "bvxor",
511 SpecOp::BVNeg => "bvneg",
512 SpecOp::BVAdd => "bvadd",
513 SpecOp::BVSub => "bvsub",
514 SpecOp::BVMul => "bvmul",
515 SpecOp::BVUdiv => "bvudiv",
516 SpecOp::BVUrem => "bvurem",
517 SpecOp::BVSdiv => "bvsdiv",
518 SpecOp::BVSrem => "bvsrem",
519 SpecOp::BVShl => "bvshl",
520 SpecOp::BVLshr => "bvlshr",
521 SpecOp::BVAshr => "bvashr",
522 SpecOp::BVSaddo => "bvsaddo",
523 SpecOp::BVUle => "bvule",
524 SpecOp::BVUlt => "bvult",
525 SpecOp::BVUgt => "bvugt",
526 SpecOp::BVUge => "bvuge",
527 SpecOp::BVSlt => "bvslt",
528 SpecOp::BVSle => "bvsle",
529 SpecOp::BVSgt => "bvsgt",
530 SpecOp::BVSge => "bvsge",
531 SpecOp::Rotr => "rotr",
532 SpecOp::Rotl => "rotl",
533 SpecOp::Extract => "extract",
534 SpecOp::ZeroExt => "zero_ext",
535 SpecOp::SignExt => "sign_ext",
536 SpecOp::Concat => "concat",
537 SpecOp::ConvTo => "conv_to",
538 SpecOp::Int2BV => "int2bv",
539 SpecOp::WidthOf => "widthof",
540 SpecOp::If => "if",
541 SpecOp::Switch => "switch",
542 SpecOp::Popcnt => "popcnt",
543 SpecOp::Rev => "rev",
544 SpecOp::Cls => "cls",
545 SpecOp::Clz => "clz",
546 SpecOp::Subs => "subs",
547 SpecOp::BV2Int => "bv2int",
548 SpecOp::LoadEffect => "load_effect",
549 SpecOp::StoreEffect => "store_effect",
550 })
551 }
552}
553
554impl ToSExpr for Pattern {
555 fn to_sexpr(&self) -> SExpr {
556 match self {
557 Pattern::Var {
558 var: Ident(var, _),
559 pos: _,
560 } => SExpr::atom(var.clone()),
561 Pattern::BindPattern {
562 var: Ident(var, _),
563 subpat,
564 pos: _,
565 } => SExpr::Binding(var.clone(), Box::new(subpat.to_sexpr())),
566 Pattern::ConstInt { val, pos: _ } => SExpr::atom(val),
567 Pattern::ConstBool { val, pos: _ } => SExpr::atom(if *val { "true" } else { "false" }),
568 Pattern::ConstPrim { val, pos: _ } => SExpr::atom(format!("${}", val.0)),
569 Pattern::Wildcard { pos: _ } => SExpr::atom("_"),
570 Pattern::Term { sym, args, pos: _ } => {
571 let mut parts = vec![sym.to_sexpr()];
572 parts.extend(args.iter().map(ToSExpr::to_sexpr));
573 SExpr::List(parts)
574 }
575 Pattern::And { subpats, pos: _ } => {
576 let mut parts = vec![SExpr::atom("and")];
577 parts.extend(subpats.iter().map(ToSExpr::to_sexpr));
578 SExpr::List(parts)
579 }
580 Pattern::MacroArg { .. } => unimplemented!("macro arguments are for internal use only"),
581 }
582 }
583}
584
585impl ToSExpr for IfLet {
586 fn to_sexpr(&self) -> SExpr {
587 let IfLet {
588 pattern,
589 expr,
590 pos: _,
591 } = self;
592 SExpr::List(vec![
593 SExpr::atom("if-let"),
594 pattern.to_sexpr(),
595 expr.to_sexpr(),
596 ])
597 }
598}
599
600impl ToSExpr for Expr {
601 fn to_sexpr(&self) -> SExpr {
602 match self {
603 Expr::Term { sym, args, pos: _ } => {
604 let mut parts = vec![sym.to_sexpr()];
605 parts.extend(args.iter().map(ToSExpr::to_sexpr));
606 SExpr::List(parts)
607 }
608 Expr::Var { name, pos: _ } => name.to_sexpr(),
609 Expr::ConstInt { val, pos: _ } => SExpr::atom(val),
610 Expr::ConstBool { val, pos: _ } => SExpr::atom(if *val { "true" } else { "false" }),
611 Expr::ConstPrim { val, pos: _ } => SExpr::atom(format!("${}", val.0)),
612 Expr::Let { defs, body, pos: _ } => {
613 let mut parts = vec![SExpr::atom("let")];
614 parts.push(SExpr::list(&defs));
615 parts.push(body.to_sexpr());
616 SExpr::List(parts)
617 }
618 }
619 }
620}
621
622impl ToSExpr for LetDef {
623 fn to_sexpr(&self) -> SExpr {
624 let LetDef {
625 var,
626 ty,
627 val,
628 pos: _,
629 } = self;
630 SExpr::List(vec![var.to_sexpr(), ty.to_sexpr(), val.to_sexpr()])
631 }
632}
633
634impl ToSExpr for Ident {
635 fn to_sexpr(&self) -> SExpr {
636 let Ident(name, _) = self;
637 SExpr::atom(name.clone())
638 }
639}