prettyplease/
stmt.rs

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        #![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::RawAddr(_)
149        | Expr::Reference(_)
150        | Expr::Repeat(_)
151        | Expr::Struct(_)
152        | Expr::Try(_)
153        | Expr::TryBlock(_)
154        | Expr::Tuple(_)
155        | Expr::Unary(_)
156        | Expr::Unsafe(_)
157        | Expr::Verbatim(_)
158        | Expr::While(_) => false,
159
160        _ => false,
161    }
162}
163
164pub fn break_after(expr: &Expr) -> bool {
165    if let Expr::Group(group) = expr {
166        if let Expr::Verbatim(verbatim) = group.expr.as_ref() {
167            return !verbatim.is_empty();
168        }
169    }
170    true
171}
172
173fn remove_semi(expr: &Expr) -> bool {
174    match expr {
175        #![cfg_attr(all(test, exhaustive), deny(non_exhaustive_omitted_patterns))]
176        Expr::ForLoop(_) | Expr::While(_) => true,
177        Expr::Group(group) => remove_semi(&group.expr),
178        Expr::If(expr) => match &expr.else_branch {
179            Some((_else_token, else_branch)) => remove_semi(else_branch),
180            None => true,
181        },
182
183        Expr::Array(_)
184        | Expr::Assign(_)
185        | Expr::Async(_)
186        | Expr::Await(_)
187        | Expr::Binary(_)
188        | Expr::Block(_)
189        | Expr::Break(_)
190        | Expr::Call(_)
191        | Expr::Cast(_)
192        | Expr::Closure(_)
193        | Expr::Continue(_)
194        | Expr::Const(_)
195        | Expr::Field(_)
196        | Expr::Index(_)
197        | Expr::Infer(_)
198        | Expr::Let(_)
199        | Expr::Lit(_)
200        | Expr::Loop(_)
201        | Expr::Macro(_)
202        | Expr::Match(_)
203        | Expr::MethodCall(_)
204        | Expr::Paren(_)
205        | Expr::Path(_)
206        | Expr::Range(_)
207        | Expr::RawAddr(_)
208        | Expr::Reference(_)
209        | Expr::Repeat(_)
210        | Expr::Return(_)
211        | Expr::Struct(_)
212        | Expr::Try(_)
213        | Expr::TryBlock(_)
214        | Expr::Tuple(_)
215        | Expr::Unary(_)
216        | Expr::Unsafe(_)
217        | Expr::Verbatim(_)
218        | Expr::Yield(_) => false,
219
220        _ => false,
221    }
222}