1use crate::algorithm::Printer;
2use crate::classify;
3use crate::expr;
4use crate::fixup::FixupContext;
5use crate::heuristics;
6use crate::mac;
7use crate::INDENT;
8use syn::{BinOp, Expr, Stmt};
9
10impl Printer {
11 pub fn stmts(&mut self, stmts: &[Stmt]) {
12 let blanks = heuristics::stmt_blank_lines(stmts);
13 for (index, stmt) in stmts.iter().enumerate() {
14 if blanks[index] {
15 self.hardbreak();
16 }
17 let is_last = index + 1 == stmts.len();
18 self.stmt(stmt, is_last);
19 }
20 }
21
22 pub fn stmt(&mut self, stmt: &Stmt, is_last: bool) {
23 match stmt {
24 Stmt::Local(local) => {
25 self.outer_attrs(&local.attrs);
26 self.ibox(0);
27 self.word("let ");
28 self.pat(&local.pat);
29 if let Some(local_init) = &local.init {
30 self.word(" = ");
31 self.neverbreak();
32 self.subexpr(
33 &local_init.expr,
34 local_init.diverge.is_some()
35 && classify::expr_trailing_brace(&local_init.expr),
36 FixupContext::NONE,
37 );
38 if let Some((_else, diverge)) = &local_init.diverge {
39 self.space();
40 self.word("else ");
41 self.end();
42 self.neverbreak();
43 self.cbox(INDENT);
44 if let Some(expr) = expr::simple_block(diverge) {
45 self.small_block(&expr.block, &[]);
46 } else {
47 self.expr_as_small_block(diverge, INDENT);
48 }
49 }
50 }
51 self.end();
52 self.word(";");
53 self.hardbreak();
54 }
55 Stmt::Item(item) => self.item(item),
56 Stmt::Expr(expr, None) => {
57 if break_after(expr) {
58 self.ibox(0);
59 self.expr_beginning_of_line(expr, false, true, FixupContext::new_stmt());
60 if add_semi(expr) {
61 self.word(";");
62 }
63 self.end();
64 self.hardbreak();
65 } else {
66 self.expr_beginning_of_line(expr, false, true, FixupContext::new_stmt());
67 }
68 }
69 Stmt::Expr(expr, Some(_semi)) => {
70 if let Expr::Verbatim(tokens) = expr {
71 if tokens.is_empty() {
72 return;
73 }
74 }
75 self.ibox(0);
76 self.expr_beginning_of_line(expr, false, true, FixupContext::new_stmt());
77 if !remove_semi(expr) {
78 self.word(";");
79 }
80 self.end();
81 self.hardbreak();
82 }
83 Stmt::Macro(stmt) => {
84 self.outer_attrs(&stmt.attrs);
85 let semicolon = stmt.semi_token.is_some()
86 || !is_last && mac::requires_semi(&stmt.mac.delimiter);
87 self.mac(&stmt.mac, None, semicolon);
88 self.hardbreak();
89 }
90 }
91 }
92}
93
94pub fn add_semi(expr: &Expr) -> bool {
95 match expr {
96 #![cfg_attr(all(test, exhaustive), deny(non_exhaustive_omitted_patterns))]
97 Expr::Assign(_) | Expr::Break(_) | Expr::Continue(_) | Expr::Return(_) | Expr::Yield(_) => {
98 true
99 }
100 Expr::Binary(expr) =>
101 {
102 match expr.op {
103 #![cfg_attr(all(test, exhaustive), deny(non_exhaustive_omitted_patterns))]
104 BinOp::AddAssign(_)
105 | BinOp::SubAssign(_)
106 | BinOp::MulAssign(_)
107 | BinOp::DivAssign(_)
108 | BinOp::RemAssign(_)
109 | BinOp::BitXorAssign(_)
110 | BinOp::BitAndAssign(_)
111 | BinOp::BitOrAssign(_)
112 | BinOp::ShlAssign(_)
113 | BinOp::ShrAssign(_) => true,
114 BinOp::Add(_)
115 | BinOp::Sub(_)
116 | BinOp::Mul(_)
117 | BinOp::Div(_)
118 | BinOp::Rem(_)
119 | BinOp::And(_)
120 | BinOp::Or(_)
121 | BinOp::BitXor(_)
122 | BinOp::BitAnd(_)
123 | BinOp::BitOr(_)
124 | BinOp::Shl(_)
125 | BinOp::Shr(_)
126 | BinOp::Eq(_)
127 | BinOp::Lt(_)
128 | BinOp::Le(_)
129 | BinOp::Ne(_)
130 | BinOp::Ge(_)
131 | BinOp::Gt(_) => false,
132 _ => {
::core::panicking::panic_fmt(format_args!("not implemented: {0}",
format_args!("unknown BinOp")));
}unimplemented!("unknown BinOp"),
133 }
134 }
135 Expr::Group(group) => add_semi(&group.expr),
136
137 Expr::Array(_)
138 | Expr::Async(_)
139 | Expr::Await(_)
140 | Expr::Block(_)
141 | Expr::Call(_)
142 | Expr::Cast(_)
143 | Expr::Closure(_)
144 | Expr::Const(_)
145 | Expr::Field(_)
146 | Expr::ForLoop(_)
147 | Expr::If(_)
148 | Expr::Index(_)
149 | Expr::Infer(_)
150 | Expr::Let(_)
151 | Expr::Lit(_)
152 | Expr::Loop(_)
153 | Expr::Macro(_)
154 | Expr::Match(_)
155 | Expr::MethodCall(_)
156 | Expr::Paren(_)
157 | Expr::Path(_)
158 | Expr::Range(_)
159 | Expr::RawAddr(_)
160 | Expr::Reference(_)
161 | Expr::Repeat(_)
162 | Expr::Struct(_)
163 | Expr::Try(_)
164 | Expr::TryBlock(_)
165 | Expr::Tuple(_)
166 | Expr::Unary(_)
167 | Expr::Unsafe(_)
168 | Expr::Verbatim(_)
169 | Expr::While(_) => false,
170
171 _ => false,
172 }
173}
174
175pub fn break_after(expr: &Expr) -> bool {
176 if let Expr::Group(group) = expr {
177 if let Expr::Verbatim(verbatim) = group.expr.as_ref() {
178 return !verbatim.is_empty();
179 }
180 }
181 true
182}
183
184fn remove_semi(expr: &Expr) -> bool {
185 match expr {
186 #![cfg_attr(all(test, exhaustive), deny(non_exhaustive_omitted_patterns))]
187 Expr::ForLoop(_) | Expr::While(_) => true,
188 Expr::Group(group) => remove_semi(&group.expr),
189 Expr::If(expr) => match &expr.else_branch {
190 Some((_else_token, else_branch)) => remove_semi(else_branch),
191 None => true,
192 },
193
194 Expr::Array(_)
195 | Expr::Assign(_)
196 | Expr::Async(_)
197 | Expr::Await(_)
198 | Expr::Binary(_)
199 | Expr::Block(_)
200 | Expr::Break(_)
201 | Expr::Call(_)
202 | Expr::Cast(_)
203 | Expr::Closure(_)
204 | Expr::Continue(_)
205 | Expr::Const(_)
206 | Expr::Field(_)
207 | Expr::Index(_)
208 | Expr::Infer(_)
209 | Expr::Let(_)
210 | Expr::Lit(_)
211 | Expr::Loop(_)
212 | Expr::Macro(_)
213 | Expr::Match(_)
214 | Expr::MethodCall(_)
215 | Expr::Paren(_)
216 | Expr::Path(_)
217 | Expr::Range(_)
218 | Expr::RawAddr(_)
219 | Expr::Reference(_)
220 | Expr::Repeat(_)
221 | Expr::Return(_)
222 | Expr::Struct(_)
223 | Expr::Try(_)
224 | Expr::TryBlock(_)
225 | Expr::Tuple(_)
226 | Expr::Unary(_)
227 | Expr::Unsafe(_)
228 | Expr::Verbatim(_)
229 | Expr::Yield(_) => false,
230
231 _ => false,
232 }
233}