• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 use crate::algorithm::Printer;
2 use crate::fixup::FixupContext;
3 use crate::iter::IterDelimited;
4 use crate::path::PathKind;
5 use crate::INDENT;
6 use proc_macro2::TokenStream;
7 use syn::{
8     FieldPat, Pat, PatIdent, PatOr, PatParen, PatReference, PatRest, PatSlice, PatStruct, PatTuple,
9     PatTupleStruct, PatType, PatWild,
10 };
11 
12 impl Printer {
pat(&mut self, pat: &Pat)13     pub fn pat(&mut self, pat: &Pat) {
14         match pat {
15             #![cfg_attr(all(test, exhaustive), deny(non_exhaustive_omitted_patterns))]
16             Pat::Const(pat) => self.expr_const(pat),
17             Pat::Ident(pat) => self.pat_ident(pat),
18             Pat::Lit(pat) => self.expr_lit(pat),
19             Pat::Macro(pat) => self.expr_macro(pat),
20             Pat::Or(pat) => self.pat_or(pat),
21             Pat::Paren(pat) => self.pat_paren(pat),
22             Pat::Path(pat) => self.expr_path(pat),
23             Pat::Range(pat) => self.expr_range(pat, FixupContext::NONE),
24             Pat::Reference(pat) => self.pat_reference(pat),
25             Pat::Rest(pat) => self.pat_rest(pat),
26             Pat::Slice(pat) => self.pat_slice(pat),
27             Pat::Struct(pat) => self.pat_struct(pat),
28             Pat::Tuple(pat) => self.pat_tuple(pat),
29             Pat::TupleStruct(pat) => self.pat_tuple_struct(pat),
30             Pat::Type(pat) => self.pat_type(pat),
31             Pat::Verbatim(pat) => self.pat_verbatim(pat),
32             Pat::Wild(pat) => self.pat_wild(pat),
33             _ => unimplemented!("unknown Pat"),
34         }
35     }
36 
pat_ident(&mut self, pat: &PatIdent)37     fn pat_ident(&mut self, pat: &PatIdent) {
38         self.outer_attrs(&pat.attrs);
39         if pat.by_ref.is_some() {
40             self.word("ref ");
41         }
42         if pat.mutability.is_some() {
43             self.word("mut ");
44         }
45         self.ident(&pat.ident);
46         if let Some((_at_token, subpat)) = &pat.subpat {
47             self.word(" @ ");
48             self.pat(subpat);
49         }
50     }
51 
pat_or(&mut self, pat: &PatOr)52     fn pat_or(&mut self, pat: &PatOr) {
53         self.outer_attrs(&pat.attrs);
54         let mut consistent_break = false;
55         for case in &pat.cases {
56             match case {
57                 Pat::Lit(_) | Pat::Wild(_) => {}
58                 _ => {
59                     consistent_break = true;
60                     break;
61                 }
62             }
63         }
64         if consistent_break {
65             self.cbox(0);
66         } else {
67             self.ibox(0);
68         }
69         for case in pat.cases.iter().delimited() {
70             if !case.is_first {
71                 self.space();
72                 self.word("| ");
73             }
74             self.pat(&case);
75         }
76         self.end();
77     }
78 
pat_paren(&mut self, pat: &PatParen)79     fn pat_paren(&mut self, pat: &PatParen) {
80         self.outer_attrs(&pat.attrs);
81         self.word("(");
82         self.pat(&pat.pat);
83         self.word(")");
84     }
85 
pat_reference(&mut self, pat: &PatReference)86     fn pat_reference(&mut self, pat: &PatReference) {
87         self.outer_attrs(&pat.attrs);
88         self.word("&");
89         if pat.mutability.is_some() {
90             self.word("mut ");
91         }
92         self.pat(&pat.pat);
93     }
94 
pat_rest(&mut self, pat: &PatRest)95     fn pat_rest(&mut self, pat: &PatRest) {
96         self.outer_attrs(&pat.attrs);
97         self.word("..");
98     }
99 
pat_slice(&mut self, pat: &PatSlice)100     fn pat_slice(&mut self, pat: &PatSlice) {
101         self.outer_attrs(&pat.attrs);
102         self.word("[");
103         for elem in pat.elems.iter().delimited() {
104             self.pat(&elem);
105             self.trailing_comma(elem.is_last);
106         }
107         self.word("]");
108     }
109 
pat_struct(&mut self, pat: &PatStruct)110     fn pat_struct(&mut self, pat: &PatStruct) {
111         self.outer_attrs(&pat.attrs);
112         self.cbox(INDENT);
113         self.path(&pat.path, PathKind::Expr);
114         self.word(" {");
115         self.space_if_nonempty();
116         for field in pat.fields.iter().delimited() {
117             self.field_pat(&field);
118             self.trailing_comma_or_space(field.is_last && pat.rest.is_none());
119         }
120         if let Some(rest) = &pat.rest {
121             self.pat_rest(rest);
122             self.space();
123         }
124         self.offset(-INDENT);
125         self.end();
126         self.word("}");
127     }
128 
pat_tuple(&mut self, pat: &PatTuple)129     fn pat_tuple(&mut self, pat: &PatTuple) {
130         self.outer_attrs(&pat.attrs);
131         self.word("(");
132         self.cbox(INDENT);
133         self.zerobreak();
134         for elem in pat.elems.iter().delimited() {
135             self.pat(&elem);
136             if pat.elems.len() == 1 {
137                 if pat.elems.trailing_punct() {
138                     self.word(",");
139                 }
140                 self.zerobreak();
141             } else {
142                 self.trailing_comma(elem.is_last);
143             }
144         }
145         self.offset(-INDENT);
146         self.end();
147         self.word(")");
148     }
149 
pat_tuple_struct(&mut self, pat: &PatTupleStruct)150     fn pat_tuple_struct(&mut self, pat: &PatTupleStruct) {
151         self.outer_attrs(&pat.attrs);
152         self.path(&pat.path, PathKind::Expr);
153         self.word("(");
154         self.cbox(INDENT);
155         self.zerobreak();
156         for elem in pat.elems.iter().delimited() {
157             self.pat(&elem);
158             self.trailing_comma(elem.is_last);
159         }
160         self.offset(-INDENT);
161         self.end();
162         self.word(")");
163     }
164 
pat_type(&mut self, pat: &PatType)165     pub fn pat_type(&mut self, pat: &PatType) {
166         self.outer_attrs(&pat.attrs);
167         self.pat(&pat.pat);
168         self.word(": ");
169         self.ty(&pat.ty);
170     }
171 
172     #[cfg(not(feature = "verbatim"))]
pat_verbatim(&mut self, pat: &TokenStream)173     fn pat_verbatim(&mut self, pat: &TokenStream) {
174         unimplemented!("Pat::Verbatim `{}`", pat);
175     }
176 
177     #[cfg(feature = "verbatim")]
pat_verbatim(&mut self, tokens: &TokenStream)178     fn pat_verbatim(&mut self, tokens: &TokenStream) {
179         use syn::parse::{Parse, ParseStream, Result};
180         use syn::{braced, Attribute, Block, Token};
181 
182         enum PatVerbatim {
183             Ellipsis,
184             Box(Pat),
185             Const(PatConst),
186         }
187 
188         struct PatConst {
189             attrs: Vec<Attribute>,
190             block: Block,
191         }
192 
193         impl Parse for PatVerbatim {
194             fn parse(input: ParseStream) -> Result<Self> {
195                 let lookahead = input.lookahead1();
196                 if lookahead.peek(Token![box]) {
197                     input.parse::<Token![box]>()?;
198                     let inner = Pat::parse_single(input)?;
199                     Ok(PatVerbatim::Box(inner))
200                 } else if lookahead.peek(Token![const]) {
201                     input.parse::<Token![const]>()?;
202                     let content;
203                     let brace_token = braced!(content in input);
204                     let attrs = content.call(Attribute::parse_inner)?;
205                     let stmts = content.call(Block::parse_within)?;
206                     Ok(PatVerbatim::Const(PatConst {
207                         attrs,
208                         block: Block { brace_token, stmts },
209                     }))
210                 } else if lookahead.peek(Token![...]) {
211                     input.parse::<Token![...]>()?;
212                     Ok(PatVerbatim::Ellipsis)
213                 } else {
214                     Err(lookahead.error())
215                 }
216             }
217         }
218 
219         let pat: PatVerbatim = match syn::parse2(tokens.clone()) {
220             Ok(pat) => pat,
221             Err(_) => unimplemented!("Pat::Verbatim `{}`", tokens),
222         };
223 
224         match pat {
225             PatVerbatim::Ellipsis => {
226                 self.word("...");
227             }
228             PatVerbatim::Box(pat) => {
229                 self.word("box ");
230                 self.pat(&pat);
231             }
232             PatVerbatim::Const(pat) => {
233                 self.word("const ");
234                 self.cbox(INDENT);
235                 self.small_block(&pat.block, &pat.attrs);
236                 self.end();
237             }
238         }
239     }
240 
pat_wild(&mut self, pat: &PatWild)241     fn pat_wild(&mut self, pat: &PatWild) {
242         self.outer_attrs(&pat.attrs);
243         self.word("_");
244     }
245 
field_pat(&mut self, field_pat: &FieldPat)246     fn field_pat(&mut self, field_pat: &FieldPat) {
247         self.outer_attrs(&field_pat.attrs);
248         if field_pat.colon_token.is_some() {
249             self.member(&field_pat.member);
250             self.word(": ");
251         }
252         self.pat(&field_pat.pat);
253     }
254 }
255