Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/rust/syn/stmt.rs
38271 views
1
// SPDX-License-Identifier: Apache-2.0 OR MIT
2
3
use crate::attr::Attribute;
4
use crate::expr::Expr;
5
use crate::item::Item;
6
use crate::mac::Macro;
7
use crate::pat::Pat;
8
use crate::token;
9
10
ast_struct! {
11
/// A braced block containing Rust statements.
12
#[cfg_attr(docsrs, doc(cfg(feature = "full")))]
13
pub struct Block {
14
pub brace_token: token::Brace,
15
/// Statements in a block
16
pub stmts: Vec<Stmt>,
17
}
18
}
19
20
ast_enum! {
21
/// A statement, usually ending in a semicolon.
22
#[cfg_attr(docsrs, doc(cfg(feature = "full")))]
23
pub enum Stmt {
24
/// A local (let) binding.
25
Local(Local),
26
27
/// An item definition.
28
Item(Item),
29
30
/// Expression, with or without trailing semicolon.
31
Expr(Expr, Option<Token![;]>),
32
33
/// A macro invocation in statement position.
34
///
35
/// Syntactically it's ambiguous which other kind of statement this
36
/// macro would expand to. It can be any of local variable (`let`),
37
/// item, or expression.
38
Macro(StmtMacro),
39
}
40
}
41
42
ast_struct! {
43
/// A local `let` binding: `let x: u64 = s.parse()?;`.
44
#[cfg_attr(docsrs, doc(cfg(feature = "full")))]
45
pub struct Local {
46
pub attrs: Vec<Attribute>,
47
pub let_token: Token![let],
48
pub pat: Pat,
49
pub init: Option<LocalInit>,
50
pub semi_token: Token![;],
51
}
52
}
53
54
ast_struct! {
55
/// The expression assigned in a local `let` binding, including optional
56
/// diverging `else` block.
57
///
58
/// `LocalInit` represents `= s.parse()?` in `let x: u64 = s.parse()?` and
59
/// `= r else { return }` in `let Ok(x) = r else { return }`.
60
#[cfg_attr(docsrs, doc(cfg(feature = "full")))]
61
pub struct LocalInit {
62
pub eq_token: Token![=],
63
pub expr: Box<Expr>,
64
pub diverge: Option<(Token![else], Box<Expr>)>,
65
}
66
}
67
68
ast_struct! {
69
/// A macro invocation in statement position.
70
///
71
/// Syntactically it's ambiguous which other kind of statement this macro
72
/// would expand to. It can be any of local variable (`let`), item, or
73
/// expression.
74
#[cfg_attr(docsrs, doc(cfg(feature = "full")))]
75
pub struct StmtMacro {
76
pub attrs: Vec<Attribute>,
77
pub mac: Macro,
78
pub semi_token: Option<Token![;]>,
79
}
80
}
81
82
#[cfg(feature = "parsing")]
83
pub(crate) mod parsing {
84
use crate::attr::Attribute;
85
use crate::classify;
86
use crate::error::Result;
87
use crate::expr::{Expr, ExprBlock, ExprMacro};
88
use crate::ident::Ident;
89
use crate::item;
90
use crate::mac::{self, Macro};
91
use crate::parse::discouraged::Speculative as _;
92
use crate::parse::{Parse, ParseStream};
93
use crate::pat::{Pat, PatType};
94
use crate::path::Path;
95
use crate::stmt::{Block, Local, LocalInit, Stmt, StmtMacro};
96
use crate::token;
97
use crate::ty::Type;
98
use proc_macro2::TokenStream;
99
100
struct AllowNoSemi(bool);
101
102
impl Block {
103
/// Parse the body of a block as zero or more statements, possibly
104
/// including one trailing expression.
105
///
106
/// # Example
107
///
108
/// ```
109
/// use syn::{braced, token, Attribute, Block, Ident, Result, Stmt, Token};
110
/// use syn::parse::{Parse, ParseStream};
111
///
112
/// // Parse a function with no generics or parameter list.
113
/// //
114
/// // fn playground {
115
/// // let mut x = 1;
116
/// // x += 1;
117
/// // println!("{}", x);
118
/// // }
119
/// struct MiniFunction {
120
/// attrs: Vec<Attribute>,
121
/// fn_token: Token![fn],
122
/// name: Ident,
123
/// brace_token: token::Brace,
124
/// stmts: Vec<Stmt>,
125
/// }
126
///
127
/// impl Parse for MiniFunction {
128
/// fn parse(input: ParseStream) -> Result<Self> {
129
/// let outer_attrs = input.call(Attribute::parse_outer)?;
130
/// let fn_token: Token![fn] = input.parse()?;
131
/// let name: Ident = input.parse()?;
132
///
133
/// let content;
134
/// let brace_token = braced!(content in input);
135
/// let inner_attrs = content.call(Attribute::parse_inner)?;
136
/// let stmts = content.call(Block::parse_within)?;
137
///
138
/// Ok(MiniFunction {
139
/// attrs: {
140
/// let mut attrs = outer_attrs;
141
/// attrs.extend(inner_attrs);
142
/// attrs
143
/// },
144
/// fn_token,
145
/// name,
146
/// brace_token,
147
/// stmts,
148
/// })
149
/// }
150
/// }
151
/// ```
152
#[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
153
pub fn parse_within(input: ParseStream) -> Result<Vec<Stmt>> {
154
let mut stmts = Vec::new();
155
loop {
156
while let semi @ Some(_) = input.parse()? {
157
stmts.push(Stmt::Expr(Expr::Verbatim(TokenStream::new()), semi));
158
}
159
if input.is_empty() {
160
break;
161
}
162
let stmt = parse_stmt(input, AllowNoSemi(true))?;
163
let requires_semicolon = match &stmt {
164
Stmt::Expr(stmt, None) => classify::requires_semi_to_be_stmt(stmt),
165
Stmt::Macro(stmt) => {
166
stmt.semi_token.is_none() && !stmt.mac.delimiter.is_brace()
167
}
168
Stmt::Local(_) | Stmt::Item(_) | Stmt::Expr(_, Some(_)) => false,
169
};
170
stmts.push(stmt);
171
if input.is_empty() {
172
break;
173
} else if requires_semicolon {
174
return Err(input.error("unexpected token, expected `;`"));
175
}
176
}
177
Ok(stmts)
178
}
179
}
180
181
#[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
182
impl Parse for Block {
183
fn parse(input: ParseStream) -> Result<Self> {
184
let content;
185
Ok(Block {
186
brace_token: braced!(content in input),
187
stmts: content.call(Block::parse_within)?,
188
})
189
}
190
}
191
192
#[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
193
impl Parse for Stmt {
194
fn parse(input: ParseStream) -> Result<Self> {
195
let allow_nosemi = AllowNoSemi(false);
196
parse_stmt(input, allow_nosemi)
197
}
198
}
199
200
fn parse_stmt(input: ParseStream, allow_nosemi: AllowNoSemi) -> Result<Stmt> {
201
let begin = input.fork();
202
let attrs = input.call(Attribute::parse_outer)?;
203
204
// brace-style macros; paren and bracket macros get parsed as
205
// expression statements.
206
let ahead = input.fork();
207
let mut is_item_macro = false;
208
if let Ok(path) = ahead.call(Path::parse_mod_style) {
209
if ahead.peek(Token![!]) {
210
if ahead.peek2(Ident) || ahead.peek2(Token![try]) {
211
is_item_macro = true;
212
} else if ahead.peek2(token::Brace)
213
&& !(ahead.peek3(Token![.]) && !ahead.peek3(Token![..])
214
|| ahead.peek3(Token![?]))
215
{
216
input.advance_to(&ahead);
217
return stmt_mac(input, attrs, path).map(Stmt::Macro);
218
}
219
}
220
}
221
222
if input.peek(Token![let]) && !input.peek(token::Group) {
223
stmt_local(input, attrs).map(Stmt::Local)
224
} else if input.peek(Token![pub])
225
|| input.peek(Token![crate]) && !input.peek2(Token![::])
226
|| input.peek(Token![extern])
227
|| input.peek(Token![use])
228
|| input.peek(Token![static])
229
&& (input.peek2(Token![mut])
230
|| input.peek2(Ident)
231
&& !(input.peek2(Token![async])
232
&& (input.peek3(Token![move]) || input.peek3(Token![|]))))
233
|| input.peek(Token![const])
234
&& !(input.peek2(token::Brace)
235
|| input.peek2(Token![static])
236
|| input.peek2(Token![async])
237
&& !(input.peek3(Token![unsafe])
238
|| input.peek3(Token![extern])
239
|| input.peek3(Token![fn]))
240
|| input.peek2(Token![move])
241
|| input.peek2(Token![|]))
242
|| input.peek(Token![unsafe]) && !input.peek2(token::Brace)
243
|| input.peek(Token![async])
244
&& (input.peek2(Token![unsafe])
245
|| input.peek2(Token![extern])
246
|| input.peek2(Token![fn]))
247
|| input.peek(Token![fn])
248
|| input.peek(Token![mod])
249
|| input.peek(Token![type])
250
|| input.peek(Token![struct])
251
|| input.peek(Token![enum])
252
|| input.peek(Token![union]) && input.peek2(Ident)
253
|| input.peek(Token![auto]) && input.peek2(Token![trait])
254
|| input.peek(Token![trait])
255
|| input.peek(Token![default])
256
&& (input.peek2(Token![unsafe]) || input.peek2(Token![impl]))
257
|| input.peek(Token![impl])
258
|| input.peek(Token![macro])
259
|| is_item_macro
260
{
261
let item = item::parsing::parse_rest_of_item(begin, attrs, input)?;
262
Ok(Stmt::Item(item))
263
} else {
264
stmt_expr(input, allow_nosemi, attrs)
265
}
266
}
267
268
fn stmt_mac(input: ParseStream, attrs: Vec<Attribute>, path: Path) -> Result<StmtMacro> {
269
let bang_token: Token![!] = input.parse()?;
270
let (delimiter, tokens) = mac::parse_delimiter(input)?;
271
let semi_token: Option<Token![;]> = input.parse()?;
272
273
Ok(StmtMacro {
274
attrs,
275
mac: Macro {
276
path,
277
bang_token,
278
delimiter,
279
tokens,
280
},
281
semi_token,
282
})
283
}
284
285
fn stmt_local(input: ParseStream, attrs: Vec<Attribute>) -> Result<Local> {
286
let let_token: Token![let] = input.parse()?;
287
288
let mut pat = Pat::parse_single(input)?;
289
if input.peek(Token![:]) {
290
let colon_token: Token![:] = input.parse()?;
291
let ty: Type = input.parse()?;
292
pat = Pat::Type(PatType {
293
attrs: Vec::new(),
294
pat: Box::new(pat),
295
colon_token,
296
ty: Box::new(ty),
297
});
298
}
299
300
let init = if let Some(eq_token) = input.parse()? {
301
let eq_token: Token![=] = eq_token;
302
let expr: Expr = input.parse()?;
303
304
let diverge = if !classify::expr_trailing_brace(&expr) && input.peek(Token![else]) {
305
let else_token: Token![else] = input.parse()?;
306
let diverge = ExprBlock {
307
attrs: Vec::new(),
308
label: None,
309
block: input.parse()?,
310
};
311
Some((else_token, Box::new(Expr::Block(diverge))))
312
} else {
313
None
314
};
315
316
Some(LocalInit {
317
eq_token,
318
expr: Box::new(expr),
319
diverge,
320
})
321
} else {
322
None
323
};
324
325
let semi_token: Token![;] = input.parse()?;
326
327
Ok(Local {
328
attrs,
329
let_token,
330
pat,
331
init,
332
semi_token,
333
})
334
}
335
336
fn stmt_expr(
337
input: ParseStream,
338
allow_nosemi: AllowNoSemi,
339
mut attrs: Vec<Attribute>,
340
) -> Result<Stmt> {
341
let mut e = Expr::parse_with_earlier_boundary_rule(input)?;
342
343
let mut attr_target = &mut e;
344
loop {
345
attr_target = match attr_target {
346
Expr::Assign(e) => &mut e.left,
347
Expr::Binary(e) => &mut e.left,
348
Expr::Cast(e) => &mut e.expr,
349
Expr::Array(_)
350
| Expr::Async(_)
351
| Expr::Await(_)
352
| Expr::Block(_)
353
| Expr::Break(_)
354
| Expr::Call(_)
355
| Expr::Closure(_)
356
| Expr::Const(_)
357
| Expr::Continue(_)
358
| Expr::Field(_)
359
| Expr::ForLoop(_)
360
| Expr::Group(_)
361
| Expr::If(_)
362
| Expr::Index(_)
363
| Expr::Infer(_)
364
| Expr::Let(_)
365
| Expr::Lit(_)
366
| Expr::Loop(_)
367
| Expr::Macro(_)
368
| Expr::Match(_)
369
| Expr::MethodCall(_)
370
| Expr::Paren(_)
371
| Expr::Path(_)
372
| Expr::Range(_)
373
| Expr::RawAddr(_)
374
| Expr::Reference(_)
375
| Expr::Repeat(_)
376
| Expr::Return(_)
377
| Expr::Struct(_)
378
| Expr::Try(_)
379
| Expr::TryBlock(_)
380
| Expr::Tuple(_)
381
| Expr::Unary(_)
382
| Expr::Unsafe(_)
383
| Expr::While(_)
384
| Expr::Yield(_)
385
| Expr::Verbatim(_) => break,
386
};
387
}
388
attrs.extend(attr_target.replace_attrs(Vec::new()));
389
attr_target.replace_attrs(attrs);
390
391
let semi_token: Option<Token![;]> = input.parse()?;
392
393
match e {
394
Expr::Macro(ExprMacro { attrs, mac })
395
if semi_token.is_some() || mac.delimiter.is_brace() =>
396
{
397
return Ok(Stmt::Macro(StmtMacro {
398
attrs,
399
mac,
400
semi_token,
401
}));
402
}
403
_ => {}
404
}
405
406
if semi_token.is_some() {
407
Ok(Stmt::Expr(e, semi_token))
408
} else if allow_nosemi.0 || !classify::requires_semi_to_be_stmt(&e) {
409
Ok(Stmt::Expr(e, None))
410
} else {
411
Err(input.error("expected semicolon"))
412
}
413
}
414
}
415
416
#[cfg(feature = "printing")]
417
pub(crate) mod printing {
418
use crate::classify;
419
use crate::expr::{self, Expr};
420
use crate::fixup::FixupContext;
421
use crate::stmt::{Block, Local, Stmt, StmtMacro};
422
use crate::token;
423
use proc_macro2::TokenStream;
424
use quote::{ToTokens, TokenStreamExt};
425
426
#[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
427
impl ToTokens for Block {
428
fn to_tokens(&self, tokens: &mut TokenStream) {
429
self.brace_token.surround(tokens, |tokens| {
430
tokens.append_all(&self.stmts);
431
});
432
}
433
}
434
435
#[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
436
impl ToTokens for Stmt {
437
fn to_tokens(&self, tokens: &mut TokenStream) {
438
match self {
439
Stmt::Local(local) => local.to_tokens(tokens),
440
Stmt::Item(item) => item.to_tokens(tokens),
441
Stmt::Expr(expr, semi) => {
442
expr::printing::print_expr(expr, tokens, FixupContext::new_stmt());
443
semi.to_tokens(tokens);
444
}
445
Stmt::Macro(mac) => mac.to_tokens(tokens),
446
}
447
}
448
}
449
450
#[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
451
impl ToTokens for Local {
452
fn to_tokens(&self, tokens: &mut TokenStream) {
453
expr::printing::outer_attrs_to_tokens(&self.attrs, tokens);
454
self.let_token.to_tokens(tokens);
455
self.pat.to_tokens(tokens);
456
if let Some(init) = &self.init {
457
init.eq_token.to_tokens(tokens);
458
expr::printing::print_subexpression(
459
&init.expr,
460
init.diverge.is_some() && classify::expr_trailing_brace(&init.expr),
461
tokens,
462
FixupContext::NONE,
463
);
464
if let Some((else_token, diverge)) = &init.diverge {
465
else_token.to_tokens(tokens);
466
match &**diverge {
467
Expr::Block(diverge) => diverge.to_tokens(tokens),
468
_ => token::Brace::default().surround(tokens, |tokens| {
469
expr::printing::print_expr(diverge, tokens, FixupContext::new_stmt());
470
}),
471
}
472
}
473
}
474
self.semi_token.to_tokens(tokens);
475
}
476
}
477
478
#[cfg_attr(docsrs, doc(cfg(feature = "printing")))]
479
impl ToTokens for StmtMacro {
480
fn to_tokens(&self, tokens: &mut TokenStream) {
481
expr::printing::outer_attrs_to_tokens(&self.attrs, tokens);
482
self.mac.to_tokens(tokens);
483
self.semi_token.to_tokens(tokens);
484
}
485
}
486
}
487
488