parent
5bc9ee73b2
commit
d5ebff42e4
|
@ -16,9 +16,9 @@ use crate::{
|
|||
BytecodeOutputSelection, ContractOutputSelection, EvmOutputSelection,
|
||||
EwasmOutputSelection,
|
||||
},
|
||||
Ast, CompactContractBytecodeCow, DevDoc, Evm, Ewasm, FunctionDebugData, GasEstimates,
|
||||
GeneratedSource, LosslessAbi, LosslessMetadata, Metadata, Offsets, Settings, StorageLayout,
|
||||
UserDoc,
|
||||
CompactContractBytecodeCow, DevDoc, Evm, Ewasm, FunctionDebugData, GasEstimates,
|
||||
GeneratedSource, LosslessAbi, LosslessMetadata, Metadata, Offsets, Settings, SourceUnit,
|
||||
StorageLayout, UserDoc,
|
||||
},
|
||||
sources::VersionedSourceFile,
|
||||
ArtifactOutput, SolcConfig, SolcError, SourceFile,
|
||||
|
@ -68,7 +68,7 @@ pub struct ConfigurableContractArtifact {
|
|||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub ewasm: Option<Ewasm>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub ast: Option<Ast>,
|
||||
pub ast: Option<SourceUnit>,
|
||||
/// The identifier of the source file
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub id: Option<u32>,
|
||||
|
|
|
@ -0,0 +1,56 @@
|
|||
/// Macro that expands to a struct with common AST node fields.
|
||||
macro_rules! ast_node {
|
||||
(
|
||||
$(#[$struct_meta:meta])*
|
||||
struct $name:ident {
|
||||
$(
|
||||
$(#[$field_meta:meta])*
|
||||
$field:ident: $ty:ty
|
||||
),* $(,)*
|
||||
}
|
||||
) => {
|
||||
$(#[$struct_meta])*
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct $name {
|
||||
pub id: usize,
|
||||
#[serde(with = "serde_helpers::display_from_str")]
|
||||
pub src: SourceLocation,
|
||||
$(
|
||||
$(#[$field_meta])*
|
||||
pub $field: $ty
|
||||
),*
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/// A macro that expands to a struct with common expression node fields.
|
||||
macro_rules! expr_node {
|
||||
(
|
||||
$(#[$struct_meta:meta])*
|
||||
struct $name:ident {
|
||||
$(
|
||||
$(#[$field_meta:meta])*
|
||||
$field:ident: $ty:ty
|
||||
),* $(,)*
|
||||
}
|
||||
) => {
|
||||
ast_node!(
|
||||
$(#[$struct_meta])*
|
||||
struct $name {
|
||||
argument_types: Vec<TypeDescriptions>,
|
||||
is_constant: bool,
|
||||
is_l_value: bool,
|
||||
is_pure: bool,
|
||||
l_value_requested: bool,
|
||||
type_descriptions: TypeDescriptions,
|
||||
$(
|
||||
$(#[$field_meta])*
|
||||
$field: $ty
|
||||
),*
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) use ast_node;
|
||||
pub(crate) use expr_node;
|
|
@ -1,63 +1,5 @@
|
|||
//! Bindings for solc's `ast` output field
|
||||
|
||||
use crate::artifacts::serde_helpers;
|
||||
use serde::{de::DeserializeOwned, Deserialize, Serialize};
|
||||
use std::{collections::BTreeMap, fmt, fmt::Write, str::FromStr};
|
||||
|
||||
/// Represents the AST field in the solc output
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct Ast {
|
||||
#[serde(rename = "absolutePath")]
|
||||
pub absolute_path: String,
|
||||
pub id: usize,
|
||||
#[serde(default, rename = "exportedSymbols")]
|
||||
pub exported_symbols: BTreeMap<String, Vec<usize>>,
|
||||
#[serde(rename = "nodeType")]
|
||||
pub node_type: NodeType,
|
||||
#[serde(with = "serde_helpers::display_from_str")]
|
||||
pub src: SourceLocation,
|
||||
#[serde(default)]
|
||||
pub nodes: Vec<Node>,
|
||||
|
||||
/// Node attributes that were not deserialized.
|
||||
#[serde(flatten)]
|
||||
pub other: BTreeMap<String, serde_json::Value>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct Node {
|
||||
/// The node ID.
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub id: Option<usize>,
|
||||
|
||||
/// The node type.
|
||||
#[serde(rename = "nodeType")]
|
||||
pub node_type: NodeType,
|
||||
|
||||
/// The location of the node in the source file.
|
||||
#[serde(with = "serde_helpers::display_from_str")]
|
||||
pub src: SourceLocation,
|
||||
|
||||
/// Child nodes for some node types.
|
||||
#[serde(default)]
|
||||
pub nodes: Vec<Node>,
|
||||
|
||||
/// Body node for some node types.
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub body: Option<Box<Node>>,
|
||||
|
||||
/// Node attributes that were not deserialized.
|
||||
#[serde(flatten)]
|
||||
pub other: BTreeMap<String, serde_json::Value>,
|
||||
}
|
||||
|
||||
impl Node {
|
||||
/// Deserialize a serialized node attribute.
|
||||
pub fn attribute<D: DeserializeOwned>(&self, key: impl AsRef<str>) -> Option<D> {
|
||||
// TODO: Can we avoid this clone?
|
||||
self.other.get(key.as_ref()).and_then(|v| serde_json::from_value(v.clone()).ok())
|
||||
}
|
||||
}
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::{fmt, fmt::Write, str::FromStr};
|
||||
|
||||
/// Represents the source location of a node: `<start byte>:<length>:<source index>`.
|
||||
///
|
||||
|
@ -119,8 +61,7 @@ impl fmt::Display for SourceLocation {
|
|||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub enum NodeType {
|
||||
// Expressions
|
||||
pub enum Expression {
|
||||
Assignment,
|
||||
BinaryOperation,
|
||||
Conditional,
|
||||
|
@ -135,8 +76,50 @@ pub enum NodeType {
|
|||
NewExpression,
|
||||
TupleExpression,
|
||||
UnaryOperation,
|
||||
}
|
||||
|
||||
// Statements
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub enum StateMutability {
|
||||
Payable,
|
||||
Pure,
|
||||
Nonpayable,
|
||||
View,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub enum TypeName {
|
||||
ArrayTypeName,
|
||||
ElementaryTypeName,
|
||||
FunctionTypeName,
|
||||
Mapping,
|
||||
UserDefinedTypeName,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub enum Mutability {
|
||||
Mutable,
|
||||
Immutable,
|
||||
Constant,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub enum StorageLocation {
|
||||
Calldata,
|
||||
Default,
|
||||
Memory,
|
||||
Storage,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub enum Visibility {
|
||||
External,
|
||||
Public,
|
||||
Internal,
|
||||
Private,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub enum Statement {
|
||||
Block,
|
||||
Break,
|
||||
Continue,
|
||||
|
@ -152,10 +135,11 @@ pub enum NodeType {
|
|||
TryStatement,
|
||||
UncheckedBlock,
|
||||
VariableDeclarationStatement,
|
||||
VariableDeclaration,
|
||||
WhileStatement,
|
||||
}
|
||||
|
||||
// Yul statements
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub enum YulStatement {
|
||||
YulAssignment,
|
||||
YulBlock,
|
||||
YulBreak,
|
||||
|
@ -167,51 +151,17 @@ pub enum NodeType {
|
|||
YulIf,
|
||||
YulSwitch,
|
||||
YulVariableDeclaration,
|
||||
}
|
||||
|
||||
// Yul expressions
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub enum YulExpression {
|
||||
YulFunctionCall,
|
||||
YulIdentifier,
|
||||
YulLiteral,
|
||||
}
|
||||
|
||||
// Yul literals
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub enum YulLiteral {
|
||||
YulLiteralValue,
|
||||
YulHexValue,
|
||||
|
||||
// Definitions
|
||||
ContractDefinition,
|
||||
FunctionDefinition,
|
||||
EventDefinition,
|
||||
ErrorDefinition,
|
||||
ModifierDefinition,
|
||||
StructDefinition,
|
||||
EnumDefinition,
|
||||
UserDefinedValueTypeDefinition,
|
||||
|
||||
// Directives
|
||||
PragmaDirective,
|
||||
ImportDirective,
|
||||
UsingForDirective,
|
||||
|
||||
// Misc
|
||||
SourceUnit,
|
||||
InheritanceSpecifier,
|
||||
ElementaryTypeName,
|
||||
FunctionTypeName,
|
||||
ParameterList,
|
||||
TryCatchClause,
|
||||
ModifierInvocation,
|
||||
|
||||
/// An unknown AST node type.
|
||||
Other(String),
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn can_parse_ast() {
|
||||
let ast = include_str!("../../test-data/ast/ast-erc4626.json");
|
||||
let _ast: Ast = serde_json::from_str(ast).unwrap();
|
||||
}
|
||||
YulLiteralHexValue,
|
||||
}
|
|
@ -0,0 +1,248 @@
|
|||
//! Bindings for solc's `ast` output field
|
||||
mod macros;
|
||||
mod misc;
|
||||
|
||||
pub use misc::*;
|
||||
pub mod util;
|
||||
pub mod visitor;
|
||||
|
||||
use crate::artifacts::serde_helpers;
|
||||
use macros::{ast_node, expr_node};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
// TODO: Node ID
|
||||
|
||||
ast_node!(
|
||||
/// The root node of a Solidity AST.
|
||||
struct SourceUnit {
|
||||
#[serde(rename = "absolutePath")]
|
||||
absolute_path: String,
|
||||
#[serde(default, rename = "exportedSymbols")]
|
||||
exported_symbols: BTreeMap<String, Vec<usize>>,
|
||||
license: Option<String>,
|
||||
#[serde(default, skip_serializing_if = "Vec::is_empty")]
|
||||
nodes: Vec<SourceUnitPart>,
|
||||
}
|
||||
);
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub enum SourceUnitPart {
|
||||
PragmaDirective,
|
||||
ImportDirective,
|
||||
UsingForDirective,
|
||||
VariableDeclaration,
|
||||
EnumDefinition,
|
||||
ErrorDefinition,
|
||||
FunctionDefinition,
|
||||
StructDefinition,
|
||||
UserDefinedValueTypeDefinition,
|
||||
ContractDefinition,
|
||||
}
|
||||
|
||||
ast_node!(
|
||||
struct ContractDefinition {
|
||||
name: String,
|
||||
name_location: Option<String>,
|
||||
is_abstract: bool,
|
||||
base_contracts: Vec<InheritanceSpecifier>,
|
||||
canonical_name: Option<String>,
|
||||
contract_dependencies: Vec<usize>,
|
||||
kind: ContractKind,
|
||||
documentation: Option<StructuredDocumentation>,
|
||||
fully_implemented: bool,
|
||||
linearized_base_contracts: Vec<usize>,
|
||||
nodes: Vec<ContractDefinitionPart>,
|
||||
scope: usize,
|
||||
used_errors: Vec<usize>,
|
||||
}
|
||||
);
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub enum ContractKind {
|
||||
Contract,
|
||||
Interface,
|
||||
Library,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub enum ContractDefinitionPart {
|
||||
EnumDefinition,
|
||||
ErrorDefinition,
|
||||
EventDefinition,
|
||||
FunctionDefinition,
|
||||
ModifierDefinition,
|
||||
StructDefinition,
|
||||
UserDefinedValueTypeDefinition,
|
||||
UsingForDirective,
|
||||
VariableDeclaration,
|
||||
}
|
||||
|
||||
ast_node!(
|
||||
struct InheritanceSpecifier {
|
||||
arguments: Vec<Expression>,
|
||||
base_name: UserDefinedTypeNameOrIdentifierPath,
|
||||
}
|
||||
);
|
||||
|
||||
// TODO: Better name
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub enum UserDefinedTypeNameOrIdentifierPath {
|
||||
UserDefinedTypeName,
|
||||
IdentifierPath,
|
||||
}
|
||||
|
||||
expr_node!(
|
||||
struct Assignment {
|
||||
lhs: Expression,
|
||||
operator: AssignmentOperator,
|
||||
rhs: Expression,
|
||||
}
|
||||
);
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub enum AssignmentOperator {
|
||||
/// =
|
||||
Assign,
|
||||
/// +=
|
||||
AddAssign,
|
||||
/// -=
|
||||
SubAssign,
|
||||
/// *=
|
||||
MulAssign,
|
||||
/// /=
|
||||
DivAssign,
|
||||
/// %=
|
||||
ModAssign,
|
||||
/// |=
|
||||
OrAssign,
|
||||
/// &=
|
||||
AndAssign,
|
||||
/// ^=
|
||||
XorAssign,
|
||||
/// >>=
|
||||
ShrAssign,
|
||||
/// <<=
|
||||
ShlAssign,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct TypeDescriptions {
|
||||
pub type_identifier: Option<String>,
|
||||
pub type_string: Option<String>,
|
||||
}
|
||||
|
||||
ast_node!(
|
||||
struct BinaryOperation {
|
||||
common_type: TypeDescriptions,
|
||||
lhs: Expression,
|
||||
operator: BinaryOperator,
|
||||
rhs: Expression,
|
||||
}
|
||||
);
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub enum BinaryOperator {
|
||||
/// +
|
||||
Add,
|
||||
/// -
|
||||
Sub,
|
||||
/// *
|
||||
Mul,
|
||||
/// /
|
||||
Div,
|
||||
/// %
|
||||
Mod,
|
||||
/// **
|
||||
Pow,
|
||||
/// &&
|
||||
And,
|
||||
/// ||
|
||||
Or,
|
||||
/// !=
|
||||
NotEqual,
|
||||
/// ==
|
||||
Equal,
|
||||
/// <
|
||||
LessThan,
|
||||
/// <=
|
||||
LessThanOrEqual,
|
||||
/// >
|
||||
GreaterThan,
|
||||
/// >=
|
||||
GreaterThanOrEqual,
|
||||
/// ^
|
||||
Xor,
|
||||
/// &
|
||||
BitAnd,
|
||||
/// |
|
||||
BitOr,
|
||||
/// <<
|
||||
Shl,
|
||||
/// >>
|
||||
Shr,
|
||||
}
|
||||
|
||||
expr_node!(
|
||||
struct Conditional {
|
||||
condition: Expression,
|
||||
false_expression: Expression,
|
||||
true_expression: Expression,
|
||||
}
|
||||
);
|
||||
|
||||
expr_node!(
|
||||
struct ElementaryTypeNameExpression {
|
||||
type_name: ElementaryTypeName,
|
||||
}
|
||||
);
|
||||
|
||||
ast_node!(
|
||||
struct ElementaryTypeName {
|
||||
type_descriptions: TypeDescriptions,
|
||||
name: String,
|
||||
state_mutability: Option<StateMutability>,
|
||||
}
|
||||
);
|
||||
|
||||
expr_node!(
|
||||
struct FunctionCall {
|
||||
arguments: Vec<Expression>,
|
||||
expression: Expression,
|
||||
kind: FunctionCallKind,
|
||||
names: Vec<String>,
|
||||
try_call: bool,
|
||||
}
|
||||
);
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub enum FunctionCallKind {
|
||||
FunctionCall,
|
||||
TypeConversion,
|
||||
StructConstructorCall,
|
||||
}
|
||||
|
||||
expr_node!(
|
||||
struct FunctionCallOptions {
|
||||
expression: Expression,
|
||||
names: Vec<String>,
|
||||
options: Vec<Expression>,
|
||||
}
|
||||
);
|
||||
|
||||
ast_node!(
|
||||
struct StructuredDocumentation {
|
||||
text: String,
|
||||
}
|
||||
);
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn can_parse_ast() {
|
||||
let ast = include_str!("../../test-data/ast/ast-erc4626.json");
|
||||
let _ast: SourceUnit = serde_json::from_str(ast).unwrap();
|
||||
}
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
|
|
@ -0,0 +1 @@
|
|||
|
|
@ -1835,7 +1835,7 @@ pub struct SecondarySourceLocation {
|
|||
pub struct SourceFile {
|
||||
pub id: u32,
|
||||
#[serde(default, with = "serde_helpers::empty_json_object_opt")]
|
||||
pub ast: Option<Ast>,
|
||||
pub ast: Option<SourceUnit>,
|
||||
}
|
||||
|
||||
// === impl SourceFile ===
|
||||
|
@ -1846,7 +1846,7 @@ impl SourceFile {
|
|||
pub fn contains_contract_definition(&self) -> bool {
|
||||
if let Some(ref ast) = self.ast {
|
||||
// contract definitions are only allowed at the source-unit level <https://docs.soliditylang.org/en/latest/grammar.html>
|
||||
return ast.nodes.iter().any(|node| node.node_type == NodeType::ContractDefinition)
|
||||
return ast.nodes.iter().any(|node| matches!(node, SourceUnitPart::ContractDefinition))
|
||||
// abstract contract, interfaces: ContractDefinition
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue