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