]> git.lizzy.rs Git - rust.git/blob - src/tools/rust-analyzer/crates/hir-def/src/body/pretty.rs
:arrow_up: rust-analyzer
[rust.git] / src / tools / rust-analyzer / crates / hir-def / src / body / pretty.rs
1 //! A pretty-printer for HIR.
2
3 use std::fmt::{self, Write};
4
5 use crate::{
6     expr::{Array, BindingAnnotation, Literal, Statement},
7     pretty::{print_generic_args, print_path, print_type_ref},
8     type_ref::TypeRef,
9 };
10
11 use super::*;
12
13 pub(super) fn print_body_hir(db: &dyn DefDatabase, body: &Body, owner: DefWithBodyId) -> String {
14     let needs_semi;
15     let header = match owner {
16         DefWithBodyId::FunctionId(it) => {
17             needs_semi = false;
18             let item_tree_id = it.lookup(db).id;
19             format!("fn {}(…) ", item_tree_id.item_tree(db)[item_tree_id.value].name)
20         }
21         DefWithBodyId::StaticId(it) => {
22             needs_semi = true;
23             let item_tree_id = it.lookup(db).id;
24             format!("static {} = ", item_tree_id.item_tree(db)[item_tree_id.value].name)
25         }
26         DefWithBodyId::ConstId(it) => {
27             needs_semi = true;
28             let item_tree_id = it.lookup(db).id;
29             let name = match &item_tree_id.item_tree(db)[item_tree_id.value].name {
30                 Some(name) => name.to_string(),
31                 None => "_".to_string(),
32             };
33             format!("const {} = ", name)
34         }
35     };
36
37     let mut p = Printer { body, buf: header, indent_level: 0, needs_indent: false };
38     p.print_expr(body.body_expr);
39     if needs_semi {
40         p.buf.push(';');
41     }
42     p.buf
43 }
44
45 macro_rules! w {
46     ($dst:expr, $($arg:tt)*) => {
47         { let _ = write!($dst, $($arg)*); }
48     };
49 }
50
51 macro_rules! wln {
52     ($dst:expr) => {
53         { let _ = writeln!($dst); }
54     };
55     ($dst:expr, $($arg:tt)*) => {
56         { let _ = writeln!($dst, $($arg)*); }
57     };
58 }
59
60 struct Printer<'a> {
61     body: &'a Body,
62     buf: String,
63     indent_level: usize,
64     needs_indent: bool,
65 }
66
67 impl<'a> Write for Printer<'a> {
68     fn write_str(&mut self, s: &str) -> fmt::Result {
69         for line in s.split_inclusive('\n') {
70             if self.needs_indent {
71                 match self.buf.chars().rev().skip_while(|ch| *ch == ' ').next() {
72                     Some('\n') | None => {}
73                     _ => self.buf.push('\n'),
74                 }
75                 self.buf.push_str(&"    ".repeat(self.indent_level));
76                 self.needs_indent = false;
77             }
78
79             self.buf.push_str(line);
80             self.needs_indent = line.ends_with('\n');
81         }
82
83         Ok(())
84     }
85 }
86
87 impl<'a> Printer<'a> {
88     fn indented(&mut self, f: impl FnOnce(&mut Self)) {
89         self.indent_level += 1;
90         wln!(self);
91         f(self);
92         self.indent_level -= 1;
93         self.buf = self.buf.trim_end_matches('\n').to_string();
94     }
95
96     fn whitespace(&mut self) {
97         match self.buf.chars().next_back() {
98             None | Some('\n' | ' ') => {}
99             _ => self.buf.push(' '),
100         }
101     }
102
103     fn newline(&mut self) {
104         match self.buf.chars().rev().skip_while(|ch| *ch == ' ').next() {
105             Some('\n') | None => {}
106             _ => writeln!(self).unwrap(),
107         }
108     }
109
110     fn print_expr(&mut self, expr: ExprId) {
111         let expr = &self.body[expr];
112
113         match expr {
114             Expr::Missing => w!(self, "�"),
115             Expr::Underscore => w!(self, "_"),
116             Expr::Path(path) => self.print_path(path),
117             Expr::If { condition, then_branch, else_branch } => {
118                 w!(self, "if ");
119                 self.print_expr(*condition);
120                 w!(self, " ");
121                 self.print_expr(*then_branch);
122                 if let Some(els) = *else_branch {
123                     w!(self, " else ");
124                     self.print_expr(els);
125                 }
126             }
127             Expr::Let { pat, expr } => {
128                 w!(self, "let ");
129                 self.print_pat(*pat);
130                 w!(self, " = ");
131                 self.print_expr(*expr);
132             }
133             Expr::Loop { body, label } => {
134                 if let Some(lbl) = label {
135                     w!(self, "{}: ", self.body[*lbl].name);
136                 }
137                 w!(self, "loop ");
138                 self.print_expr(*body);
139             }
140             Expr::While { condition, body, label } => {
141                 if let Some(lbl) = label {
142                     w!(self, "{}: ", self.body[*lbl].name);
143                 }
144                 w!(self, "while ");
145                 self.print_expr(*condition);
146                 self.print_expr(*body);
147             }
148             Expr::For { iterable, pat, body, label } => {
149                 if let Some(lbl) = label {
150                     w!(self, "{}: ", self.body[*lbl].name);
151                 }
152                 w!(self, "for ");
153                 self.print_pat(*pat);
154                 w!(self, " in ");
155                 self.print_expr(*iterable);
156                 self.print_expr(*body);
157             }
158             Expr::Call { callee, args, is_assignee_expr: _ } => {
159                 self.print_expr(*callee);
160                 w!(self, "(");
161                 if !args.is_empty() {
162                     self.indented(|p| {
163                         for arg in &**args {
164                             p.print_expr(*arg);
165                             wln!(p, ",");
166                         }
167                     });
168                 }
169                 w!(self, ")");
170             }
171             Expr::MethodCall { receiver, method_name, args, generic_args } => {
172                 self.print_expr(*receiver);
173                 w!(self, ".{}", method_name);
174                 if let Some(args) = generic_args {
175                     w!(self, "::<");
176                     print_generic_args(args, self).unwrap();
177                     w!(self, ">");
178                 }
179                 w!(self, "(");
180                 if !args.is_empty() {
181                     self.indented(|p| {
182                         for arg in &**args {
183                             p.print_expr(*arg);
184                             wln!(p, ",");
185                         }
186                     });
187                 }
188                 w!(self, ")");
189             }
190             Expr::Match { expr, arms } => {
191                 w!(self, "match ");
192                 self.print_expr(*expr);
193                 w!(self, " {{");
194                 self.indented(|p| {
195                     for arm in &**arms {
196                         p.print_pat(arm.pat);
197                         if let Some(guard) = arm.guard {
198                             w!(p, " if ");
199                             p.print_expr(guard);
200                         }
201                         w!(p, " => ");
202                         p.print_expr(arm.expr);
203                         wln!(p, ",");
204                     }
205                 });
206                 wln!(self, "}}");
207             }
208             Expr::Continue { label } => {
209                 w!(self, "continue");
210                 if let Some(label) = label {
211                     w!(self, " {}", label);
212                 }
213             }
214             Expr::Break { expr, label } => {
215                 w!(self, "break");
216                 if let Some(label) = label {
217                     w!(self, " {}", label);
218                 }
219                 if let Some(expr) = expr {
220                     self.whitespace();
221                     self.print_expr(*expr);
222                 }
223             }
224             Expr::Return { expr } => {
225                 w!(self, "return");
226                 if let Some(expr) = expr {
227                     self.whitespace();
228                     self.print_expr(*expr);
229                 }
230             }
231             Expr::Yield { expr } => {
232                 w!(self, "yield");
233                 if let Some(expr) = expr {
234                     self.whitespace();
235                     self.print_expr(*expr);
236                 }
237             }
238             Expr::RecordLit { path, fields, spread, ellipsis, is_assignee_expr: _ } => {
239                 match path {
240                     Some(path) => self.print_path(path),
241                     None => w!(self, "�"),
242                 }
243
244                 w!(self, "{{");
245                 self.indented(|p| {
246                     for field in &**fields {
247                         w!(p, "{}: ", field.name);
248                         p.print_expr(field.expr);
249                         wln!(p, ",");
250                     }
251                     if let Some(spread) = spread {
252                         w!(p, "..");
253                         p.print_expr(*spread);
254                         wln!(p);
255                     }
256                     if *ellipsis {
257                         wln!(p, "..");
258                     }
259                 });
260                 w!(self, "}}");
261             }
262             Expr::Field { expr, name } => {
263                 self.print_expr(*expr);
264                 w!(self, ".{}", name);
265             }
266             Expr::Await { expr } => {
267                 self.print_expr(*expr);
268                 w!(self, ".await");
269             }
270             Expr::Try { expr } => {
271                 self.print_expr(*expr);
272                 w!(self, "?");
273             }
274             Expr::TryBlock { body } => {
275                 w!(self, "try ");
276                 self.print_expr(*body);
277             }
278             Expr::Async { body } => {
279                 w!(self, "async ");
280                 self.print_expr(*body);
281             }
282             Expr::Const { body } => {
283                 w!(self, "const ");
284                 self.print_expr(*body);
285             }
286             Expr::Cast { expr, type_ref } => {
287                 self.print_expr(*expr);
288                 w!(self, " as ");
289                 self.print_type_ref(type_ref);
290             }
291             Expr::Ref { expr, rawness, mutability } => {
292                 w!(self, "&");
293                 if rawness.is_raw() {
294                     w!(self, "raw ");
295                 }
296                 if mutability.is_mut() {
297                     w!(self, "mut ");
298                 }
299                 self.print_expr(*expr);
300             }
301             Expr::Box { expr } => {
302                 w!(self, "box ");
303                 self.print_expr(*expr);
304             }
305             Expr::UnaryOp { expr, op } => {
306                 let op = match op {
307                     ast::UnaryOp::Deref => "*",
308                     ast::UnaryOp::Not => "!",
309                     ast::UnaryOp::Neg => "-",
310                 };
311                 w!(self, "{}", op);
312                 self.print_expr(*expr);
313             }
314             Expr::BinaryOp { lhs, rhs, op } => {
315                 let (bra, ket) = match op {
316                     None | Some(ast::BinaryOp::Assignment { .. }) => ("", ""),
317                     _ => ("(", ")"),
318                 };
319                 w!(self, "{}", bra);
320                 self.print_expr(*lhs);
321                 w!(self, "{} ", ket);
322                 match op {
323                     Some(op) => w!(self, "{}", op),
324                     None => w!(self, "�"), // :)
325                 }
326                 w!(self, " {}", bra);
327                 self.print_expr(*rhs);
328                 w!(self, "{}", ket);
329             }
330             Expr::Range { lhs, rhs, range_type } => {
331                 if let Some(lhs) = lhs {
332                     w!(self, "(");
333                     self.print_expr(*lhs);
334                     w!(self, ") ");
335                 }
336                 let range = match range_type {
337                     ast::RangeOp::Exclusive => "..",
338                     ast::RangeOp::Inclusive => "..=",
339                 };
340                 w!(self, "{}", range);
341                 if let Some(rhs) = rhs {
342                     w!(self, "(");
343                     self.print_expr(*rhs);
344                     w!(self, ") ");
345                 }
346             }
347             Expr::Index { base, index } => {
348                 self.print_expr(*base);
349                 w!(self, "[");
350                 self.print_expr(*index);
351                 w!(self, "]");
352             }
353             Expr::Closure { args, arg_types, ret_type, body } => {
354                 w!(self, "|");
355                 for (i, (pat, ty)) in args.iter().zip(arg_types.iter()).enumerate() {
356                     if i != 0 {
357                         w!(self, ", ");
358                     }
359                     self.print_pat(*pat);
360                     if let Some(ty) = ty {
361                         w!(self, ": ");
362                         self.print_type_ref(ty);
363                     }
364                 }
365                 w!(self, "|");
366                 if let Some(ret_ty) = ret_type {
367                     w!(self, " -> ");
368                     self.print_type_ref(ret_ty);
369                 }
370                 self.whitespace();
371                 self.print_expr(*body);
372             }
373             Expr::Tuple { exprs, is_assignee_expr: _ } => {
374                 w!(self, "(");
375                 for expr in exprs.iter() {
376                     self.print_expr(*expr);
377                     w!(self, ", ");
378                 }
379                 w!(self, ")");
380             }
381             Expr::Unsafe { body } => {
382                 w!(self, "unsafe ");
383                 self.print_expr(*body);
384             }
385             Expr::Array(arr) => {
386                 w!(self, "[");
387                 if !matches!(arr, Array::ElementList { elements, .. } if elements.is_empty()) {
388                     self.indented(|p| match arr {
389                         Array::ElementList { elements, is_assignee_expr: _ } => {
390                             for elem in elements.iter() {
391                                 p.print_expr(*elem);
392                                 w!(p, ", ");
393                             }
394                         }
395                         Array::Repeat { initializer, repeat } => {
396                             p.print_expr(*initializer);
397                             w!(p, "; ");
398                             p.print_expr(*repeat);
399                         }
400                     });
401                     self.newline();
402                 }
403                 w!(self, "]");
404             }
405             Expr::Literal(lit) => self.print_literal(lit),
406             Expr::Block { id: _, statements, tail, label } => {
407                 self.whitespace();
408                 if let Some(lbl) = label {
409                     w!(self, "{}: ", self.body[*lbl].name);
410                 }
411                 w!(self, "{{");
412                 if !statements.is_empty() || tail.is_some() {
413                     self.indented(|p| {
414                         for stmt in &**statements {
415                             p.print_stmt(stmt);
416                         }
417                         if let Some(tail) = tail {
418                             p.print_expr(*tail);
419                         }
420                         p.newline();
421                     });
422                 }
423                 w!(self, "}}");
424             }
425         }
426     }
427
428     fn print_pat(&mut self, pat: PatId) {
429         let pat = &self.body[pat];
430
431         match pat {
432             Pat::Missing => w!(self, "�"),
433             Pat::Wild => w!(self, "_"),
434             Pat::Tuple { args, ellipsis } => {
435                 w!(self, "(");
436                 for (i, pat) in args.iter().enumerate() {
437                     if i != 0 {
438                         w!(self, ", ");
439                     }
440                     if *ellipsis == Some(i) {
441                         w!(self, ".., ");
442                     }
443                     self.print_pat(*pat);
444                 }
445                 w!(self, ")");
446             }
447             Pat::Or(pats) => {
448                 for (i, pat) in pats.iter().enumerate() {
449                     if i != 0 {
450                         w!(self, " | ");
451                     }
452                     self.print_pat(*pat);
453                 }
454             }
455             Pat::Record { path, args, ellipsis } => {
456                 match path {
457                     Some(path) => self.print_path(path),
458                     None => w!(self, "�"),
459                 }
460
461                 w!(self, " {{");
462                 self.indented(|p| {
463                     for arg in args.iter() {
464                         w!(p, "{}: ", arg.name);
465                         p.print_pat(arg.pat);
466                         wln!(p, ",");
467                     }
468                     if *ellipsis {
469                         wln!(p, "..");
470                     }
471                 });
472                 w!(self, "}}");
473             }
474             Pat::Range { start, end } => {
475                 self.print_expr(*start);
476                 w!(self, "...");
477                 self.print_expr(*end);
478             }
479             Pat::Slice { prefix, slice, suffix } => {
480                 w!(self, "[");
481                 for pat in prefix.iter() {
482                     self.print_pat(*pat);
483                     w!(self, ", ");
484                 }
485                 if let Some(pat) = slice {
486                     self.print_pat(*pat);
487                     w!(self, ", ");
488                 }
489                 for pat in suffix.iter() {
490                     self.print_pat(*pat);
491                     w!(self, ", ");
492                 }
493                 w!(self, "]");
494             }
495             Pat::Path(path) => self.print_path(path),
496             Pat::Lit(expr) => self.print_expr(*expr),
497             Pat::Bind { mode, name, subpat } => {
498                 let mode = match mode {
499                     BindingAnnotation::Unannotated => "",
500                     BindingAnnotation::Mutable => "mut ",
501                     BindingAnnotation::Ref => "ref ",
502                     BindingAnnotation::RefMut => "ref mut ",
503                 };
504                 w!(self, "{}{}", mode, name);
505                 if let Some(pat) = subpat {
506                     self.whitespace();
507                     self.print_pat(*pat);
508                 }
509             }
510             Pat::TupleStruct { path, args, ellipsis } => {
511                 match path {
512                     Some(path) => self.print_path(path),
513                     None => w!(self, "�"),
514                 }
515                 w!(self, "(");
516                 for (i, arg) in args.iter().enumerate() {
517                     if i != 0 {
518                         w!(self, ", ");
519                     }
520                     if *ellipsis == Some(i) {
521                         w!(self, ", ..");
522                     }
523                     self.print_pat(*arg);
524                 }
525                 w!(self, ")");
526             }
527             Pat::Ref { pat, mutability } => {
528                 w!(self, "&");
529                 if mutability.is_mut() {
530                     w!(self, "mut ");
531                 }
532                 self.print_pat(*pat);
533             }
534             Pat::Box { inner } => {
535                 w!(self, "box ");
536                 self.print_pat(*inner);
537             }
538             Pat::ConstBlock(c) => {
539                 w!(self, "const ");
540                 self.print_expr(*c);
541             }
542         }
543     }
544
545     fn print_stmt(&mut self, stmt: &Statement) {
546         match stmt {
547             Statement::Let { pat, type_ref, initializer, else_branch } => {
548                 w!(self, "let ");
549                 self.print_pat(*pat);
550                 if let Some(ty) = type_ref {
551                     w!(self, ": ");
552                     self.print_type_ref(ty);
553                 }
554                 if let Some(init) = initializer {
555                     w!(self, " = ");
556                     self.print_expr(*init);
557                 }
558                 if let Some(els) = else_branch {
559                     w!(self, " else ");
560                     self.print_expr(*els);
561                 }
562                 wln!(self, ";");
563             }
564             Statement::Expr { expr, has_semi } => {
565                 self.print_expr(*expr);
566                 if *has_semi {
567                     w!(self, ";");
568                 }
569                 wln!(self);
570             }
571         }
572     }
573
574     fn print_literal(&mut self, literal: &Literal) {
575         match literal {
576             Literal::String(it) => w!(self, "{:?}", it),
577             Literal::ByteString(it) => w!(self, "\"{}\"", it.escape_ascii()),
578             Literal::Char(it) => w!(self, "'{}'", it.escape_debug()),
579             Literal::Bool(it) => w!(self, "{}", it),
580             Literal::Int(i, suffix) => {
581                 w!(self, "{}", i);
582                 if let Some(suffix) = suffix {
583                     w!(self, "{}", suffix);
584                 }
585             }
586             Literal::Uint(i, suffix) => {
587                 w!(self, "{}", i);
588                 if let Some(suffix) = suffix {
589                     w!(self, "{}", suffix);
590                 }
591             }
592             Literal::Float(f, suffix) => {
593                 w!(self, "{}", f);
594                 if let Some(suffix) = suffix {
595                     w!(self, "{}", suffix);
596                 }
597             }
598         }
599     }
600
601     fn print_type_ref(&mut self, ty: &TypeRef) {
602         print_type_ref(ty, self).unwrap();
603     }
604
605     fn print_path(&mut self, path: &Path) {
606         print_path(path, self).unwrap();
607     }
608 }