]>
Commit | Line | Data |
---|---|---|
5099ac24 FG |
1 | use crate::pp::Breaks::Inconsistent; |
2 | use crate::pprust::state::{AnnNode, IterDelimited, PrintState, State, INDENT_UNIT}; | |
3 | ||
4 | use rustc_ast::ptr::P; | |
9c376795 FG |
5 | use rustc_ast::token; |
6 | use rustc_ast::util::literal::escape_byte_str_symbol; | |
5099ac24 FG |
7 | use rustc_ast::util::parser::{self, AssocOp, Fixity}; |
8 | use rustc_ast::{self as ast, BlockCheckMode}; | |
9ffffee4 FG |
9 | use rustc_ast::{ |
10 | FormatAlignment, FormatArgPosition, FormatArgsPiece, FormatCount, FormatDebugHex, FormatSign, | |
11 | FormatTrait, | |
12 | }; | |
13 | use std::fmt::Write; | |
5099ac24 FG |
14 | |
15 | impl<'a> State<'a> { | |
16 | fn print_else(&mut self, els: Option<&ast::Expr>) { | |
17 | if let Some(_else) = els { | |
487cf647 | 18 | match &_else.kind { |
5099ac24 | 19 | // Another `else if` block. |
487cf647 | 20 | ast::ExprKind::If(i, then, e) => { |
5099ac24 FG |
21 | self.cbox(INDENT_UNIT - 1); |
22 | self.ibox(0); | |
23 | self.word(" else if "); | |
24 | self.print_expr_as_cond(i); | |
25 | self.space(); | |
26 | self.print_block(then); | |
27 | self.print_else(e.as_deref()) | |
28 | } | |
29 | // Final `else` block. | |
487cf647 | 30 | ast::ExprKind::Block(b, _) => { |
5099ac24 FG |
31 | self.cbox(INDENT_UNIT - 1); |
32 | self.ibox(0); | |
33 | self.word(" else "); | |
34 | self.print_block(b) | |
35 | } | |
36 | // Constraints would be great here! | |
37 | _ => { | |
38 | panic!("print_if saw if with weird alternative"); | |
39 | } | |
40 | } | |
41 | } | |
42 | } | |
43 | ||
44 | fn print_if(&mut self, test: &ast::Expr, blk: &ast::Block, elseopt: Option<&ast::Expr>) { | |
45 | self.head("if"); | |
46 | self.print_expr_as_cond(test); | |
47 | self.space(); | |
48 | self.print_block(blk); | |
49 | self.print_else(elseopt) | |
50 | } | |
51 | ||
52 | fn print_call_post(&mut self, args: &[P<ast::Expr>]) { | |
53 | self.popen(); | |
54 | self.commasep_exprs(Inconsistent, args); | |
55 | self.pclose() | |
56 | } | |
57 | ||
58 | fn print_expr_maybe_paren(&mut self, expr: &ast::Expr, prec: i8) { | |
59 | self.print_expr_cond_paren(expr, expr.precedence().order() < prec) | |
60 | } | |
61 | ||
62 | /// Prints an expr using syntax that's acceptable in a condition position, such as the `cond` in | |
63 | /// `if cond { ... }`. | |
64 | fn print_expr_as_cond(&mut self, expr: &ast::Expr) { | |
65 | self.print_expr_cond_paren(expr, Self::cond_needs_par(expr)) | |
66 | } | |
67 | ||
487cf647 FG |
68 | /// Does `expr` need parentheses when printed in a condition position? |
69 | /// | |
70 | /// These cases need parens due to the parse error observed in #26461: `if return {}` | |
71 | /// parses as the erroneous construct `if (return {})`, not `if (return) {}`. | |
5099ac24 FG |
72 | pub(super) fn cond_needs_par(expr: &ast::Expr) -> bool { |
73 | match expr.kind { | |
04454e1e FG |
74 | ast::ExprKind::Break(..) |
75 | | ast::ExprKind::Closure(..) | |
76 | | ast::ExprKind::Ret(..) | |
77 | | ast::ExprKind::Yeet(..) => true, | |
5099ac24 FG |
78 | _ => parser::contains_exterior_struct_lit(expr), |
79 | } | |
80 | } | |
81 | ||
82 | /// Prints `expr` or `(expr)` when `needs_par` holds. | |
83 | pub(super) fn print_expr_cond_paren(&mut self, expr: &ast::Expr, needs_par: bool) { | |
84 | if needs_par { | |
85 | self.popen(); | |
86 | } | |
87 | self.print_expr(expr); | |
88 | if needs_par { | |
89 | self.pclose(); | |
90 | } | |
91 | } | |
92 | ||
93 | fn print_expr_vec(&mut self, exprs: &[P<ast::Expr>]) { | |
94 | self.ibox(INDENT_UNIT); | |
95 | self.word("["); | |
96 | self.commasep_exprs(Inconsistent, exprs); | |
97 | self.word("]"); | |
98 | self.end(); | |
99 | } | |
100 | ||
04454e1e FG |
101 | pub(super) fn print_expr_anon_const( |
102 | &mut self, | |
103 | expr: &ast::AnonConst, | |
104 | attrs: &[ast::Attribute], | |
105 | ) { | |
5099ac24 FG |
106 | self.ibox(INDENT_UNIT); |
107 | self.word("const"); | |
04454e1e FG |
108 | self.nbsp(); |
109 | if let ast::ExprKind::Block(block, None) = &expr.value.kind { | |
110 | self.cbox(0); | |
111 | self.ibox(0); | |
112 | self.print_block_with_attrs(block, attrs); | |
113 | } else { | |
114 | self.print_expr(&expr.value); | |
115 | } | |
5099ac24 FG |
116 | self.end(); |
117 | } | |
118 | ||
119 | fn print_expr_repeat(&mut self, element: &ast::Expr, count: &ast::AnonConst) { | |
120 | self.ibox(INDENT_UNIT); | |
121 | self.word("["); | |
122 | self.print_expr(element); | |
123 | self.word_space(";"); | |
124 | self.print_expr(&count.value); | |
125 | self.word("]"); | |
126 | self.end(); | |
127 | } | |
128 | ||
129 | fn print_expr_struct( | |
130 | &mut self, | |
487cf647 | 131 | qself: &Option<P<ast::QSelf>>, |
5099ac24 FG |
132 | path: &ast::Path, |
133 | fields: &[ast::ExprField], | |
134 | rest: &ast::StructRest, | |
135 | ) { | |
136 | if let Some(qself) = qself { | |
137 | self.print_qpath(path, qself, true); | |
138 | } else { | |
139 | self.print_path(path, true, 0); | |
140 | } | |
141 | self.nbsp(); | |
142 | self.word("{"); | |
143 | let has_rest = match rest { | |
144 | ast::StructRest::Base(_) | ast::StructRest::Rest(_) => true, | |
145 | ast::StructRest::None => false, | |
146 | }; | |
147 | if fields.is_empty() && !has_rest { | |
148 | self.word("}"); | |
149 | return; | |
150 | } | |
151 | self.cbox(0); | |
152 | for field in fields.iter().delimited() { | |
153 | self.maybe_print_comment(field.span.hi()); | |
154 | self.print_outer_attributes(&field.attrs); | |
155 | if field.is_first { | |
156 | self.space_if_not_bol(); | |
157 | } | |
158 | if !field.is_shorthand { | |
159 | self.print_ident(field.ident); | |
160 | self.word_nbsp(":"); | |
161 | } | |
162 | self.print_expr(&field.expr); | |
163 | if !field.is_last || has_rest { | |
164 | self.word_space(","); | |
165 | } else { | |
166 | self.trailing_comma_or_space(); | |
167 | } | |
168 | } | |
169 | if has_rest { | |
170 | if fields.is_empty() { | |
171 | self.space(); | |
172 | } | |
173 | self.word(".."); | |
174 | if let ast::StructRest::Base(expr) = rest { | |
175 | self.print_expr(expr); | |
176 | } | |
177 | self.space(); | |
178 | } | |
179 | self.offset(-INDENT_UNIT); | |
180 | self.end(); | |
181 | self.word("}"); | |
182 | } | |
183 | ||
184 | fn print_expr_tup(&mut self, exprs: &[P<ast::Expr>]) { | |
185 | self.popen(); | |
186 | self.commasep_exprs(Inconsistent, exprs); | |
187 | if exprs.len() == 1 { | |
188 | self.word(","); | |
189 | } | |
190 | self.pclose() | |
191 | } | |
192 | ||
193 | fn print_expr_call(&mut self, func: &ast::Expr, args: &[P<ast::Expr>]) { | |
194 | let prec = match func.kind { | |
195 | ast::ExprKind::Field(..) => parser::PREC_FORCE_PAREN, | |
196 | _ => parser::PREC_POSTFIX, | |
197 | }; | |
198 | ||
199 | self.print_expr_maybe_paren(func, prec); | |
200 | self.print_call_post(args) | |
201 | } | |
202 | ||
2b03887a FG |
203 | fn print_expr_method_call( |
204 | &mut self, | |
205 | segment: &ast::PathSegment, | |
206 | receiver: &ast::Expr, | |
207 | base_args: &[P<ast::Expr>], | |
208 | ) { | |
209 | self.print_expr_maybe_paren(receiver, parser::PREC_POSTFIX); | |
5099ac24 FG |
210 | self.word("."); |
211 | self.print_ident(segment.ident); | |
487cf647 | 212 | if let Some(args) = &segment.args { |
5099ac24 FG |
213 | self.print_generic_args(args, true); |
214 | } | |
215 | self.print_call_post(base_args) | |
216 | } | |
217 | ||
218 | fn print_expr_binary(&mut self, op: ast::BinOp, lhs: &ast::Expr, rhs: &ast::Expr) { | |
219 | let assoc_op = AssocOp::from_ast_binop(op.node); | |
220 | let prec = assoc_op.precedence() as i8; | |
221 | let fixity = assoc_op.fixity(); | |
222 | ||
223 | let (left_prec, right_prec) = match fixity { | |
224 | Fixity::Left => (prec, prec + 1), | |
225 | Fixity::Right => (prec + 1, prec), | |
226 | Fixity::None => (prec + 1, prec + 1), | |
227 | }; | |
228 | ||
229 | let left_prec = match (&lhs.kind, op.node) { | |
230 | // These cases need parens: `x as i32 < y` has the parser thinking that `i32 < y` is | |
231 | // the beginning of a path type. It starts trying to parse `x as (i32 < y ...` instead | |
232 | // of `(x as i32) < ...`. We need to convince it _not_ to do that. | |
233 | (&ast::ExprKind::Cast { .. }, ast::BinOpKind::Lt | ast::BinOpKind::Shl) => { | |
234 | parser::PREC_FORCE_PAREN | |
235 | } | |
236 | // We are given `(let _ = a) OP b`. | |
237 | // | |
238 | // - When `OP <= LAnd` we should print `let _ = a OP b` to avoid redundant parens | |
239 | // as the parser will interpret this as `(let _ = a) OP b`. | |
240 | // | |
241 | // - Otherwise, e.g. when we have `(let a = b) < c` in AST, | |
242 | // parens are required since the parser would interpret `let a = b < c` as | |
243 | // `let a = (b < c)`. To achieve this, we force parens. | |
244 | (&ast::ExprKind::Let { .. }, _) if !parser::needs_par_as_let_scrutinee(prec) => { | |
245 | parser::PREC_FORCE_PAREN | |
246 | } | |
247 | _ => left_prec, | |
248 | }; | |
249 | ||
250 | self.print_expr_maybe_paren(lhs, left_prec); | |
251 | self.space(); | |
252 | self.word_space(op.node.to_string()); | |
253 | self.print_expr_maybe_paren(rhs, right_prec) | |
254 | } | |
255 | ||
256 | fn print_expr_unary(&mut self, op: ast::UnOp, expr: &ast::Expr) { | |
257 | self.word(ast::UnOp::to_string(op)); | |
258 | self.print_expr_maybe_paren(expr, parser::PREC_PREFIX) | |
259 | } | |
260 | ||
261 | fn print_expr_addr_of( | |
262 | &mut self, | |
263 | kind: ast::BorrowKind, | |
264 | mutability: ast::Mutability, | |
265 | expr: &ast::Expr, | |
266 | ) { | |
267 | self.word("&"); | |
268 | match kind { | |
269 | ast::BorrowKind::Ref => self.print_mutability(mutability, false), | |
270 | ast::BorrowKind::Raw => { | |
271 | self.word_nbsp("raw"); | |
272 | self.print_mutability(mutability, true); | |
273 | } | |
274 | } | |
275 | self.print_expr_maybe_paren(expr, parser::PREC_PREFIX) | |
276 | } | |
277 | ||
278 | pub fn print_expr(&mut self, expr: &ast::Expr) { | |
279 | self.print_expr_outer_attr_style(expr, true) | |
280 | } | |
281 | ||
282 | pub(super) fn print_expr_outer_attr_style(&mut self, expr: &ast::Expr, is_inline: bool) { | |
283 | self.maybe_print_comment(expr.span.lo()); | |
284 | ||
285 | let attrs = &expr.attrs; | |
286 | if is_inline { | |
287 | self.print_outer_attributes_inline(attrs); | |
288 | } else { | |
289 | self.print_outer_attributes(attrs); | |
290 | } | |
291 | ||
292 | self.ibox(INDENT_UNIT); | |
293 | self.ann.pre(self, AnnNode::Expr(expr)); | |
487cf647 FG |
294 | match &expr.kind { |
295 | ast::ExprKind::Box(expr) => { | |
5099ac24 FG |
296 | self.word_space("box"); |
297 | self.print_expr_maybe_paren(expr, parser::PREC_PREFIX); | |
298 | } | |
487cf647 | 299 | ast::ExprKind::Array(exprs) => { |
5099ac24 FG |
300 | self.print_expr_vec(exprs); |
301 | } | |
487cf647 | 302 | ast::ExprKind::ConstBlock(anon_const) => { |
04454e1e | 303 | self.print_expr_anon_const(anon_const, attrs); |
5099ac24 | 304 | } |
487cf647 | 305 | ast::ExprKind::Repeat(element, count) => { |
5099ac24 FG |
306 | self.print_expr_repeat(element, count); |
307 | } | |
487cf647 | 308 | ast::ExprKind::Struct(se) => { |
5099ac24 FG |
309 | self.print_expr_struct(&se.qself, &se.path, &se.fields, &se.rest); |
310 | } | |
487cf647 | 311 | ast::ExprKind::Tup(exprs) => { |
5099ac24 FG |
312 | self.print_expr_tup(exprs); |
313 | } | |
487cf647 FG |
314 | ast::ExprKind::Call(func, args) => { |
315 | self.print_expr_call(func, args); | |
316 | } | |
317 | ast::ExprKind::MethodCall(box ast::MethodCall { seg, receiver, args, .. }) => { | |
318 | self.print_expr_method_call(seg, receiver, args); | |
5099ac24 | 319 | } |
487cf647 FG |
320 | ast::ExprKind::Binary(op, lhs, rhs) => { |
321 | self.print_expr_binary(*op, lhs, rhs); | |
5099ac24 | 322 | } |
487cf647 FG |
323 | ast::ExprKind::Unary(op, expr) => { |
324 | self.print_expr_unary(*op, expr); | |
5099ac24 | 325 | } |
487cf647 FG |
326 | ast::ExprKind::AddrOf(k, m, expr) => { |
327 | self.print_expr_addr_of(*k, *m, expr); | |
5099ac24 | 328 | } |
487cf647 FG |
329 | ast::ExprKind::Lit(token_lit) => { |
330 | self.print_token_literal(*token_lit, expr.span); | |
5099ac24 | 331 | } |
487cf647 | 332 | ast::ExprKind::IncludedBytes(bytes) => { |
9c376795 | 333 | let lit = token::Lit::new(token::ByteStr, escape_byte_str_symbol(bytes), None); |
487cf647 | 334 | self.print_token_literal(lit, expr.span) |
5099ac24 | 335 | } |
487cf647 | 336 | ast::ExprKind::Cast(expr, ty) => { |
5099ac24 FG |
337 | let prec = AssocOp::As.precedence() as i8; |
338 | self.print_expr_maybe_paren(expr, prec); | |
339 | self.space(); | |
340 | self.word_space("as"); | |
341 | self.print_type(ty); | |
342 | } | |
487cf647 | 343 | ast::ExprKind::Type(expr, ty) => { |
5099ac24 FG |
344 | let prec = AssocOp::Colon.precedence() as i8; |
345 | self.print_expr_maybe_paren(expr, prec); | |
346 | self.word_space(":"); | |
347 | self.print_type(ty); | |
348 | } | |
487cf647 | 349 | ast::ExprKind::Let(pat, scrutinee, _) => { |
5099ac24 FG |
350 | self.print_let(pat, scrutinee); |
351 | } | |
487cf647 FG |
352 | ast::ExprKind::If(test, blk, elseopt) => self.print_if(test, blk, elseopt.as_deref()), |
353 | ast::ExprKind::While(test, blk, opt_label) => { | |
5099ac24 FG |
354 | if let Some(label) = opt_label { |
355 | self.print_ident(label.ident); | |
356 | self.word_space(":"); | |
357 | } | |
358 | self.cbox(0); | |
359 | self.ibox(0); | |
360 | self.word_nbsp("while"); | |
361 | self.print_expr_as_cond(test); | |
362 | self.space(); | |
363 | self.print_block_with_attrs(blk, attrs); | |
364 | } | |
487cf647 | 365 | ast::ExprKind::ForLoop(pat, iter, blk, opt_label) => { |
5099ac24 FG |
366 | if let Some(label) = opt_label { |
367 | self.print_ident(label.ident); | |
368 | self.word_space(":"); | |
369 | } | |
370 | self.cbox(0); | |
371 | self.ibox(0); | |
372 | self.word_nbsp("for"); | |
373 | self.print_pat(pat); | |
374 | self.space(); | |
375 | self.word_space("in"); | |
376 | self.print_expr_as_cond(iter); | |
377 | self.space(); | |
378 | self.print_block_with_attrs(blk, attrs); | |
379 | } | |
487cf647 | 380 | ast::ExprKind::Loop(blk, opt_label, _) => { |
5099ac24 FG |
381 | if let Some(label) = opt_label { |
382 | self.print_ident(label.ident); | |
383 | self.word_space(":"); | |
384 | } | |
385 | self.cbox(0); | |
386 | self.ibox(0); | |
387 | self.word_nbsp("loop"); | |
388 | self.print_block_with_attrs(blk, attrs); | |
389 | } | |
487cf647 | 390 | ast::ExprKind::Match(expr, arms) => { |
5099ac24 FG |
391 | self.cbox(0); |
392 | self.ibox(0); | |
393 | self.word_nbsp("match"); | |
394 | self.print_expr_as_cond(expr); | |
395 | self.space(); | |
396 | self.bopen(); | |
397 | self.print_inner_attributes_no_trailing_hardbreak(attrs); | |
398 | for arm in arms { | |
399 | self.print_arm(arm); | |
400 | } | |
401 | let empty = attrs.is_empty() && arms.is_empty(); | |
402 | self.bclose(expr.span, empty); | |
403 | } | |
487cf647 FG |
404 | ast::ExprKind::Closure(box ast::Closure { |
405 | binder, | |
5099ac24 | 406 | capture_clause, |
9c376795 | 407 | constness, |
5099ac24 FG |
408 | asyncness, |
409 | movability, | |
487cf647 FG |
410 | fn_decl, |
411 | body, | |
412 | fn_decl_span: _, | |
413 | fn_arg_span: _, | |
414 | }) => { | |
064997fb | 415 | self.print_closure_binder(binder); |
9c376795 | 416 | self.print_constness(*constness); |
487cf647 FG |
417 | self.print_movability(*movability); |
418 | self.print_asyncness(*asyncness); | |
419 | self.print_capture_clause(*capture_clause); | |
5099ac24 | 420 | |
487cf647 | 421 | self.print_fn_params_and_ret(fn_decl, true); |
5099ac24 FG |
422 | self.space(); |
423 | self.print_expr(body); | |
424 | self.end(); // need to close a box | |
425 | ||
426 | // a box will be closed by print_expr, but we didn't want an overall | |
427 | // wrapper so we closed the corresponding opening. so create an | |
428 | // empty box to satisfy the close. | |
429 | self.ibox(0); | |
430 | } | |
487cf647 | 431 | ast::ExprKind::Block(blk, opt_label) => { |
5099ac24 FG |
432 | if let Some(label) = opt_label { |
433 | self.print_ident(label.ident); | |
434 | self.word_space(":"); | |
435 | } | |
436 | // containing cbox, will be closed by print-block at } | |
437 | self.cbox(0); | |
438 | // head-box, will be closed by print-block after { | |
439 | self.ibox(0); | |
440 | self.print_block_with_attrs(blk, attrs); | |
441 | } | |
487cf647 | 442 | ast::ExprKind::Async(capture_clause, _, blk) => { |
5099ac24 | 443 | self.word_nbsp("async"); |
487cf647 | 444 | self.print_capture_clause(*capture_clause); |
5099ac24 FG |
445 | // cbox/ibox in analogy to the `ExprKind::Block` arm above |
446 | self.cbox(0); | |
447 | self.ibox(0); | |
448 | self.print_block_with_attrs(blk, attrs); | |
449 | } | |
487cf647 | 450 | ast::ExprKind::Await(expr) => { |
5099ac24 FG |
451 | self.print_expr_maybe_paren(expr, parser::PREC_POSTFIX); |
452 | self.word(".await"); | |
453 | } | |
487cf647 | 454 | ast::ExprKind::Assign(lhs, rhs, _) => { |
5099ac24 FG |
455 | let prec = AssocOp::Assign.precedence() as i8; |
456 | self.print_expr_maybe_paren(lhs, prec + 1); | |
457 | self.space(); | |
458 | self.word_space("="); | |
459 | self.print_expr_maybe_paren(rhs, prec); | |
460 | } | |
487cf647 | 461 | ast::ExprKind::AssignOp(op, lhs, rhs) => { |
5099ac24 FG |
462 | let prec = AssocOp::Assign.precedence() as i8; |
463 | self.print_expr_maybe_paren(lhs, prec + 1); | |
464 | self.space(); | |
465 | self.word(op.node.to_string()); | |
466 | self.word_space("="); | |
467 | self.print_expr_maybe_paren(rhs, prec); | |
468 | } | |
487cf647 | 469 | ast::ExprKind::Field(expr, ident) => { |
5099ac24 FG |
470 | self.print_expr_maybe_paren(expr, parser::PREC_POSTFIX); |
471 | self.word("."); | |
487cf647 | 472 | self.print_ident(*ident); |
5099ac24 | 473 | } |
487cf647 | 474 | ast::ExprKind::Index(expr, index) => { |
5099ac24 FG |
475 | self.print_expr_maybe_paren(expr, parser::PREC_POSTFIX); |
476 | self.word("["); | |
477 | self.print_expr(index); | |
478 | self.word("]"); | |
479 | } | |
487cf647 | 480 | ast::ExprKind::Range(start, end, limits) => { |
9c376795 | 481 | // Special case for `Range`. `AssocOp` claims that `Range` has higher precedence |
5099ac24 FG |
482 | // than `Assign`, but `x .. x = x` gives a parse error instead of `x .. (x = x)`. |
483 | // Here we use a fake precedence value so that any child with lower precedence than | |
9c376795 | 484 | // a "normal" binop gets parenthesized. (`LOr` is the lowest-precedence binop.) |
5099ac24 | 485 | let fake_prec = AssocOp::LOr.precedence() as i8; |
487cf647 | 486 | if let Some(e) = start { |
5099ac24 FG |
487 | self.print_expr_maybe_paren(e, fake_prec); |
488 | } | |
487cf647 FG |
489 | match limits { |
490 | ast::RangeLimits::HalfOpen => self.word(".."), | |
491 | ast::RangeLimits::Closed => self.word("..="), | |
5099ac24 | 492 | } |
487cf647 | 493 | if let Some(e) = end { |
5099ac24 FG |
494 | self.print_expr_maybe_paren(e, fake_prec); |
495 | } | |
496 | } | |
497 | ast::ExprKind::Underscore => self.word("_"), | |
487cf647 FG |
498 | ast::ExprKind::Path(None, path) => self.print_path(path, true, 0), |
499 | ast::ExprKind::Path(Some(qself), path) => self.print_qpath(path, qself, true), | |
500 | ast::ExprKind::Break(opt_label, opt_expr) => { | |
5099ac24 FG |
501 | self.word("break"); |
502 | if let Some(label) = opt_label { | |
503 | self.space(); | |
504 | self.print_ident(label.ident); | |
505 | } | |
487cf647 | 506 | if let Some(expr) = opt_expr { |
5099ac24 FG |
507 | self.space(); |
508 | self.print_expr_maybe_paren(expr, parser::PREC_JUMP); | |
509 | } | |
510 | } | |
511 | ast::ExprKind::Continue(opt_label) => { | |
512 | self.word("continue"); | |
513 | if let Some(label) = opt_label { | |
514 | self.space(); | |
515 | self.print_ident(label.ident); | |
516 | } | |
517 | } | |
487cf647 | 518 | ast::ExprKind::Ret(result) => { |
5099ac24 | 519 | self.word("return"); |
487cf647 | 520 | if let Some(expr) = result { |
5099ac24 FG |
521 | self.word(" "); |
522 | self.print_expr_maybe_paren(expr, parser::PREC_JUMP); | |
523 | } | |
524 | } | |
487cf647 | 525 | ast::ExprKind::Yeet(result) => { |
04454e1e FG |
526 | self.word("do"); |
527 | self.word(" "); | |
528 | self.word("yeet"); | |
487cf647 | 529 | if let Some(expr) = result { |
04454e1e FG |
530 | self.word(" "); |
531 | self.print_expr_maybe_paren(expr, parser::PREC_JUMP); | |
532 | } | |
533 | } | |
487cf647 | 534 | ast::ExprKind::InlineAsm(a) => { |
9ffffee4 | 535 | // FIXME: This should have its own syntax, distinct from a macro invocation. |
5099ac24 FG |
536 | self.word("asm!"); |
537 | self.print_inline_asm(a); | |
538 | } | |
9ffffee4 FG |
539 | ast::ExprKind::FormatArgs(fmt) => { |
540 | // FIXME: This should have its own syntax, distinct from a macro invocation. | |
541 | self.word("format_args!"); | |
542 | self.popen(); | |
543 | self.rbox(0, Inconsistent); | |
544 | self.word(reconstruct_format_args_template_string(&fmt.template)); | |
545 | for arg in fmt.arguments.all_args() { | |
546 | self.word_space(","); | |
547 | self.print_expr(&arg.expr); | |
548 | } | |
549 | self.end(); | |
550 | self.pclose(); | |
551 | } | |
487cf647 FG |
552 | ast::ExprKind::MacCall(m) => self.print_mac(m), |
553 | ast::ExprKind::Paren(e) => { | |
5099ac24 FG |
554 | self.popen(); |
555 | self.print_expr(e); | |
556 | self.pclose(); | |
557 | } | |
487cf647 | 558 | ast::ExprKind::Yield(e) => { |
5099ac24 FG |
559 | self.word("yield"); |
560 | ||
487cf647 | 561 | if let Some(expr) = e { |
5099ac24 FG |
562 | self.space(); |
563 | self.print_expr_maybe_paren(expr, parser::PREC_JUMP); | |
564 | } | |
565 | } | |
487cf647 | 566 | ast::ExprKind::Try(e) => { |
5099ac24 FG |
567 | self.print_expr_maybe_paren(e, parser::PREC_POSTFIX); |
568 | self.word("?") | |
569 | } | |
487cf647 | 570 | ast::ExprKind::TryBlock(blk) => { |
5099ac24 FG |
571 | self.cbox(0); |
572 | self.ibox(0); | |
573 | self.word_nbsp("try"); | |
574 | self.print_block_with_attrs(blk, attrs) | |
575 | } | |
576 | ast::ExprKind::Err => { | |
577 | self.popen(); | |
578 | self.word("/*ERROR*/"); | |
579 | self.pclose() | |
580 | } | |
581 | } | |
582 | self.ann.post(self, AnnNode::Expr(expr)); | |
583 | self.end(); | |
584 | } | |
585 | ||
586 | fn print_arm(&mut self, arm: &ast::Arm) { | |
587 | // Note, I have no idea why this check is necessary, but here it is. | |
588 | if arm.attrs.is_empty() { | |
589 | self.space(); | |
590 | } | |
591 | self.cbox(INDENT_UNIT); | |
592 | self.ibox(0); | |
593 | self.maybe_print_comment(arm.pat.span.lo()); | |
594 | self.print_outer_attributes(&arm.attrs); | |
595 | self.print_pat(&arm.pat); | |
596 | self.space(); | |
487cf647 | 597 | if let Some(e) = &arm.guard { |
5099ac24 FG |
598 | self.word_space("if"); |
599 | self.print_expr(e); | |
600 | self.space(); | |
601 | } | |
602 | self.word_space("=>"); | |
603 | ||
487cf647 FG |
604 | match &arm.body.kind { |
605 | ast::ExprKind::Block(blk, opt_label) => { | |
5099ac24 FG |
606 | if let Some(label) = opt_label { |
607 | self.print_ident(label.ident); | |
608 | self.word_space(":"); | |
609 | } | |
610 | ||
611 | // The block will close the pattern's ibox. | |
612 | self.print_block_unclosed_indent(blk); | |
613 | ||
614 | // If it is a user-provided unsafe block, print a comma after it. | |
615 | if let BlockCheckMode::Unsafe(ast::UserProvided) = blk.rules { | |
616 | self.word(","); | |
617 | } | |
618 | } | |
619 | _ => { | |
620 | self.end(); // Close the ibox for the pattern. | |
621 | self.print_expr(&arm.body); | |
622 | self.word(","); | |
623 | } | |
624 | } | |
625 | self.end(); // Close enclosing cbox. | |
626 | } | |
627 | ||
064997fb FG |
628 | fn print_closure_binder(&mut self, binder: &ast::ClosureBinder) { |
629 | match binder { | |
630 | ast::ClosureBinder::NotPresent => {} | |
631 | ast::ClosureBinder::For { generic_params, .. } => { | |
487cf647 | 632 | self.print_formal_generic_params(generic_params) |
064997fb FG |
633 | } |
634 | } | |
635 | } | |
636 | ||
5099ac24 FG |
637 | fn print_movability(&mut self, movability: ast::Movability) { |
638 | match movability { | |
639 | ast::Movability::Static => self.word_space("static"), | |
640 | ast::Movability::Movable => {} | |
641 | } | |
642 | } | |
643 | ||
644 | fn print_capture_clause(&mut self, capture_clause: ast::CaptureBy) { | |
645 | match capture_clause { | |
646 | ast::CaptureBy::Value => self.word_space("move"), | |
647 | ast::CaptureBy::Ref => {} | |
648 | } | |
649 | } | |
650 | } | |
9ffffee4 FG |
651 | |
652 | pub fn reconstruct_format_args_template_string(pieces: &[FormatArgsPiece]) -> String { | |
653 | let mut template = "\"".to_string(); | |
654 | for piece in pieces { | |
655 | match piece { | |
656 | FormatArgsPiece::Literal(s) => { | |
657 | for c in s.as_str().escape_debug() { | |
658 | template.push(c); | |
659 | if let '{' | '}' = c { | |
660 | template.push(c); | |
661 | } | |
662 | } | |
663 | } | |
664 | FormatArgsPiece::Placeholder(p) => { | |
665 | template.push('{'); | |
666 | let (Ok(n) | Err(n)) = p.argument.index; | |
667 | write!(template, "{n}").unwrap(); | |
668 | if p.format_options != Default::default() || p.format_trait != FormatTrait::Display | |
669 | { | |
670 | template.push_str(":"); | |
671 | } | |
672 | if let Some(fill) = p.format_options.fill { | |
673 | template.push(fill); | |
674 | } | |
675 | match p.format_options.alignment { | |
676 | Some(FormatAlignment::Left) => template.push_str("<"), | |
677 | Some(FormatAlignment::Right) => template.push_str(">"), | |
678 | Some(FormatAlignment::Center) => template.push_str("^"), | |
679 | None => {} | |
680 | } | |
681 | match p.format_options.sign { | |
682 | Some(FormatSign::Plus) => template.push('+'), | |
683 | Some(FormatSign::Minus) => template.push('-'), | |
684 | None => {} | |
685 | } | |
686 | if p.format_options.alternate { | |
687 | template.push('#'); | |
688 | } | |
689 | if p.format_options.zero_pad { | |
690 | template.push('0'); | |
691 | } | |
692 | if let Some(width) = &p.format_options.width { | |
693 | match width { | |
694 | FormatCount::Literal(n) => write!(template, "{n}").unwrap(), | |
695 | FormatCount::Argument(FormatArgPosition { | |
696 | index: Ok(n) | Err(n), .. | |
697 | }) => { | |
698 | write!(template, "{n}$").unwrap(); | |
699 | } | |
700 | } | |
701 | } | |
702 | if let Some(precision) = &p.format_options.precision { | |
703 | template.push('.'); | |
704 | match precision { | |
705 | FormatCount::Literal(n) => write!(template, "{n}").unwrap(), | |
706 | FormatCount::Argument(FormatArgPosition { | |
707 | index: Ok(n) | Err(n), .. | |
708 | }) => { | |
709 | write!(template, "{n}$").unwrap(); | |
710 | } | |
711 | } | |
712 | } | |
713 | match p.format_options.debug_hex { | |
714 | Some(FormatDebugHex::Lower) => template.push('x'), | |
715 | Some(FormatDebugHex::Upper) => template.push('X'), | |
716 | None => {} | |
717 | } | |
718 | template.push_str(match p.format_trait { | |
719 | FormatTrait::Display => "", | |
720 | FormatTrait::Debug => "?", | |
721 | FormatTrait::LowerExp => "e", | |
722 | FormatTrait::UpperExp => "E", | |
723 | FormatTrait::Octal => "o", | |
724 | FormatTrait::Pointer => "p", | |
725 | FormatTrait::Binary => "b", | |
726 | FormatTrait::LowerHex => "x", | |
727 | FormatTrait::UpperHex => "X", | |
728 | }); | |
729 | template.push('}'); | |
730 | } | |
731 | } | |
732 | } | |
733 | template.push('"'); | |
734 | template | |
735 | } |