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