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