1 //! A pretty-printer for HIR.
3 use std::fmt::{self, Write};
5 use syntax::ast::HasName;
8 expr::{Array, BindingAnnotation, ClosureKind, Literal, Movability, Statement},
9 pretty::{print_generic_args, print_path, print_type_ref},
15 pub(super) fn print_body_hir(db: &dyn DefDatabase, body: &Body, owner: DefWithBodyId) -> String {
17 let header = match owner {
18 DefWithBodyId::FunctionId(it) => {
20 let item_tree_id = it.lookup(db).id;
21 format!("fn {}(…) ", item_tree_id.item_tree(db)[item_tree_id.value].name)
23 DefWithBodyId::StaticId(it) => {
25 let item_tree_id = it.lookup(db).id;
26 format!("static {} = ", item_tree_id.item_tree(db)[item_tree_id.value].name)
28 DefWithBodyId::ConstId(it) => {
30 let item_tree_id = it.lookup(db).id;
31 let name = match &item_tree_id.item_tree(db)[item_tree_id.value].name {
32 Some(name) => name.to_string(),
33 None => "_".to_string(),
35 format!("const {name} = ")
37 DefWithBodyId::VariantId(it) => {
39 let src = it.parent.child_source(db);
40 let variant = &src.value[it.local_id];
41 let name = match &variant.name() {
42 Some(name) => name.to_string(),
43 None => "_".to_string(),
49 let mut p = Printer { body, buf: header, indent_level: 0, needs_indent: false };
50 p.print_expr(body.body_expr);
58 ($dst:expr, $($arg:tt)*) => {
59 { let _ = write!($dst, $($arg)*); }
65 { let _ = writeln!($dst); }
67 ($dst:expr, $($arg:tt)*) => {
68 { let _ = writeln!($dst, $($arg)*); }
79 impl<'a> Write for Printer<'a> {
80 fn write_str(&mut self, s: &str) -> fmt::Result {
81 for line in s.split_inclusive('\n') {
82 if self.needs_indent {
83 match self.buf.chars().rev().skip_while(|ch| *ch == ' ').next() {
84 Some('\n') | None => {}
85 _ => self.buf.push('\n'),
87 self.buf.push_str(&" ".repeat(self.indent_level));
88 self.needs_indent = false;
91 self.buf.push_str(line);
92 self.needs_indent = line.ends_with('\n');
99 impl<'a> Printer<'a> {
100 fn indented(&mut self, f: impl FnOnce(&mut Self)) {
101 self.indent_level += 1;
104 self.indent_level -= 1;
105 self.buf = self.buf.trim_end_matches('\n').to_string();
108 fn whitespace(&mut self) {
109 match self.buf.chars().next_back() {
110 None | Some('\n' | ' ') => {}
111 _ => self.buf.push(' '),
115 fn newline(&mut self) {
116 match self.buf.chars().rev().skip_while(|ch| *ch == ' ').next() {
117 Some('\n') | None => {}
118 _ => writeln!(self).unwrap(),
122 fn print_expr(&mut self, expr: ExprId) {
123 let expr = &self.body[expr];
126 Expr::Missing => w!(self, "�"),
127 Expr::Underscore => w!(self, "_"),
128 Expr::Path(path) => self.print_path(path),
129 Expr::If { condition, then_branch, else_branch } => {
131 self.print_expr(*condition);
133 self.print_expr(*then_branch);
134 if let Some(els) = *else_branch {
136 self.print_expr(els);
139 Expr::Let { pat, expr } => {
141 self.print_pat(*pat);
143 self.print_expr(*expr);
145 Expr::Loop { body, label } => {
146 if let Some(lbl) = label {
147 w!(self, "{}: ", self.body[*lbl].name);
150 self.print_expr(*body);
152 Expr::While { condition, body, label } => {
153 if let Some(lbl) = label {
154 w!(self, "{}: ", self.body[*lbl].name);
157 self.print_expr(*condition);
158 self.print_expr(*body);
160 Expr::For { iterable, pat, body, label } => {
161 if let Some(lbl) = label {
162 w!(self, "{}: ", self.body[*lbl].name);
165 self.print_pat(*pat);
167 self.print_expr(*iterable);
168 self.print_expr(*body);
170 Expr::Call { callee, args, is_assignee_expr: _ } => {
171 self.print_expr(*callee);
173 if !args.is_empty() {
183 Expr::MethodCall { receiver, method_name, args, generic_args } => {
184 self.print_expr(*receiver);
185 w!(self, ".{}", method_name);
186 if let Some(args) = generic_args {
188 print_generic_args(args, self).unwrap();
192 if !args.is_empty() {
202 Expr::Match { expr, arms } => {
204 self.print_expr(*expr);
208 p.print_pat(arm.pat);
209 if let Some(guard) = arm.guard {
214 p.print_expr(arm.expr);
220 Expr::Continue { label } => {
221 w!(self, "continue");
222 if let Some(label) = label {
223 w!(self, " {}", label);
226 Expr::Break { expr, label } => {
228 if let Some(label) = label {
229 w!(self, " {}", label);
231 if let Some(expr) = expr {
233 self.print_expr(*expr);
236 Expr::Return { expr } => {
238 if let Some(expr) = expr {
240 self.print_expr(*expr);
243 Expr::Yield { expr } => {
245 if let Some(expr) = expr {
247 self.print_expr(*expr);
250 Expr::Yeet { expr } => {
254 if let Some(expr) = expr {
256 self.print_expr(*expr);
259 Expr::RecordLit { path, fields, spread, ellipsis, is_assignee_expr: _ } => {
261 Some(path) => self.print_path(path),
262 None => w!(self, "�"),
267 for field in &**fields {
268 w!(p, "{}: ", field.name);
269 p.print_expr(field.expr);
272 if let Some(spread) = spread {
274 p.print_expr(*spread);
283 Expr::Field { expr, name } => {
284 self.print_expr(*expr);
285 w!(self, ".{}", name);
287 Expr::Await { expr } => {
288 self.print_expr(*expr);
291 Expr::Try { expr } => {
292 self.print_expr(*expr);
295 Expr::TryBlock { body } => {
297 self.print_expr(*body);
299 Expr::Async { body } => {
301 self.print_expr(*body);
303 Expr::Const { body } => {
305 self.print_expr(*body);
307 Expr::Cast { expr, type_ref } => {
308 self.print_expr(*expr);
310 self.print_type_ref(type_ref);
312 Expr::Ref { expr, rawness, mutability } => {
314 if rawness.is_raw() {
317 if mutability.is_mut() {
320 self.print_expr(*expr);
322 Expr::Box { expr } => {
324 self.print_expr(*expr);
326 Expr::UnaryOp { expr, op } => {
328 ast::UnaryOp::Deref => "*",
329 ast::UnaryOp::Not => "!",
330 ast::UnaryOp::Neg => "-",
333 self.print_expr(*expr);
335 Expr::BinaryOp { lhs, rhs, op } => {
336 let (bra, ket) = match op {
337 None | Some(ast::BinaryOp::Assignment { .. }) => ("", ""),
341 self.print_expr(*lhs);
342 w!(self, "{} ", ket);
344 Some(op) => w!(self, "{}", op),
345 None => w!(self, "�"), // :)
347 w!(self, " {}", bra);
348 self.print_expr(*rhs);
351 Expr::Range { lhs, rhs, range_type } => {
352 if let Some(lhs) = lhs {
354 self.print_expr(*lhs);
357 let range = match range_type {
358 ast::RangeOp::Exclusive => "..",
359 ast::RangeOp::Inclusive => "..=",
361 w!(self, "{}", range);
362 if let Some(rhs) = rhs {
364 self.print_expr(*rhs);
368 Expr::Index { base, index } => {
369 self.print_expr(*base);
371 self.print_expr(*index);
374 Expr::Closure { args, arg_types, ret_type, body, closure_kind } => {
375 if let ClosureKind::Generator(Movability::Static) = closure_kind {
379 for (i, (pat, ty)) in args.iter().zip(arg_types.iter()).enumerate() {
383 self.print_pat(*pat);
384 if let Some(ty) = ty {
386 self.print_type_ref(ty);
390 if let Some(ret_ty) = ret_type {
392 self.print_type_ref(ret_ty);
395 self.print_expr(*body);
397 Expr::Tuple { exprs, is_assignee_expr: _ } => {
399 for expr in exprs.iter() {
400 self.print_expr(*expr);
405 Expr::Unsafe { body } => {
407 self.print_expr(*body);
409 Expr::Array(arr) => {
411 if !matches!(arr, Array::ElementList { elements, .. } if elements.is_empty()) {
412 self.indented(|p| match arr {
413 Array::ElementList { elements, is_assignee_expr: _ } => {
414 for elem in elements.iter() {
419 Array::Repeat { initializer, repeat } => {
420 p.print_expr(*initializer);
422 p.print_expr(*repeat);
429 Expr::Literal(lit) => self.print_literal(lit),
430 Expr::Block { id: _, statements, tail, label } => {
432 if let Some(lbl) = label {
433 w!(self, "{}: ", self.body[*lbl].name);
436 if !statements.is_empty() || tail.is_some() {
438 for stmt in &**statements {
441 if let Some(tail) = tail {
452 fn print_pat(&mut self, pat: PatId) {
453 let pat = &self.body[pat];
456 Pat::Missing => w!(self, "�"),
457 Pat::Wild => w!(self, "_"),
458 Pat::Tuple { args, ellipsis } => {
460 for (i, pat) in args.iter().enumerate() {
464 if *ellipsis == Some(i) {
467 self.print_pat(*pat);
472 for (i, pat) in pats.iter().enumerate() {
476 self.print_pat(*pat);
479 Pat::Record { path, args, ellipsis } => {
481 Some(path) => self.print_path(path),
482 None => w!(self, "�"),
487 for arg in args.iter() {
488 w!(p, "{}: ", arg.name);
489 p.print_pat(arg.pat);
498 Pat::Range { start, end } => {
499 self.print_expr(*start);
501 self.print_expr(*end);
503 Pat::Slice { prefix, slice, suffix } => {
505 for pat in prefix.iter() {
506 self.print_pat(*pat);
509 if let Some(pat) = slice {
510 self.print_pat(*pat);
513 for pat in suffix.iter() {
514 self.print_pat(*pat);
519 Pat::Path(path) => self.print_path(path),
520 Pat::Lit(expr) => self.print_expr(*expr),
521 Pat::Bind { mode, name, subpat } => {
522 let mode = match mode {
523 BindingAnnotation::Unannotated => "",
524 BindingAnnotation::Mutable => "mut ",
525 BindingAnnotation::Ref => "ref ",
526 BindingAnnotation::RefMut => "ref mut ",
528 w!(self, "{}{}", mode, name);
529 if let Some(pat) = subpat {
531 self.print_pat(*pat);
534 Pat::TupleStruct { path, args, ellipsis } => {
536 Some(path) => self.print_path(path),
537 None => w!(self, "�"),
540 for (i, arg) in args.iter().enumerate() {
544 if *ellipsis == Some(i) {
547 self.print_pat(*arg);
551 Pat::Ref { pat, mutability } => {
553 if mutability.is_mut() {
556 self.print_pat(*pat);
558 Pat::Box { inner } => {
560 self.print_pat(*inner);
562 Pat::ConstBlock(c) => {
569 fn print_stmt(&mut self, stmt: &Statement) {
571 Statement::Let { pat, type_ref, initializer, else_branch } => {
573 self.print_pat(*pat);
574 if let Some(ty) = type_ref {
576 self.print_type_ref(ty);
578 if let Some(init) = initializer {
580 self.print_expr(*init);
582 if let Some(els) = else_branch {
584 self.print_expr(*els);
588 Statement::Expr { expr, has_semi } => {
589 self.print_expr(*expr);
598 fn print_literal(&mut self, literal: &Literal) {
600 Literal::String(it) => w!(self, "{:?}", it),
601 Literal::ByteString(it) => w!(self, "\"{}\"", it.escape_ascii()),
602 Literal::Char(it) => w!(self, "'{}'", it.escape_debug()),
603 Literal::Bool(it) => w!(self, "{}", it),
604 Literal::Int(i, suffix) => {
606 if let Some(suffix) = suffix {
607 w!(self, "{}", suffix);
610 Literal::Uint(i, suffix) => {
612 if let Some(suffix) = suffix {
613 w!(self, "{}", suffix);
616 Literal::Float(f, suffix) => {
618 if let Some(suffix) = suffix {
619 w!(self, "{}", suffix);
625 fn print_type_ref(&mut self, ty: &TypeRef) {
626 print_type_ref(ty, self).unwrap();
629 fn print_path(&mut self, path: &Path) {
630 print_path(path, self).unwrap();