prettyplease/
stmt.rs

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}