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