Skip to main content

a9_prettyplease/
stmt.rs

1use crate::algorithm::Printer;
2use crate::classify;
3use crate::expr;
4use crate::fixup::FixupContext;
5use crate::heuristics;
6use crate::mac;
7use crate::INDENT;
8use syn::{BinOp, Expr, Stmt};
9
10impl Printer {
11    pub fn stmts(&mut self, stmts: &[Stmt]) {
12        let blanks = heuristics::stmt_blank_lines(stmts);
13        for (index, stmt) in stmts.iter().enumerate() {
14            if blanks[index] {
15                self.hardbreak();
16            }
17            let is_last = index + 1 == stmts.len();
18            self.stmt(stmt, is_last);
19        }
20    }
21
22    pub fn stmt(&mut self, stmt: &Stmt, is_last: bool) {
23        match stmt {
24            Stmt::Local(local) => {
25                self.outer_attrs(&local.attrs);
26                self.ibox(0);
27                self.word("let ");
28                self.pat(&local.pat);
29                if let Some(local_init) = &local.init {
30                    self.word(" = ");
31                    self.neverbreak();
32                    self.subexpr(
33                        &local_init.expr,
34                        local_init.diverge.is_some()
35                            && classify::expr_trailing_brace(&local_init.expr),
36                        FixupContext::NONE,
37                    );
38                    if let Some((_else, diverge)) = &local_init.diverge {
39                        self.space();
40                        self.word("else ");
41                        self.end();
42                        self.neverbreak();
43                        self.cbox(INDENT);
44                        if let Some(expr) = expr::simple_block(diverge) {
45                            self.small_block(&expr.block, &[]);
46                        } else {
47                            self.expr_as_small_block(diverge, INDENT);
48                        }
49                    }
50                }
51                self.end();
52                self.word(";");
53                self.hardbreak();
54            }
55            Stmt::Item(item) => self.item(item),
56            Stmt::Expr(expr, None) => {
57                if break_after(expr) {
58                    self.ibox(0);
59                    self.expr_beginning_of_line(expr, false, true, FixupContext::new_stmt());
60                    if add_semi(expr) {
61                        self.word(";");
62                    }
63                    self.end();
64                    self.hardbreak();
65                } else {
66                    self.expr_beginning_of_line(expr, false, true, FixupContext::new_stmt());
67                }
68            }
69            Stmt::Expr(expr, Some(_semi)) => {
70                if let Expr::Verbatim(tokens) = expr {
71                    if tokens.is_empty() {
72                        return;
73                    }
74                }
75                self.ibox(0);
76                self.expr_beginning_of_line(expr, false, true, FixupContext::new_stmt());
77                if !remove_semi(expr) {
78                    self.word(";");
79                }
80                self.end();
81                self.hardbreak();
82            }
83            Stmt::Macro(stmt) => {
84                self.outer_attrs(&stmt.attrs);
85                let semicolon = stmt.semi_token.is_some()
86                    || !is_last && mac::requires_semi(&stmt.mac.delimiter);
87                self.mac(&stmt.mac, None, semicolon);
88                self.hardbreak();
89            }
90        }
91    }
92}
93
94pub fn add_semi(expr: &Expr) -> bool {
95    match expr {
96        #![cfg_attr(all(test, exhaustive), deny(non_exhaustive_omitted_patterns))]
97        Expr::Assign(_) | Expr::Break(_) | Expr::Continue(_) | Expr::Return(_) | Expr::Yield(_) => {
98            true
99        }
100        Expr::Binary(expr) =>
101        {
102            match expr.op {
103                #![cfg_attr(all(test, exhaustive), deny(non_exhaustive_omitted_patterns))]
104                BinOp::AddAssign(_)
105                | BinOp::SubAssign(_)
106                | BinOp::MulAssign(_)
107                | BinOp::DivAssign(_)
108                | BinOp::RemAssign(_)
109                | BinOp::BitXorAssign(_)
110                | BinOp::BitAndAssign(_)
111                | BinOp::BitOrAssign(_)
112                | BinOp::ShlAssign(_)
113                | BinOp::ShrAssign(_) => true,
114                BinOp::Add(_)
115                | BinOp::Sub(_)
116                | BinOp::Mul(_)
117                | BinOp::Div(_)
118                | BinOp::Rem(_)
119                | BinOp::And(_)
120                | BinOp::Or(_)
121                | BinOp::BitXor(_)
122                | BinOp::BitAnd(_)
123                | BinOp::BitOr(_)
124                | BinOp::Shl(_)
125                | BinOp::Shr(_)
126                | BinOp::Eq(_)
127                | BinOp::Lt(_)
128                | BinOp::Le(_)
129                | BinOp::Ne(_)
130                | BinOp::Ge(_)
131                | BinOp::Gt(_) => false,
132                _ => {
    ::core::panicking::panic_fmt(format_args!("not implemented: {0}",
            format_args!("unknown BinOp")));
}unimplemented!("unknown BinOp"),
133            }
134        }
135        Expr::Group(group) => add_semi(&group.expr),
136
137        Expr::Array(_)
138        | Expr::Async(_)
139        | Expr::Await(_)
140        | Expr::Block(_)
141        | Expr::Call(_)
142        | Expr::Cast(_)
143        | Expr::Closure(_)
144        | Expr::Const(_)
145        | Expr::Field(_)
146        | Expr::ForLoop(_)
147        | Expr::If(_)
148        | Expr::Index(_)
149        | Expr::Infer(_)
150        | Expr::Let(_)
151        | Expr::Lit(_)
152        | Expr::Loop(_)
153        | Expr::Macro(_)
154        | Expr::Match(_)
155        | Expr::MethodCall(_)
156        | Expr::Paren(_)
157        | Expr::Path(_)
158        | Expr::Range(_)
159        | Expr::RawAddr(_)
160        | Expr::Reference(_)
161        | Expr::Repeat(_)
162        | Expr::Struct(_)
163        | Expr::Try(_)
164        | Expr::TryBlock(_)
165        | Expr::Tuple(_)
166        | Expr::Unary(_)
167        | Expr::Unsafe(_)
168        | Expr::Verbatim(_)
169        | Expr::While(_) => false,
170
171        _ => false,
172    }
173}
174
175pub fn break_after(expr: &Expr) -> bool {
176    if let Expr::Group(group) = expr {
177        if let Expr::Verbatim(verbatim) = group.expr.as_ref() {
178            return !verbatim.is_empty();
179        }
180    }
181    true
182}
183
184fn remove_semi(expr: &Expr) -> bool {
185    match expr {
186        #![cfg_attr(all(test, exhaustive), deny(non_exhaustive_omitted_patterns))]
187        Expr::ForLoop(_) | Expr::While(_) => true,
188        Expr::Group(group) => remove_semi(&group.expr),
189        Expr::If(expr) => match &expr.else_branch {
190            Some((_else_token, else_branch)) => remove_semi(else_branch),
191            None => true,
192        },
193
194        Expr::Array(_)
195        | Expr::Assign(_)
196        | Expr::Async(_)
197        | Expr::Await(_)
198        | Expr::Binary(_)
199        | Expr::Block(_)
200        | Expr::Break(_)
201        | Expr::Call(_)
202        | Expr::Cast(_)
203        | Expr::Closure(_)
204        | Expr::Continue(_)
205        | Expr::Const(_)
206        | Expr::Field(_)
207        | Expr::Index(_)
208        | Expr::Infer(_)
209        | Expr::Let(_)
210        | Expr::Lit(_)
211        | Expr::Loop(_)
212        | Expr::Macro(_)
213        | Expr::Match(_)
214        | Expr::MethodCall(_)
215        | Expr::Paren(_)
216        | Expr::Path(_)
217        | Expr::Range(_)
218        | Expr::RawAddr(_)
219        | Expr::Reference(_)
220        | Expr::Repeat(_)
221        | Expr::Return(_)
222        | Expr::Struct(_)
223        | Expr::Try(_)
224        | Expr::TryBlock(_)
225        | Expr::Tuple(_)
226        | Expr::Unary(_)
227        | Expr::Unsafe(_)
228        | Expr::Verbatim(_)
229        | Expr::Yield(_) => false,
230
231        _ => false,
232    }
233}