prettyplease/
stmt.rs

1use crate::algorithm::Printer;
2use crate::classify;
3use crate::expr;
4use crate::fixup::FixupContext;
5use crate::mac;
6use crate::INDENT;
7use syn::{BinOp, Expr, Stmt};
8
9impl Printer {
10    pub fn stmt(&mut self, stmt: &Stmt, is_last: bool) {
11        match stmt {
12            Stmt::Local(local) => {
13                self.outer_attrs(&local.attrs);
14                self.ibox(0);
15                self.word("let ");
16                self.pat(&local.pat);
17                if let Some(local_init) = &local.init {
18                    self.word(" = ");
19                    self.neverbreak();
20                    self.subexpr(
21                        &local_init.expr,
22                        local_init.diverge.is_some()
23                            && classify::expr_trailing_brace(&local_init.expr),
24                        FixupContext::NONE,
25                    );
26                    if let Some((_else, diverge)) = &local_init.diverge {
27                        self.space();
28                        self.word("else ");
29                        self.end();
30                        self.neverbreak();
31                        self.cbox(INDENT);
32                        if let Some(expr) = expr::simple_block(diverge) {
33                            self.small_block(&expr.block, &[]);
34                        } else {
35                            self.expr_as_small_block(diverge, INDENT);
36                        }
37                    }
38                }
39                self.end();
40                self.word(";");
41                self.hardbreak();
42            }
43            Stmt::Item(item) => self.item(item),
44            Stmt::Expr(expr, None) => {
45                if break_after(expr) {
46                    self.ibox(0);
47                    self.expr_beginning_of_line(expr, false, true, FixupContext::new_stmt());
48                    if add_semi(expr) {
49                        self.word(";");
50                    }
51                    self.end();
52                    self.hardbreak();
53                } else {
54                    self.expr_beginning_of_line(expr, false, true, FixupContext::new_stmt());
55                }
56            }
57            Stmt::Expr(expr, Some(_semi)) => {
58                if let Expr::Verbatim(tokens) = expr {
59                    if tokens.is_empty() {
60                        return;
61                    }
62                }
63                self.ibox(0);
64                self.expr_beginning_of_line(expr, false, true, FixupContext::new_stmt());
65                if !remove_semi(expr) {
66                    self.word(";");
67                }
68                self.end();
69                self.hardbreak();
70            }
71            Stmt::Macro(stmt) => {
72                self.outer_attrs(&stmt.attrs);
73                let semicolon = stmt.semi_token.is_some()
74                    || !is_last && mac::requires_semi(&stmt.mac.delimiter);
75                self.mac(&stmt.mac, None, semicolon);
76                self.hardbreak();
77            }
78        }
79    }
80}
81
82pub fn add_semi(expr: &Expr) -> bool {
83    match expr {
84        #![cfg_attr(all(test, exhaustive), deny(non_exhaustive_omitted_patterns))]
85        Expr::Assign(_) | Expr::Break(_) | Expr::Continue(_) | Expr::Return(_) | Expr::Yield(_) => {
86            true
87        }
88        Expr::Binary(expr) =>
89        {
90            match expr.op {
91                #![cfg_attr(all(test, exhaustive), deny(non_exhaustive_omitted_patterns))]
92                BinOp::AddAssign(_)
93                | BinOp::SubAssign(_)
94                | BinOp::MulAssign(_)
95                | BinOp::DivAssign(_)
96                | BinOp::RemAssign(_)
97                | BinOp::BitXorAssign(_)
98                | BinOp::BitAndAssign(_)
99                | BinOp::BitOrAssign(_)
100                | BinOp::ShlAssign(_)
101                | BinOp::ShrAssign(_) => true,
102                BinOp::Add(_)
103                | BinOp::Sub(_)
104                | BinOp::Mul(_)
105                | BinOp::Div(_)
106                | BinOp::Rem(_)
107                | BinOp::And(_)
108                | BinOp::Or(_)
109                | BinOp::BitXor(_)
110                | BinOp::BitAnd(_)
111                | BinOp::BitOr(_)
112                | BinOp::Shl(_)
113                | BinOp::Shr(_)
114                | BinOp::Eq(_)
115                | BinOp::Lt(_)
116                | BinOp::Le(_)
117                | BinOp::Ne(_)
118                | BinOp::Ge(_)
119                | BinOp::Gt(_) => false,
120                _ => unimplemented!("unknown BinOp"),
121            }
122        }
123        Expr::Group(group) => add_semi(&group.expr),
124
125        Expr::Array(_)
126        | Expr::Async(_)
127        | Expr::Await(_)
128        | Expr::Block(_)
129        | Expr::Call(_)
130        | Expr::Cast(_)
131        | Expr::Closure(_)
132        | Expr::Const(_)
133        | Expr::Field(_)
134        | Expr::ForLoop(_)
135        | Expr::If(_)
136        | Expr::Index(_)
137        | Expr::Infer(_)
138        | Expr::Let(_)
139        | Expr::Lit(_)
140        | Expr::Loop(_)
141        | Expr::Macro(_)
142        | Expr::Match(_)
143        | Expr::MethodCall(_)
144        | Expr::Paren(_)
145        | Expr::Path(_)
146        | Expr::Range(_)
147        | Expr::RawAddr(_)
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
163pub 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
172fn 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::RawAddr(_)
207        | Expr::Reference(_)
208        | Expr::Repeat(_)
209        | Expr::Return(_)
210        | Expr::Struct(_)
211        | Expr::Try(_)
212        | Expr::TryBlock(_)
213        | Expr::Tuple(_)
214        | Expr::Unary(_)
215        | Expr::Unsafe(_)
216        | Expr::Verbatim(_)
217        | Expr::Yield(_) => false,
218
219        _ => false,
220    }
221}