ethers_solc/artifacts/ast/
lowfidelity.rs1use crate::artifacts::serde_helpers;
4use serde::{de::DeserializeOwned, Deserialize, Serialize};
5use std::{collections::BTreeMap, fmt, fmt::Write, str::FromStr};
6
7#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
9pub struct Ast {
10 #[serde(rename = "absolutePath")]
11 pub absolute_path: String,
12 pub id: usize,
13 #[serde(default, rename = "exportedSymbols")]
14 pub exported_symbols: BTreeMap<String, Vec<usize>>,
15 #[serde(rename = "nodeType")]
16 pub node_type: NodeType,
17 #[serde(with = "serde_helpers::display_from_str")]
18 pub src: SourceLocation,
19 #[serde(default)]
20 pub nodes: Vec<Node>,
21
22 #[serde(flatten)]
24 pub other: BTreeMap<String, serde_json::Value>,
25}
26
27#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
28pub struct Node {
29 #[serde(default, skip_serializing_if = "Option::is_none")]
31 pub id: Option<usize>,
32
33 #[serde(rename = "nodeType")]
35 pub node_type: NodeType,
36
37 #[serde(with = "serde_helpers::display_from_str")]
39 pub src: SourceLocation,
40
41 #[serde(default)]
43 pub nodes: Vec<Node>,
44
45 #[serde(default, skip_serializing_if = "Option::is_none")]
47 pub body: Option<Box<Node>>,
48
49 #[serde(flatten)]
51 pub other: BTreeMap<String, serde_json::Value>,
52}
53
54impl Node {
55 pub fn attribute<D: DeserializeOwned>(&self, key: impl AsRef<str>) -> Option<D> {
57 self.other.get(key.as_ref()).and_then(|v| serde_json::from_value(v.clone()).ok())
59 }
60}
61
62#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
66pub struct SourceLocation {
67 pub start: usize,
68 pub length: Option<usize>,
69 pub index: Option<usize>,
70}
71
72impl FromStr for SourceLocation {
73 type Err = String;
74
75 fn from_str(s: &str) -> Result<Self, Self::Err> {
76 let invalid_location = move || format!("{s} invalid source location");
77
78 let mut split = s.split(':');
79 let start = split
80 .next()
81 .ok_or_else(invalid_location)?
82 .parse::<usize>()
83 .map_err(|_| invalid_location())?;
84 let length = split
85 .next()
86 .ok_or_else(invalid_location)?
87 .parse::<isize>()
88 .map_err(|_| invalid_location())?;
89 let index = split
90 .next()
91 .ok_or_else(invalid_location)?
92 .parse::<isize>()
93 .map_err(|_| invalid_location())?;
94
95 let length = if length < 0 { None } else { Some(length as usize) };
96 let index = if index < 0 { None } else { Some(index as usize) };
97
98 Ok(Self { start, length, index })
99 }
100}
101
102impl fmt::Display for SourceLocation {
103 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
104 self.start.fmt(f)?;
105 f.write_char(':')?;
106 if let Some(length) = self.length {
107 length.fmt(f)?;
108 } else {
109 f.write_str("-1")?;
110 }
111 f.write_char(':')?;
112 if let Some(index) = self.index {
113 index.fmt(f)?;
114 } else {
115 f.write_str("-1")?;
116 }
117 Ok(())
118 }
119}
120
121#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
122pub enum NodeType {
123 Assignment,
125 BinaryOperation,
126 Conditional,
127 ElementaryTypeNameExpression,
128 FunctionCall,
129 FunctionCallOptions,
130 Identifier,
131 IndexAccess,
132 IndexRangeAccess,
133 Literal,
134 MemberAccess,
135 NewExpression,
136 TupleExpression,
137 UnaryOperation,
138
139 Block,
141 Break,
142 Continue,
143 DoWhileStatement,
144 EmitStatement,
145 ExpressionStatement,
146 ForStatement,
147 IfStatement,
148 InlineAssembly,
149 PlaceholderStatement,
150 Return,
151 RevertStatement,
152 TryStatement,
153 UncheckedBlock,
154 VariableDeclarationStatement,
155 VariableDeclaration,
156 WhileStatement,
157
158 YulAssignment,
160 YulBlock,
161 YulBreak,
162 YulContinue,
163 YulExpressionStatement,
164 YulLeave,
165 YulForLoop,
166 YulFunctionDefinition,
167 YulIf,
168 YulSwitch,
169 YulVariableDeclaration,
170
171 YulFunctionCall,
173 YulIdentifier,
174 YulLiteral,
175
176 YulLiteralValue,
178 YulHexValue,
179
180 ContractDefinition,
182 FunctionDefinition,
183 EventDefinition,
184 ErrorDefinition,
185 ModifierDefinition,
186 StructDefinition,
187 EnumDefinition,
188 UserDefinedValueTypeDefinition,
189
190 PragmaDirective,
192 ImportDirective,
193 UsingForDirective,
194
195 SourceUnit,
197 InheritanceSpecifier,
198 ElementaryTypeName,
199 FunctionTypeName,
200 ParameterList,
201 TryCatchClause,
202 ModifierInvocation,
203
204 Other(String),
206}
207
208#[cfg(test)]
209mod tests {
210 use super::*;
211
212 #[test]
213 fn can_parse_ast() {
214 let ast = include_str!("../../../test-data/ast/ast-erc4626.json");
215 let _ast: Ast = serde_json::from_str(ast).unwrap();
216 }
217}