]>
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 | } | |
353b0b11 FG |
247 | // For a binary expression like `(match () { _ => a }) OP b`, the parens are required |
248 | // otherwise the parser would interpret `match () { _ => a }` as a statement, | |
249 | // with the remaining `OP b` not making sense. So we force parens. | |
250 | (&ast::ExprKind::Match(..), _) => parser::PREC_FORCE_PAREN, | |
5099ac24 FG |
251 | _ => left_prec, |
252 | }; | |
253 | ||
254 | self.print_expr_maybe_paren(lhs, left_prec); | |
255 | self.space(); | |
256 | self.word_space(op.node.to_string()); | |
257 | self.print_expr_maybe_paren(rhs, right_prec) | |
258 | } | |
259 | ||
260 | fn print_expr_unary(&mut self, op: ast::UnOp, expr: &ast::Expr) { | |
261 | self.word(ast::UnOp::to_string(op)); | |
262 | self.print_expr_maybe_paren(expr, parser::PREC_PREFIX) | |
263 | } | |
264 | ||
265 | fn print_expr_addr_of( | |
266 | &mut self, | |
267 | kind: ast::BorrowKind, | |
268 | mutability: ast::Mutability, | |
269 | expr: &ast::Expr, | |
270 | ) { | |
271 | self.word("&"); | |
272 | match kind { | |
273 | ast::BorrowKind::Ref => self.print_mutability(mutability, false), | |
274 | ast::BorrowKind::Raw => { | |
275 | self.word_nbsp("raw"); | |
276 | self.print_mutability(mutability, true); | |
277 | } | |
278 | } | |
279 | self.print_expr_maybe_paren(expr, parser::PREC_PREFIX) | |
280 | } | |
281 | ||
282 | pub fn print_expr(&mut self, expr: &ast::Expr) { | |
283 | self.print_expr_outer_attr_style(expr, true) | |
284 | } | |
285 | ||
286 | pub(super) fn print_expr_outer_attr_style(&mut self, expr: &ast::Expr, is_inline: bool) { | |
287 | self.maybe_print_comment(expr.span.lo()); | |
288 | ||
289 | let attrs = &expr.attrs; | |
290 | if is_inline { | |
291 | self.print_outer_attributes_inline(attrs); | |
292 | } else { | |
293 | self.print_outer_attributes(attrs); | |
294 | } | |
295 | ||
296 | self.ibox(INDENT_UNIT); | |
297 | self.ann.pre(self, AnnNode::Expr(expr)); | |
487cf647 | 298 | match &expr.kind { |
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) => { |
49aad941 FG |
344 | self.word("type_ascribe!("); |
345 | self.ibox(0); | |
346 | self.print_expr(expr); | |
347 | ||
348 | self.word(","); | |
349 | self.space_if_not_bol(); | |
5099ac24 | 350 | self.print_type(ty); |
49aad941 FG |
351 | |
352 | self.end(); | |
353 | self.word(")"); | |
5099ac24 | 354 | } |
781aab86 | 355 | ast::ExprKind::Let(pat, scrutinee, _, _) => { |
5099ac24 FG |
356 | self.print_let(pat, scrutinee); |
357 | } | |
487cf647 FG |
358 | ast::ExprKind::If(test, blk, elseopt) => self.print_if(test, blk, elseopt.as_deref()), |
359 | ast::ExprKind::While(test, blk, opt_label) => { | |
5099ac24 FG |
360 | if let Some(label) = opt_label { |
361 | self.print_ident(label.ident); | |
362 | self.word_space(":"); | |
363 | } | |
364 | self.cbox(0); | |
365 | self.ibox(0); | |
366 | self.word_nbsp("while"); | |
367 | self.print_expr_as_cond(test); | |
368 | self.space(); | |
369 | self.print_block_with_attrs(blk, attrs); | |
370 | } | |
487cf647 | 371 | ast::ExprKind::ForLoop(pat, iter, blk, opt_label) => { |
5099ac24 FG |
372 | if let Some(label) = opt_label { |
373 | self.print_ident(label.ident); | |
374 | self.word_space(":"); | |
375 | } | |
376 | self.cbox(0); | |
377 | self.ibox(0); | |
378 | self.word_nbsp("for"); | |
379 | self.print_pat(pat); | |
380 | self.space(); | |
381 | self.word_space("in"); | |
382 | self.print_expr_as_cond(iter); | |
383 | self.space(); | |
384 | self.print_block_with_attrs(blk, attrs); | |
385 | } | |
487cf647 | 386 | ast::ExprKind::Loop(blk, opt_label, _) => { |
5099ac24 FG |
387 | if let Some(label) = opt_label { |
388 | self.print_ident(label.ident); | |
389 | self.word_space(":"); | |
390 | } | |
391 | self.cbox(0); | |
392 | self.ibox(0); | |
393 | self.word_nbsp("loop"); | |
394 | self.print_block_with_attrs(blk, attrs); | |
395 | } | |
487cf647 | 396 | ast::ExprKind::Match(expr, arms) => { |
5099ac24 FG |
397 | self.cbox(0); |
398 | self.ibox(0); | |
399 | self.word_nbsp("match"); | |
400 | self.print_expr_as_cond(expr); | |
401 | self.space(); | |
402 | self.bopen(); | |
403 | self.print_inner_attributes_no_trailing_hardbreak(attrs); | |
404 | for arm in arms { | |
405 | self.print_arm(arm); | |
406 | } | |
407 | let empty = attrs.is_empty() && arms.is_empty(); | |
408 | self.bclose(expr.span, empty); | |
409 | } | |
487cf647 FG |
410 | ast::ExprKind::Closure(box ast::Closure { |
411 | binder, | |
5099ac24 | 412 | capture_clause, |
9c376795 | 413 | constness, |
5099ac24 FG |
414 | asyncness, |
415 | movability, | |
487cf647 FG |
416 | fn_decl, |
417 | body, | |
418 | fn_decl_span: _, | |
419 | fn_arg_span: _, | |
420 | }) => { | |
064997fb | 421 | self.print_closure_binder(binder); |
9c376795 | 422 | self.print_constness(*constness); |
487cf647 FG |
423 | self.print_movability(*movability); |
424 | self.print_asyncness(*asyncness); | |
425 | self.print_capture_clause(*capture_clause); | |
5099ac24 | 426 | |
487cf647 | 427 | self.print_fn_params_and_ret(fn_decl, true); |
5099ac24 FG |
428 | self.space(); |
429 | self.print_expr(body); | |
430 | self.end(); // need to close a box | |
431 | ||
432 | // a box will be closed by print_expr, but we didn't want an overall | |
433 | // wrapper so we closed the corresponding opening. so create an | |
434 | // empty box to satisfy the close. | |
435 | self.ibox(0); | |
436 | } | |
487cf647 | 437 | ast::ExprKind::Block(blk, opt_label) => { |
5099ac24 FG |
438 | if let Some(label) = opt_label { |
439 | self.print_ident(label.ident); | |
440 | self.word_space(":"); | |
441 | } | |
442 | // containing cbox, will be closed by print-block at } | |
443 | self.cbox(0); | |
444 | // head-box, will be closed by print-block after { | |
445 | self.ibox(0); | |
446 | self.print_block_with_attrs(blk, attrs); | |
447 | } | |
353b0b11 | 448 | ast::ExprKind::Async(capture_clause, blk) => { |
5099ac24 | 449 | self.word_nbsp("async"); |
487cf647 | 450 | self.print_capture_clause(*capture_clause); |
5099ac24 FG |
451 | // cbox/ibox in analogy to the `ExprKind::Block` arm above |
452 | self.cbox(0); | |
453 | self.ibox(0); | |
454 | self.print_block_with_attrs(blk, attrs); | |
455 | } | |
49aad941 | 456 | ast::ExprKind::Await(expr, _) => { |
5099ac24 FG |
457 | self.print_expr_maybe_paren(expr, parser::PREC_POSTFIX); |
458 | self.word(".await"); | |
459 | } | |
487cf647 | 460 | ast::ExprKind::Assign(lhs, rhs, _) => { |
5099ac24 FG |
461 | let prec = AssocOp::Assign.precedence() as i8; |
462 | self.print_expr_maybe_paren(lhs, prec + 1); | |
463 | self.space(); | |
464 | self.word_space("="); | |
465 | self.print_expr_maybe_paren(rhs, prec); | |
466 | } | |
487cf647 | 467 | ast::ExprKind::AssignOp(op, lhs, rhs) => { |
5099ac24 FG |
468 | let prec = AssocOp::Assign.precedence() as i8; |
469 | self.print_expr_maybe_paren(lhs, prec + 1); | |
470 | self.space(); | |
471 | self.word(op.node.to_string()); | |
472 | self.word_space("="); | |
473 | self.print_expr_maybe_paren(rhs, prec); | |
474 | } | |
487cf647 | 475 | ast::ExprKind::Field(expr, ident) => { |
5099ac24 FG |
476 | self.print_expr_maybe_paren(expr, parser::PREC_POSTFIX); |
477 | self.word("."); | |
487cf647 | 478 | self.print_ident(*ident); |
5099ac24 | 479 | } |
add651ee | 480 | ast::ExprKind::Index(expr, index, _) => { |
5099ac24 FG |
481 | self.print_expr_maybe_paren(expr, parser::PREC_POSTFIX); |
482 | self.word("["); | |
483 | self.print_expr(index); | |
484 | self.word("]"); | |
485 | } | |
487cf647 | 486 | ast::ExprKind::Range(start, end, limits) => { |
9c376795 | 487 | // Special case for `Range`. `AssocOp` claims that `Range` has higher precedence |
5099ac24 FG |
488 | // than `Assign`, but `x .. x = x` gives a parse error instead of `x .. (x = x)`. |
489 | // Here we use a fake precedence value so that any child with lower precedence than | |
9c376795 | 490 | // a "normal" binop gets parenthesized. (`LOr` is the lowest-precedence binop.) |
5099ac24 | 491 | let fake_prec = AssocOp::LOr.precedence() as i8; |
487cf647 | 492 | if let Some(e) = start { |
5099ac24 FG |
493 | self.print_expr_maybe_paren(e, fake_prec); |
494 | } | |
487cf647 FG |
495 | match limits { |
496 | ast::RangeLimits::HalfOpen => self.word(".."), | |
497 | ast::RangeLimits::Closed => self.word("..="), | |
5099ac24 | 498 | } |
487cf647 | 499 | if let Some(e) = end { |
5099ac24 FG |
500 | self.print_expr_maybe_paren(e, fake_prec); |
501 | } | |
502 | } | |
503 | ast::ExprKind::Underscore => self.word("_"), | |
487cf647 FG |
504 | ast::ExprKind::Path(None, path) => self.print_path(path, true, 0), |
505 | ast::ExprKind::Path(Some(qself), path) => self.print_qpath(path, qself, true), | |
506 | ast::ExprKind::Break(opt_label, opt_expr) => { | |
5099ac24 FG |
507 | self.word("break"); |
508 | if let Some(label) = opt_label { | |
509 | self.space(); | |
510 | self.print_ident(label.ident); | |
511 | } | |
487cf647 | 512 | if let Some(expr) = opt_expr { |
5099ac24 FG |
513 | self.space(); |
514 | self.print_expr_maybe_paren(expr, parser::PREC_JUMP); | |
515 | } | |
516 | } | |
517 | ast::ExprKind::Continue(opt_label) => { | |
518 | self.word("continue"); | |
519 | if let Some(label) = opt_label { | |
520 | self.space(); | |
521 | self.print_ident(label.ident); | |
522 | } | |
523 | } | |
487cf647 | 524 | ast::ExprKind::Ret(result) => { |
5099ac24 | 525 | self.word("return"); |
487cf647 | 526 | if let Some(expr) = result { |
5099ac24 FG |
527 | self.word(" "); |
528 | self.print_expr_maybe_paren(expr, parser::PREC_JUMP); | |
529 | } | |
530 | } | |
487cf647 | 531 | ast::ExprKind::Yeet(result) => { |
04454e1e FG |
532 | self.word("do"); |
533 | self.word(" "); | |
534 | self.word("yeet"); | |
487cf647 | 535 | if let Some(expr) = result { |
04454e1e FG |
536 | self.word(" "); |
537 | self.print_expr_maybe_paren(expr, parser::PREC_JUMP); | |
538 | } | |
539 | } | |
fe692bf9 FG |
540 | ast::ExprKind::Become(result) => { |
541 | self.word("become"); | |
542 | self.word(" "); | |
543 | self.print_expr_maybe_paren(result, parser::PREC_JUMP); | |
544 | } | |
487cf647 | 545 | ast::ExprKind::InlineAsm(a) => { |
9ffffee4 | 546 | // FIXME: This should have its own syntax, distinct from a macro invocation. |
5099ac24 FG |
547 | self.word("asm!"); |
548 | self.print_inline_asm(a); | |
549 | } | |
9ffffee4 FG |
550 | ast::ExprKind::FormatArgs(fmt) => { |
551 | // FIXME: This should have its own syntax, distinct from a macro invocation. | |
552 | self.word("format_args!"); | |
553 | self.popen(); | |
554 | self.rbox(0, Inconsistent); | |
555 | self.word(reconstruct_format_args_template_string(&fmt.template)); | |
556 | for arg in fmt.arguments.all_args() { | |
557 | self.word_space(","); | |
558 | self.print_expr(&arg.expr); | |
559 | } | |
560 | self.end(); | |
561 | self.pclose(); | |
562 | } | |
49aad941 FG |
563 | ast::ExprKind::OffsetOf(container, fields) => { |
564 | self.word("builtin # offset_of"); | |
565 | self.popen(); | |
566 | self.rbox(0, Inconsistent); | |
567 | self.print_type(container); | |
568 | self.word(","); | |
569 | self.space(); | |
570 | ||
571 | if let Some((&first, rest)) = fields.split_first() { | |
572 | self.print_ident(first); | |
573 | ||
574 | for &field in rest { | |
575 | self.word("."); | |
576 | self.print_ident(field); | |
577 | } | |
578 | } | |
579 | self.pclose(); | |
580 | self.end(); | |
581 | } | |
487cf647 FG |
582 | ast::ExprKind::MacCall(m) => self.print_mac(m), |
583 | ast::ExprKind::Paren(e) => { | |
5099ac24 FG |
584 | self.popen(); |
585 | self.print_expr(e); | |
586 | self.pclose(); | |
587 | } | |
487cf647 | 588 | ast::ExprKind::Yield(e) => { |
5099ac24 FG |
589 | self.word("yield"); |
590 | ||
487cf647 | 591 | if let Some(expr) = e { |
5099ac24 FG |
592 | self.space(); |
593 | self.print_expr_maybe_paren(expr, parser::PREC_JUMP); | |
594 | } | |
595 | } | |
487cf647 | 596 | ast::ExprKind::Try(e) => { |
5099ac24 FG |
597 | self.print_expr_maybe_paren(e, parser::PREC_POSTFIX); |
598 | self.word("?") | |
599 | } | |
487cf647 | 600 | ast::ExprKind::TryBlock(blk) => { |
5099ac24 FG |
601 | self.cbox(0); |
602 | self.ibox(0); | |
603 | self.word_nbsp("try"); | |
604 | self.print_block_with_attrs(blk, attrs) | |
605 | } | |
606 | ast::ExprKind::Err => { | |
607 | self.popen(); | |
608 | self.word("/*ERROR*/"); | |
609 | self.pclose() | |
610 | } | |
611 | } | |
612 | self.ann.post(self, AnnNode::Expr(expr)); | |
613 | self.end(); | |
614 | } | |
615 | ||
616 | fn print_arm(&mut self, arm: &ast::Arm) { | |
617 | // Note, I have no idea why this check is necessary, but here it is. | |
618 | if arm.attrs.is_empty() { | |
619 | self.space(); | |
620 | } | |
621 | self.cbox(INDENT_UNIT); | |
622 | self.ibox(0); | |
623 | self.maybe_print_comment(arm.pat.span.lo()); | |
624 | self.print_outer_attributes(&arm.attrs); | |
625 | self.print_pat(&arm.pat); | |
626 | self.space(); | |
487cf647 | 627 | if let Some(e) = &arm.guard { |
5099ac24 FG |
628 | self.word_space("if"); |
629 | self.print_expr(e); | |
630 | self.space(); | |
631 | } | |
632 | self.word_space("=>"); | |
633 | ||
487cf647 FG |
634 | match &arm.body.kind { |
635 | ast::ExprKind::Block(blk, opt_label) => { | |
5099ac24 FG |
636 | if let Some(label) = opt_label { |
637 | self.print_ident(label.ident); | |
638 | self.word_space(":"); | |
639 | } | |
640 | ||
641 | // The block will close the pattern's ibox. | |
642 | self.print_block_unclosed_indent(blk); | |
643 | ||
644 | // If it is a user-provided unsafe block, print a comma after it. | |
645 | if let BlockCheckMode::Unsafe(ast::UserProvided) = blk.rules { | |
646 | self.word(","); | |
647 | } | |
648 | } | |
649 | _ => { | |
650 | self.end(); // Close the ibox for the pattern. | |
651 | self.print_expr(&arm.body); | |
652 | self.word(","); | |
653 | } | |
654 | } | |
655 | self.end(); // Close enclosing cbox. | |
656 | } | |
657 | ||
064997fb FG |
658 | fn print_closure_binder(&mut self, binder: &ast::ClosureBinder) { |
659 | match binder { | |
660 | ast::ClosureBinder::NotPresent => {} | |
661 | ast::ClosureBinder::For { generic_params, .. } => { | |
487cf647 | 662 | self.print_formal_generic_params(generic_params) |
064997fb FG |
663 | } |
664 | } | |
665 | } | |
666 | ||
5099ac24 FG |
667 | fn print_movability(&mut self, movability: ast::Movability) { |
668 | match movability { | |
669 | ast::Movability::Static => self.word_space("static"), | |
670 | ast::Movability::Movable => {} | |
671 | } | |
672 | } | |
673 | ||
674 | fn print_capture_clause(&mut self, capture_clause: ast::CaptureBy) { | |
675 | match capture_clause { | |
676 | ast::CaptureBy::Value => self.word_space("move"), | |
677 | ast::CaptureBy::Ref => {} | |
678 | } | |
679 | } | |
680 | } | |
9ffffee4 FG |
681 | |
682 | pub fn reconstruct_format_args_template_string(pieces: &[FormatArgsPiece]) -> String { | |
683 | let mut template = "\"".to_string(); | |
684 | for piece in pieces { | |
685 | match piece { | |
686 | FormatArgsPiece::Literal(s) => { | |
687 | for c in s.as_str().escape_debug() { | |
688 | template.push(c); | |
689 | if let '{' | '}' = c { | |
690 | template.push(c); | |
691 | } | |
692 | } | |
693 | } | |
694 | FormatArgsPiece::Placeholder(p) => { | |
695 | template.push('{'); | |
696 | let (Ok(n) | Err(n)) = p.argument.index; | |
697 | write!(template, "{n}").unwrap(); | |
698 | if p.format_options != Default::default() || p.format_trait != FormatTrait::Display | |
699 | { | |
add651ee | 700 | template.push(':'); |
9ffffee4 FG |
701 | } |
702 | if let Some(fill) = p.format_options.fill { | |
703 | template.push(fill); | |
704 | } | |
705 | match p.format_options.alignment { | |
add651ee FG |
706 | Some(FormatAlignment::Left) => template.push('<'), |
707 | Some(FormatAlignment::Right) => template.push('>'), | |
708 | Some(FormatAlignment::Center) => template.push('^'), | |
9ffffee4 FG |
709 | None => {} |
710 | } | |
711 | match p.format_options.sign { | |
712 | Some(FormatSign::Plus) => template.push('+'), | |
713 | Some(FormatSign::Minus) => template.push('-'), | |
714 | None => {} | |
715 | } | |
716 | if p.format_options.alternate { | |
717 | template.push('#'); | |
718 | } | |
719 | if p.format_options.zero_pad { | |
720 | template.push('0'); | |
721 | } | |
722 | if let Some(width) = &p.format_options.width { | |
723 | match width { | |
724 | FormatCount::Literal(n) => write!(template, "{n}").unwrap(), | |
725 | FormatCount::Argument(FormatArgPosition { | |
726 | index: Ok(n) | Err(n), .. | |
727 | }) => { | |
728 | write!(template, "{n}$").unwrap(); | |
729 | } | |
730 | } | |
731 | } | |
732 | if let Some(precision) = &p.format_options.precision { | |
733 | template.push('.'); | |
734 | match precision { | |
735 | FormatCount::Literal(n) => write!(template, "{n}").unwrap(), | |
736 | FormatCount::Argument(FormatArgPosition { | |
737 | index: Ok(n) | Err(n), .. | |
738 | }) => { | |
739 | write!(template, "{n}$").unwrap(); | |
740 | } | |
741 | } | |
742 | } | |
743 | match p.format_options.debug_hex { | |
744 | Some(FormatDebugHex::Lower) => template.push('x'), | |
745 | Some(FormatDebugHex::Upper) => template.push('X'), | |
746 | None => {} | |
747 | } | |
748 | template.push_str(match p.format_trait { | |
749 | FormatTrait::Display => "", | |
750 | FormatTrait::Debug => "?", | |
751 | FormatTrait::LowerExp => "e", | |
752 | FormatTrait::UpperExp => "E", | |
753 | FormatTrait::Octal => "o", | |
754 | FormatTrait::Pointer => "p", | |
755 | FormatTrait::Binary => "b", | |
756 | FormatTrait::LowerHex => "x", | |
757 | FormatTrait::UpperHex => "X", | |
758 | }); | |
759 | template.push('}'); | |
760 | } | |
761 | } | |
762 | } | |
763 | template.push('"'); | |
764 | template | |
765 | } |