syn_solidity/stmt/
for.rs

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/// A for statement: `for (uint256 i; i < 42; ++i) { ... }`.
12///
13/// Solidity Reference:
14/// <https://docs.soliditylang.org/en/latest/grammar.html#a4.SolidityParser.forStatement>
15#[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/// A for statement initializer.
65///
66/// This can either be empty, a variable declaration, or an expression.
67#[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}