syn_solidity/stmt/
mod.rs

1use crate::{kw, Spanned};
2use proc_macro2::Span;
3use std::fmt;
4use syn::{
5    parse::{Parse, ParseStream},
6    token::{Brace, Bracket, Paren},
7    Result, Token,
8};
9
10mod assembly;
11pub use assembly::{AssemblyFlags, StmtAssembly};
12
13mod blocks;
14pub use blocks::{Block, UncheckedBlock};
15
16mod r#break;
17pub use r#break::StmtBreak;
18
19mod r#continue;
20pub use r#continue::StmtContinue;
21
22mod do_while;
23pub use do_while::StmtDoWhile;
24
25mod emit;
26pub use emit::StmtEmit;
27
28mod expr;
29pub use expr::StmtExpr;
30
31mod r#for;
32pub use r#for::{ForInitStmt, StmtFor};
33
34mod r#if;
35pub use r#if::StmtIf;
36
37mod r#return;
38pub use r#return::StmtReturn;
39
40mod revert;
41pub use revert::StmtRevert;
42
43mod r#try;
44pub use r#try::{CatchClause, StmtTry};
45
46mod var_decl;
47pub use var_decl::{StmtVarDecl, VarDeclDecl, VarDeclTuple};
48
49mod r#while;
50pub use r#while::StmtWhile;
51
52/// A statement, usually ending in a semicolon.
53///
54/// Solidity reference:
55/// <https://docs.soliditylang.org/en/latest/grammar.html#a4.SolidityParser.statement>
56#[derive(Clone)]
57pub enum Stmt {
58    /// An assembly block, with optional flags: `assembly "evmasm" { ... }`.
59    Assembly(StmtAssembly),
60
61    /// A blocked scope: `{ ... }`.
62    Block(Block),
63
64    /// A break statement: `break;`.
65    Break(StmtBreak),
66
67    /// A continue statement: `continue;`.
68    Continue(StmtContinue),
69
70    /// A do-while statement: `do { ... } while (condition);`.
71    DoWhile(StmtDoWhile),
72
73    /// An emit statement: `emit FooBar(42);`.
74    Emit(StmtEmit),
75
76    /// An expression with a trailing semicolon.
77    Expr(StmtExpr),
78
79    /// A for statement: `for (uint256 i; i < 42; ++i) { ... }`.
80    For(StmtFor),
81
82    /// An `if` statement with an optional `else` block: `if (expr) { ... } else
83    /// { ... }`.
84    If(StmtIf),
85
86    /// A return statement: `return 42;`.
87    Return(StmtReturn),
88
89    /// A revert statement: `revert("error");`.
90    Revert(StmtRevert),
91
92    /// A try statement: `try fooBar(42) catch { ... }`.
93    Try(StmtTry),
94
95    /// An unchecked block: `unchecked { ... }`.
96    UncheckedBlock(UncheckedBlock),
97
98    /// A variable declaration statement: `uint256 foo = 42;`.
99    VarDecl(StmtVarDecl),
100
101    /// A while statement: `while (i < 42) { ... }`.
102    While(StmtWhile),
103}
104
105impl fmt::Debug for Stmt {
106    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
107        f.write_str("Stmt::")?;
108        match self {
109            Self::Assembly(stmt) => stmt.fmt(f),
110            Self::Block(block) => block.fmt(f),
111            Self::Break(stmt) => stmt.fmt(f),
112            Self::Continue(stmt) => stmt.fmt(f),
113            Self::DoWhile(stmt) => stmt.fmt(f),
114            Self::Emit(stmt) => stmt.fmt(f),
115            Self::Expr(stmt) => stmt.fmt(f),
116            Self::For(stmt) => stmt.fmt(f),
117            Self::If(stmt) => stmt.fmt(f),
118            Self::Return(stmt) => stmt.fmt(f),
119            Self::Revert(stmt) => stmt.fmt(f),
120            Self::Try(stmt) => stmt.fmt(f),
121            Self::UncheckedBlock(block) => block.fmt(f),
122            Self::VarDecl(stmt) => stmt.fmt(f),
123            Self::While(stmt) => stmt.fmt(f),
124        }
125    }
126}
127
128impl Parse for Stmt {
129    fn parse(input: ParseStream<'_>) -> Result<Self> {
130        // skip any attributes
131        let _ = input.call(syn::Attribute::parse_outer)?;
132
133        debug!("  > Stmt: {:?}", input.to_string());
134        let stmt = Self::parse_simple(input)?;
135        debug!("  < Stmt: {stmt:?}\n");
136        Ok(stmt)
137    }
138}
139
140impl Spanned for Stmt {
141    fn span(&self) -> Span {
142        match self {
143            Self::Assembly(stmt) => stmt.span(),
144            Self::Block(block) => block.span(),
145            Self::Break(stmt) => stmt.span(),
146            Self::Continue(stmt) => stmt.span(),
147            Self::DoWhile(stmt) => stmt.span(),
148            Self::Emit(stmt) => stmt.span(),
149            Self::Expr(stmt) => stmt.span(),
150            Self::For(stmt) => stmt.span(),
151            Self::If(stmt) => stmt.span(),
152            Self::Return(stmt) => stmt.span(),
153            Self::Revert(stmt) => stmt.span(),
154            Self::Try(stmt) => stmt.span(),
155            Self::UncheckedBlock(block) => block.span(),
156            Self::VarDecl(stmt) => stmt.span(),
157            Self::While(stmt) => stmt.span(),
158        }
159    }
160
161    fn set_span(&mut self, span: Span) {
162        match self {
163            Self::Assembly(stmt) => stmt.set_span(span),
164            Self::Block(block) => block.set_span(span),
165            Self::Break(stmt) => stmt.set_span(span),
166            Self::Continue(stmt) => stmt.set_span(span),
167            Self::DoWhile(stmt) => stmt.set_span(span),
168            Self::Emit(stmt) => stmt.set_span(span),
169            Self::Expr(stmt) => stmt.set_span(span),
170            Self::For(stmt) => stmt.set_span(span),
171            Self::If(stmt) => stmt.set_span(span),
172            Self::Return(stmt) => stmt.set_span(span),
173            Self::Revert(stmt) => stmt.set_span(span),
174            Self::Try(stmt) => stmt.set_span(span),
175            Self::UncheckedBlock(block) => block.set_span(span),
176            Self::VarDecl(stmt) => stmt.set_span(span),
177            Self::While(stmt) => stmt.set_span(span),
178        }
179    }
180}
181
182impl Stmt {
183    fn parse_simple(input: ParseStream<'_>) -> Result<Self> {
184        let lookahead = input.lookahead1();
185        if lookahead.peek(Brace) {
186            input.parse().map(Self::Block)
187        } else if lookahead.peek(Paren) {
188            StmtVarDecl::parse_or_expr(input)
189        } else if lookahead.peek(Bracket) {
190            input.parse().map(Self::Expr)
191        } else if lookahead.peek(kw::unchecked) {
192            input.parse().map(Self::UncheckedBlock)
193        } else if lookahead.peek(Token![if]) {
194            input.parse().map(Self::If)
195        } else if lookahead.peek(Token![for]) {
196            input.parse().map(Self::For)
197        } else if lookahead.peek(Token![while]) {
198            input.parse().map(Self::While)
199        } else if lookahead.peek(Token![do]) {
200            input.parse().map(Self::DoWhile)
201        } else if lookahead.peek(Token![continue]) {
202            input.parse().map(Self::Continue)
203        } else if lookahead.peek(Token![break]) {
204            input.parse().map(Self::Break)
205        } else if lookahead.peek(Token![try]) {
206            input.parse().map(Self::Try)
207        } else if lookahead.peek(Token![return]) {
208            input.parse().map(Self::Return)
209        } else if lookahead.peek(kw::emit) {
210            input.parse().map(Self::Emit)
211        } else if lookahead.peek(kw::revert) {
212            input.parse().map(Self::Revert)
213        } else if lookahead.peek(kw::assembly) {
214            input.parse().map(Self::Assembly)
215        } else {
216            StmtVarDecl::parse_or_expr(input)
217        }
218    }
219}