Skip to main content

solidity_language_server/solc_ast/
yul.rs

1//! Yul (inline assembly) AST node types.
2//!
3//! These represent the Yul sub-AST embedded inside `InlineAssembly` nodes.
4//! Field names use `nativeSrc` (not `src`) in the JSON output.
5
6use serde::{Deserialize, Serialize};
7
8use super::YulLiteralKind;
9
10// ── Yul expressions ────────────────────────────────────────────────────────
11
12/// A Yul expression — either an identifier, literal, or function call.
13#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
14#[serde(tag = "nodeType")]
15pub enum YulExpression {
16    YulIdentifier(YulIdentifier),
17    YulLiteral(YulLiteral),
18    YulFunctionCall(YulFunctionCall),
19}
20
21/// A Yul identifier reference.
22#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
23#[serde(rename_all = "camelCase")]
24pub struct YulIdentifier {
25    pub name: String,
26    pub src: String,
27    #[serde(default)]
28    pub native_src: Option<String>,
29}
30
31/// A Yul literal value.
32#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
33#[serde(rename_all = "camelCase")]
34pub struct YulLiteral {
35    pub kind: YulLiteralKind,
36    pub src: String,
37    #[serde(default)]
38    pub native_src: Option<String>,
39    #[serde(default)]
40    pub value: Option<String>,
41    /// The Yul type (e.g. `""` or `"bool"`).
42    #[serde(rename = "type", default)]
43    pub yul_type: Option<String>,
44}
45
46/// A Yul function call.
47#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
48#[serde(rename_all = "camelCase")]
49pub struct YulFunctionCall {
50    pub function_name: YulIdentifier,
51    #[serde(default)]
52    pub arguments: Vec<YulExpression>,
53    pub src: String,
54    #[serde(default)]
55    pub native_src: Option<String>,
56}
57
58// ── Yul statements ─────────────────────────────────────────────────────────
59
60/// A Yul statement.
61#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
62#[serde(tag = "nodeType")]
63pub enum YulStatement {
64    YulBlock(YulBlock),
65    YulVariableDeclaration(YulVariableDeclaration),
66    YulAssignment(YulAssignment),
67    YulExpressionStatement(YulExpressionStatement),
68    YulIf(YulIf),
69    YulForLoop(YulForLoop),
70    YulBreak(YulBreak),
71    YulContinue(YulContinue),
72    YulLeave(YulLeave),
73    YulSwitch(YulSwitch),
74    YulFunctionDefinition(YulFunctionDefinition),
75}
76
77/// A Yul block — a sequence of statements.
78#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
79#[serde(rename_all = "camelCase")]
80pub struct YulBlock {
81    pub src: String,
82    #[serde(default)]
83    pub native_src: Option<String>,
84    #[serde(default)]
85    pub statements: Vec<YulStatement>,
86}
87
88/// A typed name in Yul (used in variable declarations, function params).
89#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
90#[serde(rename_all = "camelCase")]
91pub struct YulTypedName {
92    pub name: String,
93    pub src: String,
94    #[serde(default)]
95    pub native_src: Option<String>,
96    #[serde(rename = "type", default)]
97    pub yul_type: Option<String>,
98}
99
100/// A Yul variable declaration (`let x := expr`).
101#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
102#[serde(rename_all = "camelCase")]
103pub struct YulVariableDeclaration {
104    pub src: String,
105    #[serde(default)]
106    pub native_src: Option<String>,
107    #[serde(default)]
108    pub variables: Vec<YulTypedName>,
109    pub value: Option<YulExpression>,
110}
111
112/// A Yul assignment (`x := expr`).
113#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
114#[serde(rename_all = "camelCase")]
115pub struct YulAssignment {
116    pub src: String,
117    #[serde(default)]
118    pub native_src: Option<String>,
119    #[serde(default)]
120    pub variable_names: Vec<YulIdentifier>,
121    pub value: Option<YulExpression>,
122}
123
124/// A Yul expression statement (a bare function call).
125#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
126#[serde(rename_all = "camelCase")]
127pub struct YulExpressionStatement {
128    pub src: String,
129    #[serde(default)]
130    pub native_src: Option<String>,
131    pub expression: YulExpression,
132}
133
134/// A Yul `if` statement (no `else` in Yul).
135#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
136#[serde(rename_all = "camelCase")]
137pub struct YulIf {
138    pub src: String,
139    #[serde(default)]
140    pub native_src: Option<String>,
141    pub condition: YulExpression,
142    pub body: YulBlock,
143}
144
145/// A Yul `for` loop.
146#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
147#[serde(rename_all = "camelCase")]
148pub struct YulForLoop {
149    pub src: String,
150    #[serde(default)]
151    pub native_src: Option<String>,
152    pub pre: YulBlock,
153    pub condition: YulExpression,
154    pub post: YulBlock,
155    pub body: YulBlock,
156}
157
158/// A Yul `break` statement.
159#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
160#[serde(rename_all = "camelCase")]
161pub struct YulBreak {
162    pub src: String,
163    #[serde(default)]
164    pub native_src: Option<String>,
165}
166
167/// A Yul `continue` statement.
168#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
169#[serde(rename_all = "camelCase")]
170pub struct YulContinue {
171    pub src: String,
172    #[serde(default)]
173    pub native_src: Option<String>,
174}
175
176/// A Yul `leave` statement (return from Yul function).
177#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
178#[serde(rename_all = "camelCase")]
179pub struct YulLeave {
180    pub src: String,
181    #[serde(default)]
182    pub native_src: Option<String>,
183}
184
185/// A Yul `switch` statement.
186#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
187#[serde(rename_all = "camelCase")]
188pub struct YulSwitch {
189    pub src: String,
190    #[serde(default)]
191    pub native_src: Option<String>,
192    pub expression: YulExpression,
193    #[serde(default)]
194    pub cases: Vec<YulCase>,
195}
196
197/// A single `case` in a Yul `switch`.
198#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
199#[serde(rename_all = "camelCase")]
200pub struct YulCase {
201    pub src: String,
202    #[serde(default)]
203    pub native_src: Option<String>,
204    /// `None` for the `default` case.
205    /// Solc encodes the default case's value as the string `"default"` rather
206    /// than `null`, so we need a custom deserializer.
207    #[serde(default, deserialize_with = "deserialize_yul_case_value")]
208    pub value: Option<YulLiteral>,
209    pub body: YulBlock,
210}
211
212/// Deserialize a YulCase value field that can be:
213/// - a YulLiteral object (normal case)
214/// - the string `"default"` (default case — treated as None)
215/// - null (also default case)
216fn deserialize_yul_case_value<'de, D>(deserializer: D) -> Result<Option<YulLiteral>, D::Error>
217where
218    D: serde::Deserializer<'de>,
219{
220    use serde::de;
221
222    struct YulCaseValueVisitor;
223
224    impl<'de> de::Visitor<'de> for YulCaseValueVisitor {
225        type Value = Option<YulLiteral>;
226
227        fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
228            formatter.write_str("a YulLiteral object, the string \"default\", or null")
229        }
230
231        fn visit_str<E: de::Error>(self, v: &str) -> Result<Self::Value, E> {
232            if v == "default" {
233                Ok(None)
234            } else {
235                Err(de::Error::invalid_value(de::Unexpected::Str(v), &self))
236            }
237        }
238
239        fn visit_none<E: de::Error>(self) -> Result<Self::Value, E> {
240            Ok(None)
241        }
242
243        fn visit_unit<E: de::Error>(self) -> Result<Self::Value, E> {
244            Ok(None)
245        }
246
247        fn visit_map<A: de::MapAccess<'de>>(self, map: A) -> Result<Self::Value, A::Error> {
248            let literal = YulLiteral::deserialize(de::value::MapAccessDeserializer::new(map))?;
249            Ok(Some(literal))
250        }
251    }
252
253    deserializer.deserialize_any(YulCaseValueVisitor)
254}
255
256/// A Yul function definition.
257#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
258#[serde(rename_all = "camelCase")]
259pub struct YulFunctionDefinition {
260    pub src: String,
261    #[serde(default)]
262    pub native_src: Option<String>,
263    pub name: String,
264    #[serde(default)]
265    pub parameters: Vec<YulTypedName>,
266    #[serde(default)]
267    pub return_variables: Vec<YulTypedName>,
268    pub body: YulBlock,
269}