1 //! A pretty-printer for HIR.
3 use std::fmt::{self, Write};
6 expr::{Array, BindingAnnotation, Literal, Statement},
7 pretty::{print_generic_args, print_path, print_type_ref},
13 pub(super) fn print_body_hir(db: &dyn DefDatabase, body: &Body, owner: DefWithBodyId) -> String {
15 let header = match owner {
16 DefWithBodyId::FunctionId(it) => {
18 let item_tree_id = it.lookup(db).id;
19 format!("fn {}(…) ", item_tree_id.item_tree(db)[item_tree_id.value].name)
21 DefWithBodyId::StaticId(it) => {
23 let item_tree_id = it.lookup(db).id;
24 format!("static {} = ", item_tree_id.item_tree(db)[item_tree_id.value].name)
26 DefWithBodyId::ConstId(it) => {
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(),
33 format!("const {} = ", name)
37 let mut p = Printer { body, buf: header, indent_level: 0, needs_indent: false };
38 p.print_expr(body.body_expr);
46 ($dst:expr, $($arg:tt)*) => {
47 { let _ = write!($dst, $($arg)*); }
53 { let _ = writeln!($dst); }
55 ($dst:expr, $($arg:tt)*) => {
56 { let _ = writeln!($dst, $($arg)*); }
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'),
75 self.buf.push_str(&" ".repeat(self.indent_level));
76 self.needs_indent = false;
79 self.buf.push_str(line);
80 self.needs_indent = line.ends_with('\n');
87 impl<'a> Printer<'a> {
88 fn indented(&mut self, f: impl FnOnce(&mut Self)) {
89 self.indent_level += 1;
92 self.indent_level -= 1;
93 self.buf = self.buf.trim_end_matches('\n').to_string();
96 fn whitespace(&mut self) {
97 match self.buf.chars().next_back() {
98 None | Some('\n' | ' ') => {}
99 _ => self.buf.push(' '),
103 fn newline(&mut self) {
104 match self.buf.chars().rev().skip_while(|ch| *ch == ' ').next() {
105 Some('\n') | None => {}
106 _ => writeln!(self).unwrap(),
110 fn print_expr(&mut self, expr: ExprId) {
111 let expr = &self.body[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 } => {
119 self.print_expr(*condition);
121 self.print_expr(*then_branch);
122 if let Some(els) = *else_branch {
124 self.print_expr(els);
127 Expr::Let { pat, expr } => {
129 self.print_pat(*pat);
131 self.print_expr(*expr);
133 Expr::Loop { body, label } => {
134 if let Some(lbl) = label {
135 w!(self, "{}: ", self.body[*lbl].name);
138 self.print_expr(*body);
140 Expr::While { condition, body, label } => {
141 if let Some(lbl) = label {
142 w!(self, "{}: ", self.body[*lbl].name);
145 self.print_expr(*condition);
146 self.print_expr(*body);
148 Expr::For { iterable, pat, body, label } => {
149 if let Some(lbl) = label {
150 w!(self, "{}: ", self.body[*lbl].name);
153 self.print_pat(*pat);
155 self.print_expr(*iterable);
156 self.print_expr(*body);
158 Expr::Call { callee, args, is_assignee_expr: _ } => {
159 self.print_expr(*callee);
161 if !args.is_empty() {
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 {
176 print_generic_args(args, self).unwrap();
180 if !args.is_empty() {
190 Expr::Match { expr, arms } => {
192 self.print_expr(*expr);
196 p.print_pat(arm.pat);
197 if let Some(guard) = arm.guard {
202 p.print_expr(arm.expr);
208 Expr::Continue { label } => {
209 w!(self, "continue");
210 if let Some(label) = label {
211 w!(self, " {}", label);
214 Expr::Break { expr, label } => {
216 if let Some(label) = label {
217 w!(self, " {}", label);
219 if let Some(expr) = expr {
221 self.print_expr(*expr);
224 Expr::Return { expr } => {
226 if let Some(expr) = expr {
228 self.print_expr(*expr);
231 Expr::Yield { expr } => {
233 if let Some(expr) = expr {
235 self.print_expr(*expr);
238 Expr::RecordLit { path, fields, spread, ellipsis, is_assignee_expr: _ } => {
240 Some(path) => self.print_path(path),
241 None => w!(self, "�"),
246 for field in &**fields {
247 w!(p, "{}: ", field.name);
248 p.print_expr(field.expr);
251 if let Some(spread) = spread {
253 p.print_expr(*spread);
262 Expr::Field { expr, name } => {
263 self.print_expr(*expr);
264 w!(self, ".{}", name);
266 Expr::Await { expr } => {
267 self.print_expr(*expr);
270 Expr::Try { expr } => {
271 self.print_expr(*expr);
274 Expr::TryBlock { body } => {
276 self.print_expr(*body);
278 Expr::Async { body } => {
280 self.print_expr(*body);
282 Expr::Const { body } => {
284 self.print_expr(*body);
286 Expr::Cast { expr, type_ref } => {
287 self.print_expr(*expr);
289 self.print_type_ref(type_ref);
291 Expr::Ref { expr, rawness, mutability } => {
293 if rawness.is_raw() {
296 if mutability.is_mut() {
299 self.print_expr(*expr);
301 Expr::Box { expr } => {
303 self.print_expr(*expr);
305 Expr::UnaryOp { expr, op } => {
307 ast::UnaryOp::Deref => "*",
308 ast::UnaryOp::Not => "!",
309 ast::UnaryOp::Neg => "-",
312 self.print_expr(*expr);
314 Expr::BinaryOp { lhs, rhs, op } => {
315 let (bra, ket) = match op {
316 None | Some(ast::BinaryOp::Assignment { .. }) => ("", ""),
320 self.print_expr(*lhs);
321 w!(self, "{} ", ket);
323 Some(op) => w!(self, "{}", op),
324 None => w!(self, "�"), // :)
326 w!(self, " {}", bra);
327 self.print_expr(*rhs);
330 Expr::Range { lhs, rhs, range_type } => {
331 if let Some(lhs) = lhs {
333 self.print_expr(*lhs);
336 let range = match range_type {
337 ast::RangeOp::Exclusive => "..",
338 ast::RangeOp::Inclusive => "..=",
340 w!(self, "{}", range);
341 if let Some(rhs) = rhs {
343 self.print_expr(*rhs);
347 Expr::Index { base, index } => {
348 self.print_expr(*base);
350 self.print_expr(*index);
353 Expr::Closure { args, arg_types, ret_type, body } => {
355 for (i, (pat, ty)) in args.iter().zip(arg_types.iter()).enumerate() {
359 self.print_pat(*pat);
360 if let Some(ty) = ty {
362 self.print_type_ref(ty);
366 if let Some(ret_ty) = ret_type {
368 self.print_type_ref(ret_ty);
371 self.print_expr(*body);
373 Expr::Tuple { exprs, is_assignee_expr: _ } => {
375 for expr in exprs.iter() {
376 self.print_expr(*expr);
381 Expr::Unsafe { body } => {
383 self.print_expr(*body);
385 Expr::Array(arr) => {
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() {
395 Array::Repeat { initializer, repeat } => {
396 p.print_expr(*initializer);
398 p.print_expr(*repeat);
405 Expr::Literal(lit) => self.print_literal(lit),
406 Expr::Block { id: _, statements, tail, label } => {
408 if let Some(lbl) = label {
409 w!(self, "{}: ", self.body[*lbl].name);
412 if !statements.is_empty() || tail.is_some() {
414 for stmt in &**statements {
417 if let Some(tail) = tail {
428 fn print_pat(&mut self, pat: PatId) {
429 let pat = &self.body[pat];
432 Pat::Missing => w!(self, "�"),
433 Pat::Wild => w!(self, "_"),
434 Pat::Tuple { args, ellipsis } => {
436 for (i, pat) in args.iter().enumerate() {
440 if *ellipsis == Some(i) {
443 self.print_pat(*pat);
448 for (i, pat) in pats.iter().enumerate() {
452 self.print_pat(*pat);
455 Pat::Record { path, args, ellipsis } => {
457 Some(path) => self.print_path(path),
458 None => w!(self, "�"),
463 for arg in args.iter() {
464 w!(p, "{}: ", arg.name);
465 p.print_pat(arg.pat);
474 Pat::Range { start, end } => {
475 self.print_expr(*start);
477 self.print_expr(*end);
479 Pat::Slice { prefix, slice, suffix } => {
481 for pat in prefix.iter() {
482 self.print_pat(*pat);
485 if let Some(pat) = slice {
486 self.print_pat(*pat);
489 for pat in suffix.iter() {
490 self.print_pat(*pat);
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 ",
504 w!(self, "{}{}", mode, name);
505 if let Some(pat) = subpat {
507 self.print_pat(*pat);
510 Pat::TupleStruct { path, args, ellipsis } => {
512 Some(path) => self.print_path(path),
513 None => w!(self, "�"),
516 for (i, arg) in args.iter().enumerate() {
520 if *ellipsis == Some(i) {
523 self.print_pat(*arg);
527 Pat::Ref { pat, mutability } => {
529 if mutability.is_mut() {
532 self.print_pat(*pat);
534 Pat::Box { inner } => {
536 self.print_pat(*inner);
538 Pat::ConstBlock(c) => {
545 fn print_stmt(&mut self, stmt: &Statement) {
547 Statement::Let { pat, type_ref, initializer, else_branch } => {
549 self.print_pat(*pat);
550 if let Some(ty) = type_ref {
552 self.print_type_ref(ty);
554 if let Some(init) = initializer {
556 self.print_expr(*init);
558 if let Some(els) = else_branch {
560 self.print_expr(*els);
564 Statement::Expr { expr, has_semi } => {
565 self.print_expr(*expr);
574 fn print_literal(&mut self, literal: &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) => {
582 if let Some(suffix) = suffix {
583 w!(self, "{}", suffix);
586 Literal::Uint(i, suffix) => {
588 if let Some(suffix) = suffix {
589 w!(self, "{}", suffix);
592 Literal::Float(f, suffix) => {
594 if let Some(suffix) = suffix {
595 w!(self, "{}", suffix);
601 fn print_type_ref(&mut self, ty: &TypeRef) {
602 print_type_ref(ty, self).unwrap();
605 fn print_path(&mut self, path: &Path) {
606 print_path(path, self).unwrap();