solar_ast/ast/
yul.rs

1//! Yul AST.
2
3use super::{AstPath, Box, DocComments, Lit, StrLit};
4use solar_interface::{Ident, Span};
5
6/// A block of Yul statements: `{ ... }`.
7///
8/// Reference: <https://docs.soliditylang.org/en/latest/grammar.html#a4.SolidityParser.yulBlock>
9#[derive(Debug)]
10pub struct Block<'ast> {
11    /// The span of the block, including the `{` and `}`.
12    pub span: Span,
13    /// The statements in the block.
14    pub stmts: Box<'ast, [Stmt<'ast>]>,
15}
16
17impl<'ast> std::ops::Deref for Block<'ast> {
18    type Target = [Stmt<'ast>];
19
20    fn deref(&self) -> &Self::Target {
21        self.stmts
22    }
23}
24
25impl<'ast> std::ops::DerefMut for Block<'ast> {
26    fn deref_mut(&mut self) -> &mut Self::Target {
27        self.stmts
28    }
29}
30
31/// A Yul object.
32///
33/// Reference: <https://docs.soliditylang.org/en/latest/yul.html#specification-of-yul-object>
34#[derive(Debug)]
35pub struct Object<'ast> {
36    /// The doc-comments of the object.
37    pub docs: DocComments<'ast>,
38    /// The span of the object, including the `object` keyword, but excluding the doc-comments.
39    pub span: Span,
40    /// The name of the object.
41    pub name: StrLit,
42    /// The `code` block.
43    pub code: CodeBlock<'ast>,
44    /// Sub-objects, if any.
45    pub children: Box<'ast, [Object<'ast>]>,
46    /// `data` segments, if any.
47    pub data: Box<'ast, [Data<'ast>]>,
48}
49
50/// A Yul `code` block. See [`Object`].
51#[derive(Debug)]
52pub struct CodeBlock<'ast> {
53    /// The span of the code block, including the `code` keyword.
54    ///
55    /// The `code` keyword may not be present in the source code if the object is parsed as a
56    /// plain [`Block`].
57    pub span: Span,
58    /// The `code` block.
59    pub code: Block<'ast>,
60}
61
62/// A Yul `data` segment. See [`Object`].
63#[derive(Debug)]
64pub struct Data<'ast> {
65    /// The span of the code block, including the `data` keyword.
66    pub span: Span,
67    /// The name of the data segment.
68    pub name: StrLit,
69    /// The data. Can only be a `Str` or `HexStr` literal.
70    pub data: Lit<'ast>,
71}
72
73/// A Yul statement.
74///
75/// Reference: <https://docs.soliditylang.org/en/latest/grammar.html#a4.SolidityParser.yulStatement>
76#[derive(Debug)]
77pub struct Stmt<'ast> {
78    /// The doc-comments of the statement.
79    pub docs: DocComments<'ast>,
80    /// The span of the statement.
81    pub span: Span,
82    /// The kind of statement.
83    pub kind: StmtKind<'ast>,
84}
85
86/// A kind of Yul statement.
87#[derive(Debug)]
88pub enum StmtKind<'ast> {
89    /// A blocked scope: `{ ... }`.
90    ///
91    /// Reference: <https://docs.soliditylang.org/en/latest/grammar.html#a4.SolidityParser.yulBlock>
92    Block(Block<'ast>),
93
94    /// A single-variable assignment statement: `x := 1`.
95    ///
96    /// Reference: <https://docs.soliditylang.org/en/latest/grammar.html#a4.SolidityParser.yulAssignment>
97    AssignSingle(AstPath<'ast>, Expr<'ast>),
98
99    /// A multiple-variable assignment statement: `x, y, z := foo(1, 2)`.
100    ///
101    /// Multi-assignments require a function call on the right-hand side.
102    ///
103    /// Reference: <https://docs.soliditylang.org/en/latest/grammar.html#a4.SolidityParser.yulAssignment>
104    AssignMulti(Box<'ast, [AstPath<'ast>]>, ExprCall<'ast>),
105
106    /// An expression statement. This can only be a function call.
107    Expr(ExprCall<'ast>),
108
109    /// An if statement: `if lt(a, b) { ... }`.
110    ///
111    /// Reference: <https://docs.soliditylang.org/en/latest/grammar.html#a4.SolidityParser.yulIfStatement>
112    If(Expr<'ast>, Block<'ast>),
113
114    /// A for statement: `for {let i := 0} lt(i,10) {i := add(i,1)} { ... }`.
115    ///
116    /// Reference: <https://docs.soliditylang.org/en/latest/grammar.html#a4.SolidityParser.yulForStatement>
117    ///
118    /// Breakdown of parts: <https://docs.soliditylang.org/en/latest/yul.html#loops>
119    For { init: Block<'ast>, cond: Expr<'ast>, step: Block<'ast>, body: Block<'ast> },
120
121    /// A switch statement: `switch expr case 0 { ... } default { ... }`.
122    ///
123    /// Reference: <https://docs.soliditylang.org/en/latest/grammar.html#a4.SolidityParser.yulSwitchStatement>
124    Switch(StmtSwitch<'ast>),
125
126    /// A leave statement: `leave`.
127    Leave,
128
129    /// A break statement: `break`.
130    Break,
131
132    /// A continue statement: `continue`.
133    Continue,
134
135    /// A function definition statement: `function f() { ... }`.
136    FunctionDef(Function<'ast>),
137
138    /// A variable declaration statement: `let x := 0`.
139    ///
140    /// Reference: <https://docs.soliditylang.org/en/latest/grammar.html#a4.SolidityParser.yulVariableDeclaration>
141    VarDecl(Box<'ast, [Ident]>, Option<Expr<'ast>>),
142}
143
144/// A Yul switch statement can consist of only a default-case or one
145/// or more non-default cases optionally followed by a default-case.
146///
147/// Example switch statement in Yul:
148///
149/// ```solidity
150/// switch exponent
151/// case 0 { result := 1 }
152/// case 1 { result := base }
153/// default { revert(0, 0) }
154/// ```
155///
156/// Reference: <https://docs.soliditylang.org/en/latest/grammar.html#a4.SolidityParser.yulSwitchStatement>
157#[derive(Debug)]
158pub struct StmtSwitch<'ast> {
159    pub selector: Expr<'ast>,
160    pub branches: Box<'ast, [StmtSwitchCase<'ast>]>,
161    pub default_case: Option<Block<'ast>>,
162}
163
164/// Represents a non-default case of a Yul switch statement.
165///
166/// See [`StmtSwitch`] for more information.
167#[derive(Debug)]
168pub struct StmtSwitchCase<'ast> {
169    pub constant: Lit<'ast>,
170    pub body: Block<'ast>,
171}
172
173/// Yul function definition: `function f() -> a, b { ... }`.
174///
175/// Reference: <https://docs.soliditylang.org/en/latest/grammar.html#a4.SolidityParser.yulFunctionDefinition>
176#[derive(Debug)]
177pub struct Function<'ast> {
178    pub name: Ident,
179    pub parameters: Box<'ast, [Ident]>,
180    pub returns: Box<'ast, [Ident]>,
181    pub body: Block<'ast>,
182}
183
184/// A Yul expression.
185#[derive(Debug)]
186pub struct Expr<'ast> {
187    /// The span of the expression.
188    pub span: Span,
189    /// The kind of expression.
190    pub kind: ExprKind<'ast>,
191}
192
193/// A kind of Yul expression.
194#[derive(Debug)]
195pub enum ExprKind<'ast> {
196    /// A single path.
197    Path(AstPath<'ast>),
198    /// A function call: `foo(a, b)`.
199    Call(ExprCall<'ast>),
200    /// A literal.
201    Lit(Box<'ast, Lit<'ast>>),
202}
203
204/// A Yul function call expression: `foo(a, b)`.
205///
206/// Reference: <https://docs.soliditylang.org/en/latest/grammar.html#a4.SolidityParser.yulFunctionCall>
207#[derive(Debug)]
208pub struct ExprCall<'ast> {
209    pub name: Ident,
210    pub arguments: Box<'ast, [Expr<'ast>]>,
211}