use serde::{Deserialize, Serialize};
pub fn parse_src(src: &str) -> (u64, u64, u64) {
let parts: Vec<&str> = src.split(':').collect();
let start = parts.first().and_then(|s| s.parse().ok()).unwrap_or(0);
let length = parts.get(1).and_then(|s| s.parse().ok()).unwrap_or(0);
let file = parts.get(2).and_then(|s| s.parse().ok()).unwrap_or(0);
(start, length, file)
}
pub fn offset_to_line(source: &str, byte_offset: u64) -> usize {
source[..std::cmp::min(byte_offset as usize, source.len())]
.chars()
.filter(|&c| c == '\n')
.count()
+ 1
}
#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct SourceUnit {
pub id: u64,
pub src: String,
pub nodes: Vec<AstNode>,
}
#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct ContractDefinition {
pub id: u64,
pub src: String,
pub name: String,
#[serde(rename = "contractKind")]
pub contract_kind: String,
#[serde(rename = "baseContracts")]
pub base_contracts: Vec<InheritanceSpecifier>,
pub nodes: Vec<AstNode>,
#[serde(rename = "linearizedBaseContracts")]
pub linearized_base_contracts: Vec<u64>,
}
#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct InheritanceSpecifier {
#[serde(rename = "baseName")]
pub base_name: Identifier,
}
#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct FunctionDefinition {
pub id: u64,
pub src: String,
pub name: String,
pub visibility: String,
#[serde(rename = "stateMutability")]
pub state_mutability: String,
#[serde(rename = "isConstructor")]
pub is_constructor: bool,
pub modifiers: Vec<ModifierInvocation>,
pub parameters: ParameterList,
#[serde(rename = "returnParameters")]
pub return_parameters: ParameterList,
pub body: Option<Block>,
}
#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct ModifierInvocation {
#[serde(rename = "modifierName")]
pub modifier_name: Identifier,
}
#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct ParameterList {
pub parameters: Vec<VariableDeclaration>,
}
#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct VariableDeclaration {
pub id: u64,
pub src: String,
pub name: String,
#[serde(rename = "stateVariable")]
pub state_variable: bool,
pub visibility: String,
#[serde(rename = "storageLocation")]
pub storage_location: String,
#[serde(rename = "typeName")]
pub type_name: Option<Box<AstNode>>,
#[serde(rename = "typeDescriptions")]
pub type_descriptions: Option<TypeDescription>,
}
#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct TypeDescription {
#[serde(rename = "typeIdentifier")]
pub type_identifier: String,
#[serde(rename = "typeString")]
pub type_string: String,
}
#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct Block {
pub id: u64,
pub src: String,
pub statements: Vec<AstNode>,
}
#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct ExpressionStatement {
pub id: u64,
pub src: String,
pub expression: Option<Box<AstNode>>,
}
#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct IfStatement {
pub id: u64,
pub src: String,
pub condition: Box<AstNode>,
#[serde(rename = "trueBody")]
pub true_body: Box<AstNode>,
#[serde(rename = "falseBody")]
pub false_body: Option<Box<AstNode>>,
}
#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct ForStatement {
pub id: u64,
pub src: String,
}
#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct WhileStatement {
pub id: u64,
pub src: String,
}
#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct ReturnStatement {
pub id: u64,
pub src: String,
}
#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct Assignment {
pub id: u64,
pub src: String,
#[serde(rename = "leftHandSide")]
pub left_hand_side: Box<AstNode>,
pub operator: String,
#[serde(rename = "rightHandSide")]
pub right_hand_side: Box<AstNode>,
}
#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct FunctionCall {
pub id: u64,
pub src: String,
pub expression: Box<AstNode>,
pub arguments: Vec<AstNode>,
pub names: Vec<String>,
#[serde(rename = "tryCall")]
pub try_call: bool,
}
#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct MemberAccess {
pub id: u64,
pub src: String,
pub expression: Box<AstNode>,
#[serde(rename = "memberName")]
pub member_name: String,
#[serde(rename = "typeDescriptions")]
pub type_descriptions: Option<TypeDescription>,
}
#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct IndexAccess {
pub id: u64,
pub src: String,
#[serde(rename = "baseExpression")]
pub base_expression: Box<AstNode>,
#[serde(rename = "indexExpression")]
pub index_expression: Option<Box<AstNode>>,
}
#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct BinaryOperation {
pub id: u64,
pub src: String,
pub operator: String,
#[serde(rename = "leftExpression")]
pub left_expression: Box<AstNode>,
#[serde(rename = "rightExpression")]
pub right_expression: Box<AstNode>,
#[serde(rename = "commonType")]
pub common_type: Option<TypeDescription>,
}
#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct Identifier {
pub id: u64,
pub src: String,
pub name: String,
#[serde(rename = "referencedDeclaration")]
pub referenced_declaration: Option<u64>,
#[serde(rename = "typeDescriptions")]
pub type_descriptions: Option<TypeDescription>,
}
#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct Literal {
pub id: u64,
pub src: String,
pub value: String,
pub subdenomination: Option<String>,
#[serde(rename = "typeDescriptions")]
pub type_descriptions: Option<TypeDescription>,
}
#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct EmitStatement {
pub id: u64,
pub src: String,
#[serde(rename = "eventCall")]
pub event_call: Box<AstNode>,
}
#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct RevertStatement {
pub id: u64,
pub src: String,
#[serde(rename = "errorCall")]
pub error_call: Option<Box<AstNode>>,
}
#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct ModifierDefinition {
pub id: u64,
pub src: String,
pub name: String,
pub parameters: ParameterList,
pub body: Option<Block>,
}
#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct StateVariableDeclaration {
pub id: u64,
pub src: String,
pub variables: Vec<VariableDeclaration>,
}
#[derive(Debug, Clone, Deserialize, Serialize)]
#[serde(tag = "nodeType")]
pub enum AstNode {
#[serde(rename = "SourceUnit")]
SourceUnit(SourceUnit),
#[serde(rename = "ContractDefinition")]
ContractDefinition(ContractDefinition),
#[serde(rename = "FunctionDefinition")]
FunctionDefinition(FunctionDefinition),
#[serde(rename = "ModifierDefinition")]
ModifierDefinition(ModifierDefinition),
#[serde(rename = "VariableDeclarationStatement")]
StateVariableDeclaration(StateVariableDeclaration),
#[serde(rename = "ExpressionStatement")]
ExpressionStatement(ExpressionStatement),
#[serde(rename = "IfStatement")]
IfStatement(IfStatement),
#[serde(rename = "ForStatement")]
ForStatement(ForStatement),
#[serde(rename = "WhileStatement")]
WhileStatement(WhileStatement),
#[serde(rename = "Return")]
ReturnStatement(ReturnStatement),
#[serde(rename = "Assignment")]
Assignment(Assignment),
#[serde(rename = "FunctionCall")]
FunctionCall(FunctionCall),
#[serde(rename = "MemberAccess")]
MemberAccess(MemberAccess),
#[serde(rename = "IndexAccess")]
IndexAccess(IndexAccess),
#[serde(rename = "BinaryOperation")]
BinaryOperation(BinaryOperation),
#[serde(rename = "Identifier")]
Identifier(Identifier),
#[serde(rename = "Literal")]
Literal(Literal),
#[serde(rename = "Block")]
Block(Block),
#[serde(rename = "EmitStatement")]
EmitStatement(EmitStatement),
#[serde(rename = "RevertStatement")]
RevertStatement(RevertStatement),
#[serde(rename = "VariableDeclaration")]
VariableDeclaration(VariableDeclaration),
#[serde(other)]
Other,
}
impl AstNode {
pub fn get_type_string(&self) -> Option<String> {
match self {
AstNode::Identifier(id) => id.type_descriptions.as_ref().map(|t| t.type_string.clone()),
AstNode::Literal(lit) => lit
.type_descriptions
.as_ref()
.map(|t| t.type_string.clone()),
AstNode::MemberAccess(ma) => {
ma.type_descriptions.as_ref().map(|t| t.type_string.clone())
}
AstNode::BinaryOperation(bo) => bo.common_type.as_ref().map(|t| t.type_string.clone()),
_ => None,
}
}
}