1use crate::{Expr, Spanned, Stmt, StmtExpr, StmtVarDecl};
2use proc_macro2::Span;
3use std::fmt;
4use syn::{
5 parenthesized,
6 parse::{Parse, ParseStream},
7 token::Paren,
8 Result, Token,
9};
10
11#[derive(Clone)]
16pub struct StmtFor {
17 pub for_token: Token![for],
18 pub paren_token: Paren,
19 pub init: ForInitStmt,
20 pub cond: Option<Box<Expr>>,
21 pub semi_token: Token![;],
22 pub post: Option<Box<Expr>>,
23 pub body: Box<Stmt>,
24}
25
26impl fmt::Debug for StmtFor {
27 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
28 f.debug_struct("StmtFor")
29 .field("init", &self.init)
30 .field("cond", &self.cond)
31 .field("post", &self.post)
32 .field("body", &self.body)
33 .finish()
34 }
35}
36
37impl Parse for StmtFor {
38 fn parse(input: ParseStream<'_>) -> Result<Self> {
39 let content;
40 Ok(Self {
41 for_token: input.parse()?,
42 paren_token: parenthesized!(content in input),
43 init: content.parse()?,
44 cond: if content.peek(Token![;]) { None } else { Some(content.parse()?) },
45 semi_token: content.parse()?,
46 post: if content.is_empty() { None } else { Some(content.parse()?) },
47 body: input.parse()?,
48 })
49 }
50}
51
52impl Spanned for StmtFor {
53 fn span(&self) -> Span {
54 let span = self.for_token.span;
55 span.join(self.body.span()).unwrap_or(span)
56 }
57
58 fn set_span(&mut self, span: Span) {
59 self.for_token.span = span;
60 self.body.set_span(span);
61 }
62}
63
64#[derive(Clone, Debug)]
68pub enum ForInitStmt {
69 Empty(Token![;]),
70 VarDecl(StmtVarDecl),
71 Expr(StmtExpr),
72}
73
74impl Parse for ForInitStmt {
75 fn parse(input: ParseStream<'_>) -> Result<Self> {
76 let lookahead = input.lookahead1();
77 if lookahead.peek(Token![;]) {
78 input.parse().map(Self::Empty)
79 } else {
80 match StmtVarDecl::parse_or_expr(input)? {
81 Stmt::VarDecl(decl) => Ok(Self::VarDecl(decl)),
82 Stmt::Expr(expr) => Ok(Self::Expr(expr)),
83 s => unreachable!("StmtVarDecl::parse_or_expr: invalid output {s:?}"),
84 }
85 }
86 }
87}