1use crate::syntax::*;
5use std::fmt::Write;
6
7pub fn print_program(program: &Program) -> String {
8 let mut p = Printer::new();
9 p.program(program);
10 p.out
11}
12
13struct Printer {
14 out: String,
15 indent: usize,
16}
17
18impl Printer {
19 fn new() -> Self { Self { out: String::new(), indent: 0 } }
20
21 fn write_indent(&mut self) {
22 for _ in 0..self.indent {
23 self.out.push_str(" ");
24 }
25 }
26
27 fn nl(&mut self) {
28 self.out.push('\n');
29 }
30
31 fn program(&mut self, p: &Program) {
32 for c in &p.leading_comments {
37 writeln!(self.out, "{c}").unwrap();
38 }
39 if !p.leading_comments.is_empty() && !p.items.is_empty() {
40 self.nl();
41 }
42 for (i, item) in p.items.iter().enumerate() {
43 if i > 0 { self.nl(); }
44 self.item(item);
45 }
46 if !p.items.is_empty() {
47 self.nl();
48 }
49 if !p.trailing_comments.is_empty() {
53 if !p.items.is_empty() { self.nl(); }
54 for c in &p.trailing_comments {
55 writeln!(self.out, "{c}").unwrap();
56 }
57 }
58 }
59
60 fn item(&mut self, item: &Item) {
61 let leading: &[String] = match item {
65 Item::Import(i) => &i.leading_comments,
66 Item::TypeDecl(td) => &td.leading_comments,
67 Item::FnDecl(fd) => &fd.leading_comments,
68 };
69 for c in leading {
70 writeln!(self.out, "{c}").unwrap();
71 }
72 match item {
73 Item::Import(i) => {
74 writeln!(self.out, "import \"{}\" as {}", i.reference, i.alias).unwrap();
75 }
76 Item::TypeDecl(td) => self.type_decl(td),
77 Item::FnDecl(fd) => self.fn_decl(fd),
78 }
79 }
80
81 fn type_decl(&mut self, td: &TypeDecl) {
82 write!(self.out, "type {}", td.name).unwrap();
83 if !td.params.is_empty() {
84 write!(self.out, "[{}]", td.params.join(", ")).unwrap();
85 }
86 write!(self.out, " = ").unwrap();
87 self.type_expr(&td.definition);
88 self.nl();
89 }
90
91 fn fn_decl(&mut self, fd: &FnDecl) {
92 write!(self.out, "fn {}", fd.name).unwrap();
93 if !fd.type_params.is_empty() {
94 write!(self.out, "[{}]", fd.type_params.join(", ")).unwrap();
95 }
96 write!(self.out, "(").unwrap();
97 for (i, p) in fd.params.iter().enumerate() {
98 if i > 0 { write!(self.out, ", ").unwrap(); }
99 write!(self.out, "{} :: ", p.name).unwrap();
100 self.type_expr(&p.ty);
101 }
102 write!(self.out, ") -> ").unwrap();
103 self.effects(&fd.effects, fd.effect_row_var.as_ref());
104 self.type_expr(&fd.return_type);
105 if fd.examples.is_empty() {
106 write!(self.out, " ").unwrap();
107 } else {
108 self.examples(&fd.name, &fd.examples);
109 self.nl();
110 }
111 self.block(&fd.body);
112 self.nl();
113 }
114
115 fn examples(&mut self, fn_name: &str, examples: &[Example]) {
116 if examples.is_empty() { return; }
117 self.nl();
118 write!(self.out, " examples {{").unwrap();
119 self.indent += 2;
120 for (i, ex) in examples.iter().enumerate() {
121 self.nl();
122 self.write_indent();
123 write!(self.out, "{}(", fn_name).unwrap();
124 for (j, a) in ex.args.iter().enumerate() {
125 if j > 0 { write!(self.out, ", ").unwrap(); }
126 self.expr(a);
127 }
128 write!(self.out, ") => ").unwrap();
129 self.expr(&ex.expected);
130 if i + 1 < examples.len() {
131 write!(self.out, ",").unwrap();
132 }
133 }
134 self.indent -= 2;
135 self.nl();
136 write!(self.out, " }}").unwrap();
137 }
138
139 fn effects(&mut self, effects: &[Effect], tail: Option<&String>) {
140 if effects.is_empty() && tail.is_none() { return; }
141 write!(self.out, "[").unwrap();
142 for (i, e) in effects.iter().enumerate() {
143 if i > 0 { write!(self.out, ", ").unwrap(); }
144 write!(self.out, "{}", e.name).unwrap();
145 if let Some(arg) = &e.arg {
146 match arg {
147 EffectArg::Str(s) => write!(self.out, "(\"{}\")", s).unwrap(),
148 EffectArg::Int(n) => write!(self.out, "({})", n).unwrap(),
149 EffectArg::Ident(s) => write!(self.out, "({})", s).unwrap(),
150 }
151 }
152 }
153 if let Some(v) = tail {
154 if effects.is_empty() {
155 write!(self.out, "| {}", v).unwrap();
156 } else {
157 write!(self.out, " | {}", v).unwrap();
158 }
159 }
160 write!(self.out, "] ").unwrap();
161 }
162
163 fn type_expr(&mut self, t: &TypeExpr) {
164 match t {
165 TypeExpr::Named { name, args } => {
166 write!(self.out, "{}", name).unwrap();
167 if !args.is_empty() {
168 write!(self.out, "[").unwrap();
169 for (i, a) in args.iter().enumerate() {
170 if i > 0 { write!(self.out, ", ").unwrap(); }
171 self.type_expr(a);
172 }
173 write!(self.out, "]").unwrap();
174 }
175 }
176 TypeExpr::Record(fs) => {
177 write!(self.out, "{{ ").unwrap();
178 for (i, f) in fs.iter().enumerate() {
179 if i > 0 { write!(self.out, ", ").unwrap(); }
180 write!(self.out, "{} :: ", f.name).unwrap();
181 self.type_expr(&f.ty);
182 }
183 write!(self.out, " }}").unwrap();
184 }
185 TypeExpr::RecordWithSpreads { spreads, fields } => {
186 write!(self.out, "{{ ").unwrap();
187 for (i, s) in spreads.iter().enumerate() {
188 if i > 0 { write!(self.out, ", ").unwrap(); }
189 write!(self.out, "...{}", s).unwrap();
190 }
191 for f in fields {
192 write!(self.out, ", {} :: ", f.name).unwrap();
193 self.type_expr(&f.ty);
194 }
195 write!(self.out, " }}").unwrap();
196 }
197 TypeExpr::Tuple(items) => {
198 write!(self.out, "(").unwrap();
199 for (i, it) in items.iter().enumerate() {
200 if i > 0 { write!(self.out, ", ").unwrap(); }
201 self.type_expr(it);
202 }
203 write!(self.out, ")").unwrap();
204 }
205 TypeExpr::Function { params, effects, effect_row_var, ret } => {
206 write!(self.out, "(").unwrap();
207 for (i, p) in params.iter().enumerate() {
208 if i > 0 { write!(self.out, ", ").unwrap(); }
209 self.type_expr(p);
210 }
211 write!(self.out, ") -> ").unwrap();
212 self.effects(effects, effect_row_var.as_ref());
213 self.type_expr(ret);
214 }
215 TypeExpr::Union(variants) => {
216 for (i, v) in variants.iter().enumerate() {
217 if i > 0 { write!(self.out, " | ").unwrap(); }
218 write!(self.out, "{}", v.name).unwrap();
219 if let Some(payload) = &v.payload {
220 write!(self.out, "(").unwrap();
221 self.type_expr(payload);
222 write!(self.out, ")").unwrap();
223 }
224 }
225 }
226 TypeExpr::Refined { base, binding, predicate } => {
227 self.type_expr(base);
228 write!(self.out, "{{{} | ", binding).unwrap();
229 self.expr(predicate);
230 write!(self.out, "}}").unwrap();
231 }
232 }
233 }
234
235 fn block(&mut self, b: &Block) {
236 write!(self.out, "{{").unwrap();
237 self.indent += 1;
238 for stmt in &b.statements {
239 self.nl();
240 self.write_indent();
241 self.statement(stmt);
242 }
243 self.nl();
244 self.write_indent();
245 self.expr(&b.result);
246 self.indent -= 1;
247 self.nl();
248 self.write_indent();
249 write!(self.out, "}}").unwrap();
250 }
251
252 fn statement(&mut self, s: &Statement) {
253 match s {
254 Statement::Let { name, ty, value } => {
255 write!(self.out, "let {}", name).unwrap();
256 if let Some(ty) = ty {
257 write!(self.out, " :: ").unwrap();
258 self.type_expr(ty);
259 }
260 write!(self.out, " := ").unwrap();
261 self.expr(value);
262 }
263 Statement::Expr(e) => self.expr(e),
264 }
265 }
266
267 fn expr(&mut self, e: &Expr) {
268 self.expr_prec(e, 0);
269 }
270
271 fn expr_prec(&mut self, e: &Expr, parent_prec: u8) {
272 match e {
273 Expr::Lit(l) => self.literal(l),
274 Expr::Var(n) => { write!(self.out, "{}", n).unwrap(); }
275 Expr::Block(b) => self.block(b),
276 Expr::Call { callee, args } => {
277 self.expr_prec(callee, 100);
278 write!(self.out, "(").unwrap();
279 for (i, a) in args.iter().enumerate() {
280 if i > 0 { write!(self.out, ", ").unwrap(); }
281 self.expr(a);
282 }
283 write!(self.out, ")").unwrap();
284 }
285 Expr::Pipe { left, right } => {
286 if parent_prec > 0 { write!(self.out, "(").unwrap(); }
287 self.expr_prec(left, 1);
288 write!(self.out, " |> ").unwrap();
289 self.expr_prec(right, 1);
290 if parent_prec > 0 { write!(self.out, ")").unwrap(); }
291 }
292 Expr::Try(inner) => {
293 self.expr_prec(inner, 100);
294 write!(self.out, "?").unwrap();
295 }
296 Expr::Field { value, field } => {
297 self.expr_prec(value, 100);
298 write!(self.out, ".{}", field).unwrap();
299 }
300 Expr::BinOp { op, lhs, rhs } => {
301 let prec = op.precedence() + 10;
302 if parent_prec > prec { write!(self.out, "(").unwrap(); }
303 self.expr_prec(lhs, prec);
304 write!(self.out, " {} ", op.as_str()).unwrap();
305 self.expr_prec(rhs, prec + 1);
306 if parent_prec > prec { write!(self.out, ")").unwrap(); }
307 }
308 Expr::UnaryOp { op, expr } => {
309 let s = match op { UnaryOp::Neg => "-", UnaryOp::Not => "not " };
310 write!(self.out, "{}", s).unwrap();
311 self.expr_prec(expr, 100);
312 }
313 Expr::If { cond, then_block, else_block } => {
314 write!(self.out, "if ").unwrap();
315 self.expr(cond);
316 write!(self.out, " ").unwrap();
317 self.block(then_block);
318 write!(self.out, " else ").unwrap();
319 self.block(else_block);
320 }
321 Expr::Match { scrutinee, arms } => {
322 write!(self.out, "match ").unwrap();
323 self.expr(scrutinee);
324 write!(self.out, " {{").unwrap();
325 self.indent += 1;
326 for arm in arms {
327 self.nl();
328 self.write_indent();
329 self.pattern(&arm.pattern);
330 write!(self.out, " => ").unwrap();
331 self.expr(&arm.body);
332 write!(self.out, ",").unwrap();
333 }
334 self.indent -= 1;
335 self.nl();
336 self.write_indent();
337 write!(self.out, "}}").unwrap();
338 }
339 Expr::RecordLit(fields) => {
340 write!(self.out, "{{ ").unwrap();
341 for (i, f) in fields.iter().enumerate() {
342 if i > 0 { write!(self.out, ", ").unwrap(); }
343 write!(self.out, "{}: ", f.name).unwrap();
344 self.expr(&f.value);
345 }
346 write!(self.out, " }}").unwrap();
347 }
348 Expr::TupleLit(items) => {
349 write!(self.out, "(").unwrap();
350 for (i, it) in items.iter().enumerate() {
351 if i > 0 { write!(self.out, ", ").unwrap(); }
352 self.expr(it);
353 }
354 write!(self.out, ")").unwrap();
355 }
356 Expr::ListLit(items) => {
357 write!(self.out, "[").unwrap();
358 for (i, it) in items.iter().enumerate() {
359 if i > 0 { write!(self.out, ", ").unwrap(); }
360 self.expr(it);
361 }
362 write!(self.out, "]").unwrap();
363 }
364 Expr::Constructor { name, args } => {
365 write!(self.out, "{}", name).unwrap();
366 if !args.is_empty() {
367 write!(self.out, "(").unwrap();
368 for (i, a) in args.iter().enumerate() {
369 if i > 0 { write!(self.out, ", ").unwrap(); }
370 self.expr(a);
371 }
372 write!(self.out, ")").unwrap();
373 }
374 }
375 Expr::Ascription { value, ty } => {
376 write!(self.out, "(").unwrap();
377 self.expr(value);
378 write!(self.out, " :: ").unwrap();
379 self.type_expr(ty);
380 write!(self.out, ")").unwrap();
381 }
382 Expr::Lambda(l) => {
383 write!(self.out, "fn (").unwrap();
384 for (i, p) in l.params.iter().enumerate() {
385 if i > 0 { write!(self.out, ", ").unwrap(); }
386 write!(self.out, "{} :: ", p.name).unwrap();
387 self.type_expr(&p.ty);
388 }
389 write!(self.out, ") -> ").unwrap();
390 self.effects(&l.effects, l.effect_row_var.as_ref());
391 self.type_expr(&l.return_type);
392 write!(self.out, " ").unwrap();
393 self.block(&l.body);
394 }
395 }
396 }
397
398 fn literal(&mut self, l: &Literal) {
399 match l {
400 Literal::Int(n) => write!(self.out, "{}", n).unwrap(),
401 Literal::Float(n) => write!(self.out, "{}", format_float(*n)).unwrap(),
402 Literal::Str(s) => write!(self.out, "\"{}\"", escape(s)).unwrap(),
403 Literal::Bytes(b) => {
404 write!(self.out, "b\"").unwrap();
405 for &c in b {
406 if c.is_ascii() && (c as char).is_ascii_graphic() && c != b'"' && c != b'\\' {
407 self.out.push(c as char);
408 } else {
409 write!(self.out, "\\x{:02x}", c).unwrap();
410 }
411 }
412 write!(self.out, "\"").unwrap();
413 }
414 Literal::Bool(b) => write!(self.out, "{}", b).unwrap(),
415 Literal::Unit => write!(self.out, "()").unwrap(),
416 }
417 }
418
419 fn pattern(&mut self, p: &Pattern) {
420 match p {
421 Pattern::Lit(l) => self.literal(l),
422 Pattern::Var(n) => { write!(self.out, "{}", n).unwrap(); }
423 Pattern::Wild => { write!(self.out, "_").unwrap(); }
424 Pattern::Constructor { name, args } => {
425 write!(self.out, "{}", name).unwrap();
426 if !args.is_empty() {
427 write!(self.out, "(").unwrap();
428 for (i, a) in args.iter().enumerate() {
429 if i > 0 { write!(self.out, ", ").unwrap(); }
430 self.pattern(a);
431 }
432 write!(self.out, ")").unwrap();
433 }
434 }
435 Pattern::Record { fields, rest: _ } => {
436 write!(self.out, "{{ ").unwrap();
437 for (i, f) in fields.iter().enumerate() {
438 if i > 0 { write!(self.out, ", ").unwrap(); }
439 write!(self.out, "{}", f.name).unwrap();
440 if let Some(p) = &f.pattern {
441 write!(self.out, ": ").unwrap();
442 self.pattern(p);
443 }
444 }
445 write!(self.out, " }}").unwrap();
446 }
447 Pattern::Tuple(items) => {
448 write!(self.out, "(").unwrap();
449 for (i, it) in items.iter().enumerate() {
450 if i > 0 { write!(self.out, ", ").unwrap(); }
451 self.pattern(it);
452 }
453 write!(self.out, ")").unwrap();
454 }
455 }
456 }
457}
458
459fn escape(s: &str) -> String {
460 let mut out = String::with_capacity(s.len());
461 for c in s.chars() {
462 match c {
463 '\\' => out.push_str("\\\\"),
464 '"' => out.push_str("\\\""),
465 '\n' => out.push_str("\\n"),
466 '\t' => out.push_str("\\t"),
467 '\r' => out.push_str("\\r"),
468 c => out.push(c),
469 }
470 }
471 out
472}
473
474fn format_float(n: f64) -> String {
475 if n.is_finite() && n == n.trunc() {
476 format!("{:.1}", n)
477 } else {
478 format!("{}", n)
479 }
480}