syn_solidity/stmt/
for.rs

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