1use super::*;
2
3ast_struct! {
4 pub struct Block {
8 pub brace_token: token::Brace,
9 pub stmts: Vec<Stmt>,
11 }
12}
13
14ast_enum! {
15 pub enum Stmt {
19 Local(Local),
21
22 Item(Item),
24
25 Expr(Expr),
27
28 Semi(Expr, Token![;]),
30 }
31}
32
33ast_struct! {
34 pub struct Local {
38 pub attrs: Vec<Attribute>,
39 pub let_token: Token![let],
40 pub pat: Pat,
41 pub init: Option<(Token![=], Box<Expr>)>,
42 pub semi_token: Token![;],
43 }
44}
45
46#[cfg(feature = "parsing")]
47pub mod parsing {
48 use super::*;
49
50 use crate::parse::{Parse, ParseStream, Result};
51 use crate::punctuated::Punctuated;
52
53 impl Block {
54 pub fn parse_within(input: ParseStream) -> Result<Vec<Stmt>> {
107 let mut stmts = Vec::new();
108 loop {
109 while input.peek(Token![;]) {
110 input.parse::<Token![;]>()?;
111 }
112 if input.is_empty() {
113 break;
114 }
115 let s = parse_stmt(input, true)?;
116 let requires_semicolon = if let Stmt::Expr(s) = &s {
117 expr::requires_terminator(s)
118 } else {
119 false
120 };
121 stmts.push(s);
122 if input.is_empty() {
123 break;
124 } else if requires_semicolon {
125 return Err(input.error("unexpected token"));
126 }
127 }
128 Ok(stmts)
129 }
130 }
131
132 impl Parse for Block {
133 fn parse(input: ParseStream) -> Result<Self> {
134 let content;
135 Ok(Block {
136 brace_token: braced!(content in input),
137 stmts: content.call(Block::parse_within)?,
138 })
139 }
140 }
141
142 impl Parse for Stmt {
143 fn parse(input: ParseStream) -> Result<Self> {
144 parse_stmt(input, false)
145 }
146 }
147
148 fn parse_stmt(input: ParseStream, allow_nosemi: bool) -> Result<Stmt> {
149 let ahead = input.fork();
151 ahead.call(Attribute::parse_outer)?;
152
153 if {
154 let ahead = ahead.fork();
155 ahead.call(Path::parse_mod_style).is_ok()
158 && ahead.parse::<Token![!]>().is_ok()
159 && (ahead.peek(token::Brace) || ahead.peek(Ident))
160 } {
161 stmt_mac(input)
162 } else if ahead.peek(Token![let]) {
163 stmt_local(input).map(Stmt::Local)
164 } else if ahead.peek(Token![pub])
165 || ahead.peek(Token![crate]) && !ahead.peek2(Token![::])
166 || ahead.peek(Token![extern]) && !ahead.peek2(Token![::])
167 || ahead.peek(Token![use])
168 || ahead.peek(Token![static]) && (ahead.peek2(Token![mut]) || ahead.peek2(Ident))
169 || ahead.peek(Token![const])
170 || ahead.peek(Token![unsafe]) && !ahead.peek2(token::Brace)
171 || ahead.peek(Token![async])
172 && (ahead.peek2(Token![unsafe])
173 || ahead.peek2(Token![extern])
174 || ahead.peek2(Token![fn]))
175 || ahead.peek(Token![fn])
176 || ahead.peek(Token![mod])
177 || ahead.peek(Token![type])
178 || ahead.peek(item::parsing::existential) && ahead.peek2(Token![type])
179 || ahead.peek(Token![struct])
180 || ahead.peek(Token![enum])
181 || ahead.peek(Token![union]) && ahead.peek2(Ident)
182 || ahead.peek(Token![auto]) && ahead.peek2(Token![trait])
183 || ahead.peek(Token![trait])
184 || ahead.peek(Token![default])
185 && (ahead.peek2(Token![unsafe]) || ahead.peek2(Token![impl]))
186 || ahead.peek(Token![impl])
187 || ahead.peek(Token![macro])
188 {
189 input.parse().map(Stmt::Item)
190 } else {
191 stmt_expr(input, allow_nosemi)
192 }
193 }
194
195 fn stmt_mac(input: ParseStream) -> Result<Stmt> {
196 let attrs = input.call(Attribute::parse_outer)?;
197 let path = input.call(Path::parse_mod_style)?;
198 let bang_token: Token![!] = input.parse()?;
199 let ident: Option<Ident> = input.parse()?;
200 let (delimiter, tokens) = mac::parse_delimiter(input)?;
201 let semi_token: Option<Token![;]> = input.parse()?;
202
203 Ok(Stmt::Item(Item::Macro(ItemMacro {
204 attrs,
205 ident,
206 mac: Macro {
207 path,
208 bang_token,
209 delimiter,
210 tokens,
211 },
212 semi_token,
213 })))
214 }
215
216 fn stmt_local(input: ParseStream) -> Result<Local> {
217 Ok(Local {
218 attrs: input.call(Attribute::parse_outer)?,
219 let_token: input.parse()?,
220 pat: {
221 let leading_vert: Option<Token![|]> = input.parse()?;
222 let mut pat: Pat = input.parse()?;
223 if leading_vert.is_some()
224 || input.peek(Token![|]) && !input.peek(Token![||]) && !input.peek(Token![|=])
225 {
226 let mut cases = Punctuated::new();
227 cases.push_value(pat);
228 while input.peek(Token![|])
229 && !input.peek(Token![||])
230 && !input.peek(Token![|=])
231 {
232 let punct = input.parse()?;
233 cases.push_punct(punct);
234 let pat: Pat = input.parse()?;
235 cases.push_value(pat);
236 }
237 pat = Pat::Or(PatOr {
238 attrs: Vec::new(),
239 leading_vert,
240 cases,
241 });
242 }
243 if input.peek(Token![:]) {
244 let colon_token: Token![:] = input.parse()?;
245 let ty: Type = input.parse()?;
246 pat = Pat::Type(PatType {
247 attrs: Vec::new(),
248 pat: Box::new(pat),
249 colon_token,
250 ty: Box::new(ty),
251 });
252 }
253 pat
254 },
255 init: {
256 if input.peek(Token![=]) {
257 let eq_token: Token![=] = input.parse()?;
258 let init: Expr = input.parse()?;
259 Some((eq_token, Box::new(init)))
260 } else {
261 None
262 }
263 },
264 semi_token: input.parse()?,
265 })
266 }
267
268 fn stmt_expr(input: ParseStream, allow_nosemi: bool) -> Result<Stmt> {
269 let mut attrs = input.call(Attribute::parse_outer)?;
270 let mut e = expr::parsing::expr_early(input)?;
271
272 attrs.extend(e.replace_attrs(Vec::new()));
273 e.replace_attrs(attrs);
274
275 if input.peek(Token![;]) {
276 return Ok(Stmt::Semi(e, input.parse()?));
277 }
278
279 if allow_nosemi || !expr::requires_terminator(&e) {
280 Ok(Stmt::Expr(e))
281 } else {
282 Err(input.error("expected semicolon"))
283 }
284 }
285}
286
287#[cfg(feature = "printing")]
288mod printing {
289 use super::*;
290
291 use proc_macro2::TokenStream;
292 use quote::{ToTokens, TokenStreamExt};
293
294 impl ToTokens for Block {
295 fn to_tokens(&self, tokens: &mut TokenStream) {
296 self.brace_token.surround(tokens, |tokens| {
297 tokens.append_all(&self.stmts);
298 });
299 }
300 }
301
302 impl ToTokens for Stmt {
303 fn to_tokens(&self, tokens: &mut TokenStream) {
304 match self {
305 Stmt::Local(local) => local.to_tokens(tokens),
306 Stmt::Item(item) => item.to_tokens(tokens),
307 Stmt::Expr(expr) => expr.to_tokens(tokens),
308 Stmt::Semi(expr, semi) => {
309 expr.to_tokens(tokens);
310 semi.to_tokens(tokens);
311 }
312 }
313 }
314 }
315
316 impl ToTokens for Local {
317 fn to_tokens(&self, tokens: &mut TokenStream) {
318 expr::printing::outer_attrs_to_tokens(&self.attrs, tokens);
319 self.let_token.to_tokens(tokens);
320 self.pat.to_tokens(tokens);
321 if let Some((eq_token, init)) = &self.init {
322 eq_token.to_tokens(tokens);
323 init.to_tokens(tokens);
324 }
325 self.semi_token.to_tokens(tokens);
326 }
327 }
328}