1 use crate::algorithm::Printer;
2 use crate::INDENT;
3 use syn::{BinOp, Expr, Stmt};
4 
5 impl Printer {
stmt(&mut self, stmt: &Stmt)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 
add_semi(expr: &Expr) -> bool83 pub fn add_semi(expr: &Expr) -> bool {
84     match expr {
85         #![cfg_attr(all(test, exhaustive), deny(non_exhaustive_omitted_patterns))]
86         Expr::Assign(_) | Expr::Break(_) | Expr::Continue(_) | Expr::Return(_) | Expr::Yield(_) => {
87             true
88         }
89         Expr::Binary(expr) =>
90         {
91             match expr.op {
92                 #![cfg_attr(all(test, exhaustive), deny(non_exhaustive_omitted_patterns))]
93                 BinOp::AddAssign(_)
94                 | BinOp::SubAssign(_)
95                 | BinOp::MulAssign(_)
96                 | BinOp::DivAssign(_)
97                 | BinOp::RemAssign(_)
98                 | BinOp::BitXorAssign(_)
99                 | BinOp::BitAndAssign(_)
100                 | BinOp::BitOrAssign(_)
101                 | BinOp::ShlAssign(_)
102                 | BinOp::ShrAssign(_) => true,
103                 BinOp::Add(_)
104                 | BinOp::Sub(_)
105                 | BinOp::Mul(_)
106                 | BinOp::Div(_)
107                 | BinOp::Rem(_)
108                 | BinOp::And(_)
109                 | BinOp::Or(_)
110                 | BinOp::BitXor(_)
111                 | BinOp::BitAnd(_)
112                 | BinOp::BitOr(_)
113                 | BinOp::Shl(_)
114                 | BinOp::Shr(_)
115                 | BinOp::Eq(_)
116                 | BinOp::Lt(_)
117                 | BinOp::Le(_)
118                 | BinOp::Ne(_)
119                 | BinOp::Ge(_)
120                 | BinOp::Gt(_) => false,
121                 _ => unimplemented!("unknown BinOp"),
122             }
123         }
124         Expr::Group(group) => add_semi(&group.expr),
125 
126         Expr::Array(_)
127         | Expr::Async(_)
128         | Expr::Await(_)
129         | Expr::Block(_)
130         | Expr::Call(_)
131         | Expr::Cast(_)
132         | Expr::Closure(_)
133         | Expr::Const(_)
134         | Expr::Field(_)
135         | Expr::ForLoop(_)
136         | Expr::If(_)
137         | Expr::Index(_)
138         | Expr::Infer(_)
139         | Expr::Let(_)
140         | Expr::Lit(_)
141         | Expr::Loop(_)
142         | Expr::Macro(_)
143         | Expr::Match(_)
144         | Expr::MethodCall(_)
145         | Expr::Paren(_)
146         | Expr::Path(_)
147         | Expr::Range(_)
148         | Expr::Reference(_)
149         | Expr::Repeat(_)
150         | Expr::Struct(_)
151         | Expr::Try(_)
152         | Expr::TryBlock(_)
153         | Expr::Tuple(_)
154         | Expr::Unary(_)
155         | Expr::Unsafe(_)
156         | Expr::Verbatim(_)
157         | Expr::While(_) => false,
158 
159         _ => false,
160     }
161 }
162 
break_after(expr: &Expr) -> bool163 pub fn break_after(expr: &Expr) -> bool {
164     if let Expr::Group(group) = expr {
165         if let Expr::Verbatim(verbatim) = group.expr.as_ref() {
166             return !verbatim.is_empty();
167         }
168     }
169     true
170 }
171 
remove_semi(expr: &Expr) -> bool172 fn remove_semi(expr: &Expr) -> bool {
173     match expr {
174         #![cfg_attr(all(test, exhaustive), deny(non_exhaustive_omitted_patterns))]
175         Expr::ForLoop(_) | Expr::While(_) => true,
176         Expr::Group(group) => remove_semi(&group.expr),
177         Expr::If(expr) => match &expr.else_branch {
178             Some((_else_token, else_branch)) => remove_semi(else_branch),
179             None => true,
180         },
181 
182         Expr::Array(_)
183         | Expr::Assign(_)
184         | Expr::Async(_)
185         | Expr::Await(_)
186         | Expr::Binary(_)
187         | Expr::Block(_)
188         | Expr::Break(_)
189         | Expr::Call(_)
190         | Expr::Cast(_)
191         | Expr::Closure(_)
192         | Expr::Continue(_)
193         | Expr::Const(_)
194         | Expr::Field(_)
195         | Expr::Index(_)
196         | Expr::Infer(_)
197         | Expr::Let(_)
198         | Expr::Lit(_)
199         | Expr::Loop(_)
200         | Expr::Macro(_)
201         | Expr::Match(_)
202         | Expr::MethodCall(_)
203         | Expr::Paren(_)
204         | Expr::Path(_)
205         | Expr::Range(_)
206         | Expr::Reference(_)
207         | Expr::Repeat(_)
208         | Expr::Return(_)
209         | Expr::Struct(_)
210         | Expr::Try(_)
211         | Expr::TryBlock(_)
212         | Expr::Tuple(_)
213         | Expr::Unary(_)
214         | Expr::Unsafe(_)
215         | Expr::Verbatim(_)
216         | Expr::Yield(_) => false,
217 
218         _ => false,
219     }
220 }
221