diff --git a/Cargo.lock b/Cargo.lock index cc4f6e7b15..cf0acbd2a6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3802,6 +3802,8 @@ dependencies = [ name = "slang_solidity_v2" version = "1.3.4" dependencies = [ + "anyhow", + "slang_solidity_v2_ast", "slang_solidity_v2_common", "slang_solidity_v2_ir", "slang_solidity_v2_parser", @@ -3809,6 +3811,16 @@ dependencies = [ "thiserror 2.0.12", ] +[[package]] +name = "slang_solidity_v2_ast" +version = "1.3.4" +dependencies = [ + "paste", + "sha3", + "slang_solidity_v2_ir", + "slang_solidity_v2_semantic", +] + [[package]] name = "slang_solidity_v2_common" version = "1.3.4" @@ -3829,6 +3841,7 @@ name = "slang_solidity_v2_ir" version = "1.3.4" dependencies = [ "anyhow", + "indexmap", "slang_solidity_v2_common", "slang_solidity_v2_cst", "slang_solidity_v2_parser", diff --git a/Cargo.toml b/Cargo.toml index 377debc743..623ffe6ae4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -52,6 +52,7 @@ members = [ "crates/solidity-v2/inputs/language", + "crates/solidity-v2/outputs/cargo/ast", "crates/solidity-v2/outputs/cargo/common", "crates/solidity-v2/outputs/cargo/cst", "crates/solidity-v2/outputs/cargo/ir", @@ -113,6 +114,7 @@ solidity_testing_utils = { path = "crates/solidity/testing/utils", version = "1. solidity_v2_language = { path = "crates/solidity-v2/inputs/language", version = "1.3.4" } slang_solidity_v2 = { path = "crates/solidity-v2/outputs/cargo/slang_solidity", version = "1.3.4" } +slang_solidity_v2_ast = { path = "crates/solidity-v2/outputs/cargo/ast", version = "1.3.4" } slang_solidity_v2_cst = { path = "crates/solidity-v2/outputs/cargo/cst", version = "1.3.4" } slang_solidity_v2_common = { path = "crates/solidity-v2/outputs/cargo/common", version = "1.3.4" } slang_solidity_v2_ir = { path = "crates/solidity-v2/outputs/cargo/ir", version = "1.3.4" } diff --git a/crates/codegen/runner/src/main.rs b/crates/codegen/runner/src/main.rs index f23437b249..f4273c4514 100644 --- a/crates/codegen/runner/src/main.rs +++ b/crates/codegen/runner/src/main.rs @@ -44,6 +44,13 @@ fn main() { "solidity_npm_package", ) }, + || { + generate_in_place_v2( + &mut CodegenFileSystem::default(), + &SolidityDefinitionV2::create(), + "slang_solidity_v2_ast", + ) + }, || { generate_in_place_v2( &mut CodegenFileSystem::default(), diff --git a/crates/solidity-v2/outputs/cargo/ast/Cargo.toml b/crates/solidity-v2/outputs/cargo/ast/Cargo.toml new file mode 100644 index 0000000000..72756486cc --- /dev/null +++ b/crates/solidity-v2/outputs/cargo/ast/Cargo.toml @@ -0,0 +1,28 @@ +[package] +version.workspace = true +rust-version.workspace = true +edition.workspace = true +publish = false + +name = "slang_solidity_v2_ast" +description = "AST interface for the [slang_solidity](https://crates.io/crates/slang_solidity) crate." +homepage = "https://nomicfoundation.github.io/slang/" +repository = "https://github.com/NomicFoundation/slang/" +authors = [ + "Slang Team ", + "Nomic Foundation ", +] + +readme = "README.md" +license = "MIT" +keywords = ["utilities"] +categories = ["compilers", "utilities"] + +[dependencies] +paste = { workspace = true } +sha3 = { workspace = true } +slang_solidity_v2_ir = { workspace = true } +slang_solidity_v2_semantic = { workspace = true } + +[lints] +workspace = true diff --git a/crates/solidity-v2/outputs/cargo/ast/LICENSE b/crates/solidity-v2/outputs/cargo/ast/LICENSE new file mode 100644 index 0000000000..e19d35d9da --- /dev/null +++ b/crates/solidity-v2/outputs/cargo/ast/LICENSE @@ -0,0 +1,20 @@ +MIT License + +Copyright (c) 2022-2026 Nomic Foundation +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/crates/solidity-v2/outputs/cargo/ast/README.md b/crates/solidity-v2/outputs/cargo/ast/README.md new file mode 100644 index 0000000000..7415e6b872 --- /dev/null +++ b/crates/solidity-v2/outputs/cargo/ast/README.md @@ -0,0 +1,4 @@ +# slang_solidity_v2_semantic + +Semantic analysis for the [slang_solidity](https://crates.io/crates/slang_solidity) crate. +Please see the [NomicFoundation/slang](https://github.com/NomicFoundation/slang/) project for more information. diff --git a/crates/solidity-v2/outputs/cargo/ast/src/abi/mod.rs b/crates/solidity-v2/outputs/cargo/ast/src/abi/mod.rs new file mode 100644 index 0000000000..f3ebbcc9e3 --- /dev/null +++ b/crates/solidity-v2/outputs/cargo/ast/src/abi/mod.rs @@ -0,0 +1,274 @@ +use std::cmp::Ordering; +use std::rc::Rc; + +use sha3::{Digest, Keccak256}; +use slang_solidity_v2_ir::ir::{self, NodeId}; +use slang_solidity_v2_semantic::binder::Definition; +use slang_solidity_v2_semantic::context::SemanticContext; +use slang_solidity_v2_semantic::types::{Type, TypeId}; + +pub struct ContractAbi { + pub node_id: NodeId, + pub name: String, + pub file_id: String, + pub entries: Vec, + pub storage_layout: Vec, + pub transient_storage_layout: Vec, +} + +pub type AbiMutability = ir::FunctionMutability; + +#[derive(Clone, Debug)] +pub enum AbiEntry { + Constructor { + node_id: NodeId, + inputs: Vec, + state_mutability: AbiMutability, + }, + Error { + node_id: NodeId, + name: String, + inputs: Vec, + }, + Event { + node_id: NodeId, + name: String, + inputs: Vec, + anonymous: bool, + }, + Fallback { + node_id: NodeId, + state_mutability: AbiMutability, + }, + Function { + node_id: NodeId, + name: String, + inputs: Vec, + outputs: Vec, + state_mutability: AbiMutability, + }, + Receive { + node_id: NodeId, + state_mutability: AbiMutability, + }, +} + +impl PartialEq for AbiEntry { + fn eq(&self, other: &Self) -> bool { + match (self, other) { + ( + Self::Constructor { + node_id: self_node_id, + .. + }, + Self::Constructor { + node_id: other_node_id, + .. + }, + ) + | ( + Self::Error { + node_id: self_node_id, + .. + }, + Self::Error { + node_id: other_node_id, + .. + }, + ) + | ( + Self::Event { + node_id: self_node_id, + .. + }, + Self::Event { + node_id: other_node_id, + .. + }, + ) + | ( + Self::Fallback { + node_id: self_node_id, + .. + }, + Self::Fallback { + node_id: other_node_id, + .. + }, + ) + | ( + Self::Function { + node_id: self_node_id, + .. + }, + Self::Function { + node_id: other_node_id, + .. + }, + ) + | ( + Self::Receive { + node_id: self_node_id, + .. + }, + Self::Receive { + node_id: other_node_id, + .. + }, + ) => self_node_id == other_node_id, + _ => false, + } + } +} + +impl Eq for AbiEntry {} + +impl Ord for AbiEntry { + fn cmp(&self, other: &Self) -> Ordering { + match (self, other) { + (Self::Constructor { .. }, Self::Constructor { .. }) + | (Self::Fallback { .. }, Self::Fallback { .. }) + | (Self::Receive { .. }, Self::Receive { .. }) => Ordering::Equal, + ( + Self::Error { + name: self_name, .. + }, + Self::Error { + name: other_name, .. + }, + ) + | ( + Self::Event { + name: self_name, .. + }, + Self::Event { + name: other_name, .. + }, + ) + | ( + Self::Function { + name: self_name, .. + }, + Self::Function { + name: other_name, .. + }, + ) => self_name.cmp(other_name), + + (Self::Constructor { .. }, _) => Ordering::Less, + (_, Self::Constructor { .. }) => Ordering::Greater, + (Self::Error { .. }, _) => Ordering::Less, + (_, Self::Error { .. }) => Ordering::Greater, + (Self::Event { .. }, _) => Ordering::Less, + (_, Self::Event { .. }) => Ordering::Greater, + (Self::Fallback { .. }, _) => Ordering::Less, + (_, Self::Fallback { .. }) => Ordering::Greater, + (Self::Function { .. }, _) => Ordering::Less, + (_, Self::Function { .. }) => Ordering::Greater, + } + } +} + +impl PartialOrd for AbiEntry { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} + +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct ParameterComponent { + pub name: String, + pub r#type: String, + pub components: Vec, +} + +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct AbiParameter { + pub node_id: Option, // will be `None` if the function is a generated getter + pub name: Option, + pub r#type: String, + pub components: Vec, + pub indexed: bool, +} + +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct StorageItem { + pub node_id: NodeId, + pub label: String, + pub slot: usize, + pub offset: usize, + pub r#type: String, +} + +pub fn selector_from_signature(signature: &str) -> u32 { + let mut hasher = Keccak256::new(); + hasher.update(signature.as_bytes()); + let result = hasher.finalize(); + + let selector_bytes: [u8; 4] = result[0..4].try_into().unwrap(); + u32::from_be_bytes(selector_bytes) +} + +pub(crate) fn extract_function_type_parameters_abi( + semantic: &Rc, + type_id: TypeId, +) -> Option<(Vec, Vec)> { + let Type::Function(function_type) = semantic.types().get_type_by_id(type_id) else { + return None; + }; + let mut inputs = Vec::new(); + for parameter_type_id in &function_type.parameter_types { + let (r#type, components) = type_as_abi_parameter(semantic, *parameter_type_id)?; + inputs.push(AbiParameter { + node_id: None, + name: None, + r#type, + components, + indexed: false, + }); + } + let (r#type, components) = type_as_abi_parameter(semantic, function_type.return_type)?; + let outputs = vec![AbiParameter { + node_id: None, + name: None, + r#type, + components, + indexed: false, + }]; + Some((inputs, outputs)) +} + +pub(crate) fn type_as_abi_parameter( + semantic: &Rc, + type_id: TypeId, +) -> Option<(String, Vec)> { + match semantic.types().get_type_by_id(type_id) { + Type::Array { element_type, .. } => { + let (element_type_name, element_components) = + type_as_abi_parameter(semantic, *element_type)?; + Some((format!("{element_type_name}[]"), element_components)) + } + Type::Struct { definition_id, .. } => { + // We need to recursively expand the struct fields as components + let Definition::Struct(definition) = semantic + .binder() + .find_definition_by_id(*definition_id) + .expect("the definition of a type exists") + else { + unreachable!("the definition of a struct type is a struct"); + }; + let mut components = Vec::new(); + for member in &definition.ir_node.members { + let name = member.name.unparse(semantic.interner()).to_string(); + let member_type_id = semantic.binder().node_typing(member.id()).as_type_id()?; + let (r#type, subcomponents) = type_as_abi_parameter(semantic, member_type_id)?; + components.push(ParameterComponent { + name, + r#type, + components: subcomponents, + }); + } + Some(("tuple".to_string(), components)) + } + _ => Some((semantic.type_canonical_name(type_id)?, Vec::new())), + } +} diff --git a/crates/solidity-v2/outputs/cargo/ast/src/ast/definitions.rs b/crates/solidity-v2/outputs/cargo/ast/src/ast/definitions.rs new file mode 100644 index 0000000000..8255a4b2a9 --- /dev/null +++ b/crates/solidity-v2/outputs/cargo/ast/src/ast/definitions.rs @@ -0,0 +1,293 @@ +use std::rc::Rc; + +use paste::paste; +use slang_solidity_v2_ir::ir::NodeId; +use slang_solidity_v2_semantic::binder; +use slang_solidity_v2_semantic::context::SemanticContext; + +use super::nodes::{ + create_constant_definition, create_contract_definition, create_enum_definition, + create_error_definition, create_event_definition, create_function_definition, + create_identifier, create_import_deconstruction_symbol, create_interface_definition, + create_library_definition, create_parameter, create_path_import, + create_state_variable_definition, create_struct_definition, create_struct_member, + create_user_defined_value_type_definition, create_variable_declaration, + create_yul_function_definition, ConstantDefinition, ConstantDefinitionStruct, + ContractDefinition, ContractDefinitionStruct, EnumDefinition, EnumDefinitionStruct, + ErrorDefinition, ErrorDefinitionStruct, EventDefinition, EventDefinitionStruct, + FunctionDefinition, FunctionDefinitionStruct, Identifier, ImportDeconstructionSymbol, + ImportDeconstructionSymbolStruct, InterfaceDefinition, InterfaceDefinitionStruct, + LibraryDefinition, LibraryDefinitionStruct, Parameter, ParameterStruct, PathImport, + PathImportStruct, StateVariableDefinition, StateVariableDefinitionStruct, StructDefinition, + StructDefinitionStruct, StructMember, StructMemberStruct, UserDefinedValueTypeDefinition, + UserDefinedValueTypeDefinitionStruct, VariableDeclaration, VariableDeclarationStruct, + YulFunctionDefinition, YulFunctionDefinitionStruct, +}; +use super::references::{references_binding_to_definition, Reference}; + +// __SLANG_DEFINITION_TYPES__ keep in sync with binder +#[derive(Clone)] +pub enum Definition { + Constant(ConstantDefinition), + Contract(ContractDefinition), + Enum(EnumDefinition), + EnumMember(Identifier), + Error(ErrorDefinition), + Event(EventDefinition), + Function(FunctionDefinition), + Import(PathImport), + ImportedSymbol(ImportDeconstructionSymbol), + Interface(InterfaceDefinition), + Library(LibraryDefinition), + Modifier(FunctionDefinition), + Parameter(Parameter), + StateVariable(StateVariableDefinition), + Struct(StructDefinition), + StructMember(StructMember), + TypeParameter(Parameter), + UserDefinedValueType(UserDefinedValueTypeDefinition), + Variable(VariableDeclaration), + YulFunction(YulFunctionDefinition), + YulParameter(Identifier), + YulVariable(Identifier), +} + +impl Definition { + pub fn try_create(definition_id: NodeId, semantic: &Rc) -> Option { + let definition = semantic.binder().find_definition_by_id(definition_id)?; + + let definition = match definition { + binder::Definition::Constant(constant_definition) => Self::Constant( + create_constant_definition(&constant_definition.ir_node, semantic), + ), + binder::Definition::Contract(contract_definition) => Self::Contract( + create_contract_definition(&contract_definition.ir_node, semantic), + ), + binder::Definition::Enum(enum_definition) => { + Self::Enum(create_enum_definition(&enum_definition.ir_node, semantic)) + } + binder::Definition::EnumMember(enum_member_definition) => { + Self::EnumMember(create_identifier(&enum_member_definition.ir_node, semantic)) + } + binder::Definition::Error(error_definition) => { + Self::Error(create_error_definition(&error_definition.ir_node, semantic)) + } + binder::Definition::Event(event_definition) => { + Self::Event(create_event_definition(&event_definition.ir_node, semantic)) + } + binder::Definition::Function(function_definition) => Self::Function( + create_function_definition(&function_definition.ir_node, semantic), + ), + binder::Definition::Import(import_definition) => { + Self::Import(create_path_import(&import_definition.ir_node, semantic)) + } + binder::Definition::ImportedSymbol(imported_symbol_definition) => Self::ImportedSymbol( + create_import_deconstruction_symbol(&imported_symbol_definition.ir_node, semantic), + ), + binder::Definition::Interface(interface_definition) => Self::Interface( + create_interface_definition(&interface_definition.ir_node, semantic), + ), + binder::Definition::Library(library_definition) => Self::Library( + create_library_definition(&library_definition.ir_node, semantic), + ), + binder::Definition::Modifier(modifier_definition) => Self::Modifier( + create_function_definition(&modifier_definition.ir_node, semantic), + ), + binder::Definition::Parameter(parameter_definition) => { + Self::Parameter(create_parameter(¶meter_definition.ir_node, semantic)) + } + binder::Definition::StateVariable(state_variable_definition) => Self::StateVariable( + create_state_variable_definition(&state_variable_definition.ir_node, semantic), + ), + binder::Definition::Struct(struct_definition) => Self::Struct( + create_struct_definition(&struct_definition.ir_node, semantic), + ), + binder::Definition::StructMember(struct_member_definition) => Self::StructMember( + create_struct_member(&struct_member_definition.ir_node, semantic), + ), + binder::Definition::TypeParameter(type_parameter_definition) => Self::TypeParameter( + create_parameter(&type_parameter_definition.ir_node, semantic), + ), + binder::Definition::UserDefinedValueType(user_defined_value_type_definition) => { + Self::UserDefinedValueType(create_user_defined_value_type_definition( + &user_defined_value_type_definition.ir_node, + semantic, + )) + } + binder::Definition::Variable(variable_definition) => Self::Variable( + create_variable_declaration(&variable_definition.ir_node, semantic), + ), + binder::Definition::YulFunction(yul_function_definition) => Self::YulFunction( + create_yul_function_definition(&yul_function_definition.ir_node, semantic), + ), + binder::Definition::YulParameter(yul_parameter_definition) => Self::YulParameter( + create_identifier(&yul_parameter_definition.ir_node, semantic), + ), + binder::Definition::YulVariable(yul_variable_definition) => Self::YulVariable( + create_identifier(&yul_variable_definition.ir_node, semantic), + ), + }; + Some(definition) + } + + pub fn node_id(&self) -> NodeId { + match self { + Definition::Constant(constant_definition) => constant_definition.node_id(), + Definition::Contract(contract_definition) => contract_definition.node_id(), + Definition::Enum(enum_definition) => enum_definition.node_id(), + Definition::EnumMember(identifier) => identifier.node_id(), + Definition::Error(error_definition) => error_definition.node_id(), + Definition::Event(event_definition) => event_definition.node_id(), + Definition::Function(function_definition) => function_definition.node_id(), + Definition::Import(path_import) => path_import.node_id(), + Definition::ImportedSymbol(import_deconstruction_symbol) => { + import_deconstruction_symbol.node_id() + } + Definition::Interface(interface_definition) => interface_definition.node_id(), + Definition::Library(library_definition) => library_definition.node_id(), + Definition::Modifier(function_definition) => function_definition.node_id(), + Definition::Parameter(parameter) => parameter.node_id(), + Definition::StateVariable(state_variable_definition) => { + state_variable_definition.node_id() + } + Definition::Struct(struct_definition) => struct_definition.node_id(), + Definition::StructMember(struct_member) => struct_member.node_id(), + Definition::TypeParameter(parameter) => parameter.node_id(), + Definition::UserDefinedValueType(user_defined_value_type_definition) => { + user_defined_value_type_definition.node_id() + } + Definition::Variable(variable_declaration_statement) => { + variable_declaration_statement.node_id() + } + Definition::YulFunction(yul_function_definition) => yul_function_definition.node_id(), + Definition::YulParameter(identifier) => identifier.node_id(), + Definition::YulVariable(identifier) => identifier.node_id(), + } + } + + pub fn identifier(&self) -> Identifier { + match self { + Definition::Constant(constant_definition) => constant_definition.name(), + Definition::Contract(contract_definition) => contract_definition.name(), + Definition::Enum(enum_definition) => enum_definition.name(), + Definition::EnumMember(identifier) => Rc::clone(identifier), + Definition::Error(error_definition) => error_definition.name(), + Definition::Event(event_definition) => event_definition.name(), + Definition::Function(function_definition) => { + // functions that are definitions always have a name + function_definition + .name() + .expect("function definitions have a name") + } + Definition::Import(path_import) => { + // imports that are definition always have a name + path_import + .alias() + .expect("path import definitions have a name") + } + Definition::ImportedSymbol(import_deconstruction_symbol) => { + import_deconstruction_symbol + .alias() + .unwrap_or_else(|| import_deconstruction_symbol.name()) + } + Definition::Interface(interface_definition) => interface_definition.name(), + Definition::Library(library_definition) => library_definition.name(), + Definition::Modifier(function_definition) => { + // modifiers always have a name + function_definition.name().expect("modifiers have a name") + } + Definition::Parameter(parameter) => { + // parameters that are definitions always have a name + parameter.name().expect("parameter definitions have a name") + } + Definition::StateVariable(state_variable_definition) => { + state_variable_definition.name() + } + Definition::Struct(struct_definition) => struct_definition.name(), + Definition::StructMember(struct_member) => struct_member.name(), + Definition::TypeParameter(parameter) => { + // parameters that are definitions always have a name + parameter + .name() + .expect("type parameter definitions have a name") + } + Definition::UserDefinedValueType(user_defined_value_type_definition) => { + user_defined_value_type_definition.name() + } + Definition::Variable(variable_declaration_statement) => { + variable_declaration_statement.name() + } + Definition::YulFunction(yul_function_definition) => yul_function_definition.name(), + Definition::YulParameter(identifier) => Rc::clone(identifier), + Definition::YulVariable(identifier) => Rc::clone(identifier), + } + } + + pub fn references(&self) -> Vec { + match self { + Definition::Constant(constant_definition) => constant_definition.references(), + Definition::Contract(contract_definition) => contract_definition.references(), + Definition::Enum(enum_definition) => enum_definition.references(), + Definition::EnumMember(identifier) => identifier.references(), + Definition::Error(error_definition) => error_definition.references(), + Definition::Event(event_definition) => event_definition.references(), + Definition::Function(function_definition) => function_definition.references(), + Definition::Import(path_import) => path_import.references(), + Definition::ImportedSymbol(import_deconstruction_symbol) => { + import_deconstruction_symbol.references() + } + Definition::Interface(interface_definition) => interface_definition.references(), + Definition::Library(library_definition) => library_definition.references(), + Definition::Modifier(function_definition) => function_definition.references(), + Definition::Parameter(parameter) => parameter.references(), + Definition::StateVariable(state_variable_definition) => { + state_variable_definition.references() + } + Definition::Struct(struct_definition) => struct_definition.references(), + Definition::StructMember(struct_member) => struct_member.references(), + Definition::TypeParameter(parameter) => parameter.references(), + Definition::UserDefinedValueType(user_defined_value_type_definition) => { + user_defined_value_type_definition.references() + } + Definition::Variable(variable_declaration) => variable_declaration.references(), + Definition::YulFunction(yul_function_definition) => { + yul_function_definition.references() + } + Definition::YulParameter(identifier) => identifier.references(), + Definition::YulVariable(identifier) => identifier.references(), + } + } +} + +macro_rules! define_references_method { + ($type:ident) => { + paste! { + impl [<$type Struct>] { + pub fn references(&self) -> Vec { + references_binding_to_definition(self.ir_node.id(), &self.semantic) + } + pub fn as_definition(&self) -> Option { + Definition::try_create(self.ir_node.id(), &self.semantic) + } + } + } + }; +} + +define_references_method!(ConstantDefinition); +define_references_method!(ContractDefinition); +define_references_method!(EnumDefinition); +define_references_method!(ErrorDefinition); +define_references_method!(EventDefinition); +define_references_method!(FunctionDefinition); +define_references_method!(ImportDeconstructionSymbol); +define_references_method!(InterfaceDefinition); +define_references_method!(LibraryDefinition); +define_references_method!(Parameter); +define_references_method!(PathImport); +define_references_method!(StateVariableDefinition); +define_references_method!(StructDefinition); +define_references_method!(StructMember); +define_references_method!(UserDefinedValueTypeDefinition); +define_references_method!(VariableDeclaration); +define_references_method!(YulFunctionDefinition); diff --git a/crates/solidity-v2/outputs/cargo/ast/src/ast/mod.rs b/crates/solidity-v2/outputs/cargo/ast/src/ast/mod.rs new file mode 100644 index 0000000000..67bf72ac5c --- /dev/null +++ b/crates/solidity-v2/outputs/cargo/ast/src/ast/mod.rs @@ -0,0 +1,18 @@ +mod definitions; +pub use definitions::Definition; + +mod node_extensions; +pub use node_extensions::*; + +#[path = "nodes.generated.rs"] +mod nodes; +pub use nodes::*; + +mod references; +pub use references::Reference; + +mod types; +pub use types::Type; + +#[path = "visitor.generated.rs"] +pub mod visitor; diff --git a/crates/solidity-v2/outputs/cargo/ast/src/ast/node_extensions/contracts.rs b/crates/solidity-v2/outputs/cargo/ast/src/ast/node_extensions/contracts.rs new file mode 100644 index 0000000000..3b18c0effe --- /dev/null +++ b/crates/solidity-v2/outputs/cargo/ast/src/ast/node_extensions/contracts.rs @@ -0,0 +1,388 @@ +use std::cmp::Ordering; +use std::ops::Div; +use std::rc::Rc; + +use slang_solidity_v2_semantic::binder; +use slang_solidity_v2_semantic::context::SemanticContext; + +use super::super::{ + ContractDefinition, ContractDefinitionStruct, ContractMember, ContractMembersStruct, + Definition, ErrorDefinition, EventDefinition, FunctionDefinition, FunctionKind, + InterfaceDefinition, InterfaceMembersStruct, StateVariableDefinition, +}; +use crate::abi::{AbiEntry, ContractAbi, StorageItem}; +use crate::ast::StateVariableMutability; + +pub enum ContractBase { + Contract(ContractDefinition), + Interface(InterfaceDefinition), +} + +impl ContractBase { + fn from_definition(definition: &Definition) -> Option { + match definition { + Definition::Contract(contract) => Some(Self::Contract(Rc::clone(contract))), + Definition::Interface(interface) => Some(Self::Interface(Rc::clone(interface))), + _ => None, + } + } +} + +impl ContractDefinitionStruct { + pub fn direct_bases(&self) -> Vec { + self.inheritance_types() + .iter() + .filter_map(|inheritance_type| { + let base = inheritance_type.type_name().resolve_to_definition()?; + ContractBase::from_definition(&base) + }) + .collect() + } + + /// Returns the list of contracts/interfaces in the hierarchy (including + /// self) in the order given by the C3 linearisation, with self contract + /// always first + pub fn compute_linearised_bases(&self) -> Vec { + let Some(base_node_ids) = self + .semantic + .binder() + .get_linearised_bases(self.ir_node.id()) + else { + // TODO(validation): once we have validation implemented, this + // branch should not be reachable, or we should generate an error + // while building the `SemanticAnalysis`. + return Vec::new(); + }; + base_node_ids + .iter() + .map(|node_id| { + let base_definition = + Definition::try_create(*node_id, &self.semantic).expect("node is a definition"); + ContractBase::from_definition(&base_definition) + .expect("Linearised base is either a contract or interface") + }) + .collect() + } + + pub fn state_variables(&self) -> Vec { + self.members().iter_state_variable_definitions().collect() + } + + /// Returns the list of state variable definitions in the order laid out in storage + pub fn compute_linearised_state_variables(&self) -> Vec { + let mut state_variables = Vec::new(); + let bases = self.compute_linearised_bases(); + for base in bases.iter().rev() { + let ContractBase::Contract(contract) = base else { + continue; + }; + state_variables.extend(contract.members().iter_state_variable_definitions()); + } + state_variables + } + + pub fn functions(&self) -> Vec { + self.members() + .iter_function_definitions() + .filter(|function| { + matches!( + function.kind(), + FunctionKind::Regular | FunctionKind::Fallback | FunctionKind::Receive + ) + }) + .collect() + } + + pub fn modifiers(&self) -> Vec { + self.members() + .iter_function_definitions() + .filter(|function| matches!(function.kind(), FunctionKind::Modifier)) + .collect() + } + + pub fn constructor(&self) -> Option { + self.members() + .iter_function_definitions() + .find(|function| matches!(function.kind(), FunctionKind::Constructor)) + } + + /// Returns the list of functions defined in all the hierarchy of the + /// contract, in alphabetical order + pub fn compute_linearised_functions(&self) -> Vec { + let mut functions: Vec = Vec::new(); + let bases = self.compute_linearised_bases(); + for base in &bases { + // TODO(validation): we don't pick up functions defined in + // interfaces because they should be implemented in inheriting + // contracts, but this is not yet enforced anywhere + let ContractBase::Contract(contract) = base else { + continue; + }; + + // Handle function overriding + let contract_functions = contract + .functions() + .into_iter() + .filter(|function| { + // check the existing functions and remove any duplicates + // because they should be overridden by them + let existing = functions + .iter() + .any(|linearised_function| linearised_function.overrides(function)); + !existing + }) + // collect to avoid holding the read-borrow on `functions` + .collect::>(); + + functions.extend(contract_functions); + } + + // sort returned functions by name + functions.sort_by(|a, b| match (a.name(), b.name()) { + (None, None) => Ordering::Equal, + (None, Some(_)) => Ordering::Less, + (Some(_), None) => Ordering::Greater, + (Some(a), Some(b)) => a.name().cmp(&b.name()), + }); + functions + } + + pub fn errors(&self) -> Vec { + self.members().iter_error_definitions().collect() + } + + pub fn compute_linearised_errors(&self) -> Vec { + let mut errors = Vec::new(); + let bases = self.compute_linearised_bases(); + for base in bases.iter().rev() { + match base { + ContractBase::Contract(contract) => { + errors.extend(contract.members().iter_error_definitions()); + } + ContractBase::Interface(interface) => { + errors.extend(interface.members().iter_error_definitions()); + } + } + } + errors + } + + pub fn events(&self) -> Vec { + self.members().iter_event_definitions().collect() + } + + pub fn compute_linearised_events(&self) -> Vec { + let mut events = Vec::new(); + let bases = self.compute_linearised_bases(); + for base in bases.iter().rev() { + match base { + ContractBase::Contract(contract) => { + events.extend(contract.members().iter_event_definitions()); + } + ContractBase::Interface(interface) => { + events.extend(interface.members().iter_event_definitions()); + } + } + } + events + } +} + +// ABI related extensions +impl ContractDefinitionStruct { + // TODO: ideally the user wouldn't need to provide the file_id and we should + // be able to obtain it here, but for that we need bi-directional tree + // navigation + pub fn compute_abi_with_file_id(&self, file_id: String) -> Option { + let name = self + .ir_node + .name + .unparse(self.semantic.interner()) + .to_string(); + let entries = self.compute_abi_entries()?; + let (storage_layout, transient_storage_layout) = self.compute_storage_layout()?; + Some(ContractAbi { + node_id: self.ir_node.id(), + name, + file_id, + entries, + storage_layout, + transient_storage_layout, + }) + } + + fn compute_abi_entries(&self) -> Option> { + let mut entries = Vec::new(); + if let Some(constructor) = self.constructor() { + entries.push(constructor.compute_abi_entry()?); + } + for function in &self.compute_linearised_functions() { + if function.is_externally_visible() { + entries.push(function.compute_abi_entry()?); + } + } + for state_variable in &self.compute_linearised_state_variables() { + if state_variable.is_externally_visible() { + entries.push(state_variable.compute_abi_entry()?); + } + } + for error in &self.compute_linearised_errors() { + entries.push(error.compute_abi_entry()?); + } + for event in &self.compute_linearised_events() { + entries.push(event.compute_abi_entry()?); + } + + entries.sort(); + Some(entries) + } + + /// Retrieves the custom base slot for this contract, if specified. This is + /// used for computing the base of the storage layout for non-transient + /// state variables. + fn base_slot(&self) -> Option { + let binder::Definition::Contract(definition) = self + .semantic + .binder() + .find_definition_by_id(self.ir_node.id())? + else { + unreachable!("definition is not a contract"); + }; + definition.base_slot + } + + /// Computes the layouts of both permanent and transient state variables + fn compute_storage_layout(&self) -> Option<(Vec, Vec)> { + let all_state_variables = self.compute_linearised_state_variables(); + + // TODO(validation): it is an error if any contract in the hierarchy + // other than the leaf has a custom offset layout + let storage_layout = self.lay_out_state_variables( + self.base_slot().unwrap_or_default() * SemanticContext::SLOT_SIZE, + all_state_variables.iter().filter(|state_variable| { + matches!( + state_variable.mutability(), + StateVariableMutability::Mutable + ) + }), + )?; + let transient_storage_layout = self.lay_out_state_variables( + 0usize, + all_state_variables.iter().filter(|state_variable| { + matches!( + state_variable.mutability(), + StateVariableMutability::Transient + ) + }), + )?; + Some((storage_layout, transient_storage_layout)) + } + + fn lay_out_state_variables<'a>( + &self, + base_ptr: usize, + variables: impl Iterator, + ) -> Option> { + let mut storage_layout = Vec::new(); + let mut ptr: usize = base_ptr; + for state_variable in variables { + let node_id = state_variable.ir_node.id(); + let variable_type_id = self.semantic.binder().node_typing(node_id).as_type_id()?; + let variable_size = self.semantic.storage_size_of_type_id(variable_type_id)?; + + // check if we can pack the variable in the previous slot + let remaining_bytes = SemanticContext::SLOT_SIZE - (ptr % SemanticContext::SLOT_SIZE); + if remaining_bytes < SemanticContext::SLOT_SIZE && variable_size > remaining_bytes { + ptr += remaining_bytes; + } + + let label = state_variable + .ir_node + .name + .unparse(self.semantic.interner()) + .to_string(); + let slot = ptr.div(SemanticContext::SLOT_SIZE); + let offset = ptr % SemanticContext::SLOT_SIZE; + let r#type = self.semantic.type_internal_name(variable_type_id); + storage_layout.push(StorageItem { + node_id, + label, + slot, + offset, + r#type, + }); + + // ready pointer for the next variable + ptr += variable_size; + } + Some(storage_layout) + } +} + +impl ContractMembersStruct { + pub(crate) fn iter_function_definitions( + &self, + ) -> impl Iterator + use<'_> { + self.iter().filter_map(|member| { + if let ContractMember::FunctionDefinition(function) = member { + Some(function) + } else { + None + } + }) + } + + pub(crate) fn iter_state_variable_definitions( + &self, + ) -> impl Iterator + use<'_> { + self.iter().filter_map(|member| { + if let ContractMember::StateVariableDefinition(state_variable) = member { + Some(state_variable) + } else { + None + } + }) + } + + pub(crate) fn iter_error_definitions(&self) -> impl Iterator + use<'_> { + self.iter().filter_map(|member| { + if let ContractMember::ErrorDefinition(error_definition) = member { + Some(error_definition) + } else { + None + } + }) + } + + pub(crate) fn iter_event_definitions(&self) -> impl Iterator + use<'_> { + self.iter().filter_map(|member| { + if let ContractMember::EventDefinition(event_definition) = member { + Some(event_definition) + } else { + None + } + }) + } +} + +impl InterfaceMembersStruct { + pub(crate) fn iter_error_definitions(&self) -> impl Iterator + use<'_> { + self.iter().filter_map(|member| { + if let ContractMember::ErrorDefinition(error_definition) = member { + Some(error_definition) + } else { + None + } + }) + } + + pub(crate) fn iter_event_definitions(&self) -> impl Iterator + use<'_> { + self.iter().filter_map(|member| { + if let ContractMember::EventDefinition(event_definition) = member { + Some(event_definition) + } else { + None + } + }) + } +} diff --git a/crates/solidity-v2/outputs/cargo/ast/src/ast/node_extensions/errors.rs b/crates/solidity-v2/outputs/cargo/ast/src/ast/node_extensions/errors.rs new file mode 100644 index 0000000000..cf97ace383 --- /dev/null +++ b/crates/solidity-v2/outputs/cargo/ast/src/ast/node_extensions/errors.rs @@ -0,0 +1,18 @@ +use crate::abi::AbiEntry; +use crate::ast::ErrorDefinitionStruct; + +impl ErrorDefinitionStruct { + pub fn compute_abi_entry(&self) -> Option { + let inputs = self.parameters().compute_abi_parameters()?; + + Some(AbiEntry::Error { + node_id: self.ir_node.id(), + name: self + .ir_node + .name + .unparse(self.semantic.interner()) + .to_string(), + inputs, + }) + } +} diff --git a/crates/solidity-v2/outputs/cargo/ast/src/ast/node_extensions/events.rs b/crates/solidity-v2/outputs/cargo/ast/src/ast/node_extensions/events.rs new file mode 100644 index 0000000000..b52966938f --- /dev/null +++ b/crates/solidity-v2/outputs/cargo/ast/src/ast/node_extensions/events.rs @@ -0,0 +1,19 @@ +use crate::abi::AbiEntry; +use crate::ast::EventDefinitionStruct; + +impl EventDefinitionStruct { + pub fn compute_abi_entry(&self) -> Option { + let inputs = self.parameters().compute_abi_parameters()?; + + Some(AbiEntry::Event { + node_id: self.ir_node.id(), + name: self + .ir_node + .name + .unparse(self.semantic.interner()) + .to_string(), + inputs, + anonymous: self.ir_node.anonymous_keyword, + }) + } +} diff --git a/crates/solidity-v2/outputs/cargo/ast/src/ast/node_extensions/expressions.rs b/crates/solidity-v2/outputs/cargo/ast/src/ast/node_extensions/expressions.rs new file mode 100644 index 0000000000..3a2c54c336 --- /dev/null +++ b/crates/solidity-v2/outputs/cargo/ast/src/ast/node_extensions/expressions.rs @@ -0,0 +1,23 @@ +use slang_solidity_v2_ir::ir; +use slang_solidity_v2_semantic::binder::Typing; + +use super::super::FunctionCallExpressionStruct; + +impl FunctionCallExpressionStruct { + /// Returns `true` if this call is a type conversion (e.g. `uint256(x)`, + /// `address(y)`) rather than a function call. + pub fn is_type_conversion(&self) -> bool { + match &self.ir_node.operand { + ir::Expression::ElementaryType(_) | ir::Expression::PayableKeyword => true, + ir::Expression::Identifier(terminal) => matches!( + self.semantic.binder().node_typing(terminal.id()), + Typing::MetaType(_) | Typing::UserMetaType(_) + ), + ir::Expression::MemberAccessExpression(mae) => matches!( + self.semantic.binder().node_typing(mae.id()), + Typing::MetaType(_) | Typing::UserMetaType(_) + ), + _ => false, + } + } +} diff --git a/crates/solidity-v2/outputs/cargo/ast/src/ast/node_extensions/functions.rs b/crates/solidity-v2/outputs/cargo/ast/src/ast/node_extensions/functions.rs new file mode 100644 index 0000000000..f6b5190c4f --- /dev/null +++ b/crates/solidity-v2/outputs/cargo/ast/src/ast/node_extensions/functions.rs @@ -0,0 +1,152 @@ +use slang_solidity_v2_ir::ir; + +use super::super::{FunctionDefinition, FunctionDefinitionStruct}; +use crate::abi::{ + selector_from_signature, type_as_abi_parameter, AbiEntry, AbiMutability, AbiParameter, +}; +use crate::ast::{FunctionVisibility, ParametersStruct}; + +impl FunctionDefinitionStruct { + pub(crate) fn overrides(&self, other: &FunctionDefinition) -> bool { + let name_matches = match (&self.ir_node.name, &other.ir_node.name) { + (None, None) => { + // for unnamed functions, we check the kind because `receive` + // and `fallback` may have the same parameters but they are + // different functions + self.ir_node.kind == other.ir_node.kind + } + (Some(name), Some(other_name)) => name.string_id == other_name.string_id, + _ => false, + }; + if !name_matches { + return false; + } + let type_id = self + .semantic + .binder() + .node_typing(self.ir_node.id()) + .as_type_id(); + let other_type_id = self + .semantic + .binder() + .node_typing(other.ir_node.id()) + .as_type_id(); + + match (type_id, other_type_id) { + (Some(type_id), Some(other_type_id)) => self + .semantic + .types() + .type_id_is_function_and_overrides(type_id, other_type_id), + _ => false, + } + + // TODO(validation): check also that the function mutability is stricter than other's + } +} + +// ABI-related extensions +impl FunctionDefinitionStruct { + pub fn is_externally_visible(&self) -> bool { + matches!( + self.visibility(), + FunctionVisibility::Public | FunctionVisibility::External + ) + } + + pub fn compute_abi_entry(&self) -> Option { + if !self.is_externally_visible() { + return None; + } + let inputs = self.parameters().compute_abi_parameters()?; + let outputs = if let Some(returns) = self.returns() { + returns.compute_abi_parameters()? + } else { + Vec::new() + }; + + let node_id = self.ir_node.id(); + let name = self + .ir_node + .name + .as_ref() + .map(|name| name.unparse(self.semantic.interner()).to_string()); + let state_mutability: AbiMutability = self.ir_node.mutability.clone(); + + match self.ir_node.kind { + ir::FunctionKind::Regular => Some(AbiEntry::Function { + node_id, + name: name?, + inputs, + outputs, + state_mutability, + }), + ir::FunctionKind::Constructor => Some(AbiEntry::Constructor { + node_id, + inputs, + state_mutability, + }), + ir::FunctionKind::Fallback => Some(AbiEntry::Fallback { + node_id, + state_mutability, + }), + ir::FunctionKind::Receive => Some(AbiEntry::Receive { + node_id, + state_mutability, + }), + ir::FunctionKind::Modifier => None, + } + } + + pub fn compute_selector(&self) -> Option { + if !self.is_externally_visible() { + return None; + } + let name = self + .ir_node + .name + .as_ref()? + .unparse(self.semantic.interner()); + let signature = format!( + "{name}({parameters})", + parameters = self.parameters().compute_canonical_signature()?, + ); + + Some(selector_from_signature(&signature)) + } +} + +impl ParametersStruct { + pub(crate) fn compute_abi_parameters(&self) -> Option> { + let mut result = Vec::new(); + for parameter in &self.ir_nodes { + let node_id = parameter.id(); + let name = parameter + .name + .as_ref() + .map(|name| name.unparse(self.semantic.interner()).to_string()); + let indexed = parameter.indexed; + // Bail out with `None` if any of the parameters fails typing + let type_id = self.semantic.binder().node_typing(node_id).as_type_id()?; + let (r#type, components) = type_as_abi_parameter(&self.semantic, type_id)?; + result.push(AbiParameter { + node_id: Some(node_id), + name, + r#type, + components, + indexed, + }); + } + Some(result) + } + + pub(crate) fn compute_canonical_signature(&self) -> Option { + let mut result = Vec::new(); + for parameter in &self.ir_nodes { + let node_id = parameter.id(); + // Bail out with `None` if any of the parameters fails typing + let type_id = self.semantic.binder().node_typing(node_id).as_type_id()?; + result.push(self.semantic.type_canonical_name(type_id)?); + } + Some(result.join(",")) + } +} diff --git a/crates/solidity-v2/outputs/cargo/ast/src/ast/node_extensions/identifiers.rs b/crates/solidity-v2/outputs/cargo/ast/src/ast/node_extensions/identifiers.rs new file mode 100644 index 0000000000..7687ca9c1c --- /dev/null +++ b/crates/solidity-v2/outputs/cargo/ast/src/ast/node_extensions/identifiers.rs @@ -0,0 +1,118 @@ +use slang_solidity_v2_ir::ir::NodeId; +use slang_solidity_v2_semantic::binder; +use slang_solidity_v2_semantic::built_ins::BuiltIn; + +use super::super::nodes::{IdentifierPathStruct, IdentifierStruct}; +use crate::ast::references::references_binding_to_definition; +use crate::ast::{Definition, Reference}; + +impl IdentifierStruct { + pub fn node_id(&self) -> NodeId { + self.ir_node.id() + } + + pub fn name(&self) -> String { + self.ir_node.unparse(self.semantic.interner()).to_string() + } + + pub fn is_reference(&self) -> bool { + self.semantic + .binder() + .find_reference_by_identifier_node_id(self.ir_node.id()) + .is_some() + } + + /// Attempts to resolve the identifier to a definition, following symbol + /// aliases (import deconstructions). Returns `None` if the identifier is + /// not acting as a reference, or the reference cannot be resolved. + pub fn resolve_to_definition(&self) -> Option { + let definition_id = self + .semantic + .resolve_reference_identifier_to_definition_id(self.ir_node.id())?; + Definition::try_create(definition_id, &self.semantic) + } + + /// Attempts to resolve the identifier to an immediate definition, without + /// following symbol aliases, possibly returning import deconstruction + /// symbols. If the identifier refers to a direct definition, this is + /// equivalent to `resolve_to_definition()`. Returns `None` if the + /// identifier is not acting as a reference, or the reference cannot be + /// resolved. + pub fn resolve_to_immediate_definition(&self) -> Option { + let definition_id = self + .semantic + .resolve_reference_identifier_to_immediate_definition_id(self.ir_node.id())?; + Definition::try_create(definition_id, &self.semantic) + } + + /// If this identifier resolves to a built-in (e.g. `msg`, `block`, + /// `tx`), returns the corresponding [`BuiltIn`] variant. + pub fn resolve_to_built_in(&self) -> Option { + let reference = self + .semantic + .binder() + .find_reference_by_identifier_node_id(self.ir_node.id())?; + match &reference.resolution { + binder::Resolution::BuiltIn(built_in) => Some(*built_in), + _ => None, + } + } + + /// Returns `true` if the identifier itself is a definition (eg. an enum member) + pub fn is_definition(&self) -> bool { + self.as_definition().is_some() + } + + /// Returns the `Definition` corresponding to this identifier. Panics if the + /// identifier is not a definition by itself, ie. this can only be called + /// safely if `is_definition()` returns `true`. + pub fn as_definition(&self) -> Option { + Definition::try_create(self.ir_node.id(), &self.semantic) + } + + /// Returns `true` if the identifier is a definition itself, or is the name + /// identifier of a definition + pub fn is_name_of_definition(&self) -> bool { + self.semantic + .binder() + .find_definition_by_identifier_node_id(self.ir_node.id()) + .is_some() + } + + // only makes sense if `is_definition()` is true + pub fn references(&self) -> Vec { + references_binding_to_definition(self.ir_node.id(), &self.semantic) + } +} + +impl IdentifierPathStruct { + pub fn name(&self) -> String { + self.ir_nodes + .iter() + .map(|ir_node| ir_node.unparse(self.semantic.interner())) + .collect::>() + .join(".") + } + + /// Attempts to resolve the identifier path to a definition, following + /// symbol aliases (import deconstructions). + pub fn resolve_to_definition(&self) -> Option { + let ir_node = self.ir_nodes.last()?; + let definition_id = self + .semantic + .resolve_reference_identifier_to_definition_id(ir_node.id())?; + Definition::try_create(definition_id, &self.semantic) + } + + /// Attempts to resolve the identifier path to an immediate definition, + /// without following symbol aliases, possibly returning import + /// deconstruction symbols. If the path refers to a direct definition, this + /// is equivalent to `resolve_to_definition`. + pub fn resolve_to_immediate_definition(&self) -> Option { + let ir_node = self.ir_nodes.last()?; + let definition_id = self + .semantic + .resolve_reference_identifier_to_immediate_definition_id(ir_node.id())?; + Definition::try_create(definition_id, &self.semantic) + } +} diff --git a/crates/solidity-v2/outputs/cargo/ast/src/ast/node_extensions/mod.rs b/crates/solidity-v2/outputs/cargo/ast/src/ast/node_extensions/mod.rs new file mode 100644 index 0000000000..f56d71fc24 --- /dev/null +++ b/crates/solidity-v2/outputs/cargo/ast/src/ast/node_extensions/mod.rs @@ -0,0 +1,10 @@ +mod contracts; +pub use contracts::ContractBase; + +mod errors; +mod events; +mod expressions; +mod functions; +mod identifiers; +mod source_unit; +mod state_variables; diff --git a/crates/solidity-v2/outputs/cargo/ast/src/ast/node_extensions/source_unit.rs b/crates/solidity-v2/outputs/cargo/ast/src/ast/node_extensions/source_unit.rs new file mode 100644 index 0000000000..432eb70041 --- /dev/null +++ b/crates/solidity-v2/outputs/cargo/ast/src/ast/node_extensions/source_unit.rs @@ -0,0 +1,35 @@ +use super::super::{ContractDefinition, SourceUnitMember, SourceUnitStruct}; +use crate::abi; + +impl SourceUnitStruct { + pub fn file_id(&self) -> String { + self.semantic.node_id_to_file_id(self.ir_node.id()).unwrap() + } + + pub fn contracts(&self) -> Vec { + self.members() + .iter() + .filter_map(|member| { + if let SourceUnitMember::ContractDefinition(contract) = member { + Some(contract) + } else { + None + } + }) + .collect() + } + + pub fn compute_contracts_abi(&self) -> Vec { + let file_id = self.file_id(); + self.contracts() + .iter() + .filter_map(|contract| { + if contract.abstract_keyword() { + None + } else { + contract.compute_abi_with_file_id(file_id.clone()) + } + }) + .collect() + } +} diff --git a/crates/solidity-v2/outputs/cargo/ast/src/ast/node_extensions/state_variables.rs b/crates/solidity-v2/outputs/cargo/ast/src/ast/node_extensions/state_variables.rs new file mode 100644 index 0000000000..0142d35846 --- /dev/null +++ b/crates/solidity-v2/outputs/cargo/ast/src/ast/node_extensions/state_variables.rs @@ -0,0 +1,62 @@ +use slang_solidity_v2_semantic::binder; + +use crate::abi::{ + extract_function_type_parameters_abi, selector_from_signature, AbiEntry, AbiMutability, + AbiParameter, +}; +use crate::ast::{StateVariableDefinitionStruct, StateVariableVisibility}; + +impl StateVariableDefinitionStruct { + pub fn is_externally_visible(&self) -> bool { + matches!(self.visibility(), StateVariableVisibility::Public) + } + + fn extract_getter_type_parameters_abi(&self) -> Option<(Vec, Vec)> { + let binder::Definition::StateVariable(definition) = self + .semantic + .binder() + .find_definition_by_id(self.ir_node.id())? + else { + unreachable!("definition is not a state variable"); + }; + extract_function_type_parameters_abi(&self.semantic, definition.getter_type_id?) + } + + pub fn compute_abi_entry(&self) -> Option { + if !self.is_externally_visible() { + return None; + } + let (inputs, outputs) = self.extract_getter_type_parameters_abi()?; + + Some(AbiEntry::Function { + node_id: self.ir_node.id(), + name: self + .ir_node + .name + .unparse(self.semantic.interner()) + .to_string(), + inputs, + outputs, + state_mutability: AbiMutability::View, + }) + } + + pub fn compute_selector(&self) -> Option { + if !self.is_externally_visible() { + return None; + } + let (inputs, _) = self.extract_getter_type_parameters_abi()?; + + let signature = format!( + "{name}({parameters})", + name = self.ir_node.name.unparse(self.semantic.interner()), + parameters = inputs + .into_iter() + .map(|parameter| parameter.r#type) + .collect::>() + .join(","), + ); + + Some(selector_from_signature(&signature)) + } +} diff --git a/crates/solidity-v2/outputs/cargo/ast/src/ast/nodes.generated.rs b/crates/solidity-v2/outputs/cargo/ast/src/ast/nodes.generated.rs new file mode 100644 index 0000000000..9ab79dedd2 --- /dev/null +++ b/crates/solidity-v2/outputs/cargo/ast/src/ast/nodes.generated.rs @@ -0,0 +1,5677 @@ +// This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +#![allow(unused)] +#![allow(non_camel_case_types)] +use std::rc::Rc; + +use slang_solidity_v2_ir::ir::{self, NodeId}; +use slang_solidity_v2_semantic::context::SemanticContext; + +use super::types::Type; + +// +// Sequences +// + +pub type AbicoderPragma = Rc; + +pub struct AbicoderPragmaStruct { + pub(crate) ir_node: ir::AbicoderPragma, + pub(crate) semantic: Rc, +} + +pub fn create_abicoder_pragma( + ir_node: &ir::AbicoderPragma, + semantic: &Rc, +) -> AbicoderPragma { + Rc::new(AbicoderPragmaStruct { + ir_node: Rc::clone(ir_node), + semantic: Rc::clone(semantic), + }) +} + +impl AbicoderPragmaStruct { + pub fn node_id(&self) -> NodeId { + self.ir_node.id() + } + + pub fn version(&self) -> AbicoderVersion { + create_abicoder_version(&self.ir_node.version, &self.semantic) + } + + pub fn get_type(&self) -> Option { + Type::try_create_for_node_id(self.ir_node.id(), &self.semantic) + } +} + +pub type AdditiveExpression = Rc; + +pub struct AdditiveExpressionStruct { + pub(crate) ir_node: ir::AdditiveExpression, + pub(crate) semantic: Rc, +} + +pub fn create_additive_expression( + ir_node: &ir::AdditiveExpression, + semantic: &Rc, +) -> AdditiveExpression { + Rc::new(AdditiveExpressionStruct { + ir_node: Rc::clone(ir_node), + semantic: Rc::clone(semantic), + }) +} + +impl AdditiveExpressionStruct { + pub fn node_id(&self) -> NodeId { + self.ir_node.id() + } + + pub fn left_operand(&self) -> Expression { + create_expression(&self.ir_node.left_operand, &self.semantic) + } + + pub fn expression_additive_expression_operator( + &self, + ) -> Expression_AdditiveExpression_Operator { + create_expression_additive_expression_operator( + &self.ir_node.expression_additive_expression_operator, + &self.semantic, + ) + } + + pub fn right_operand(&self) -> Expression { + create_expression(&self.ir_node.right_operand, &self.semantic) + } + + pub fn get_type(&self) -> Option { + Type::try_create_for_node_id(self.ir_node.id(), &self.semantic) + } +} + +pub type AddressType = Rc; + +pub struct AddressTypeStruct { + pub(crate) ir_node: ir::AddressType, + pub(crate) semantic: Rc, +} + +pub fn create_address_type( + ir_node: &ir::AddressType, + semantic: &Rc, +) -> AddressType { + Rc::new(AddressTypeStruct { + ir_node: Rc::clone(ir_node), + semantic: Rc::clone(semantic), + }) +} + +impl AddressTypeStruct { + pub fn node_id(&self) -> NodeId { + self.ir_node.id() + } + + pub fn payable_keyword(&self) -> bool { + self.ir_node.payable_keyword + } + + pub fn get_type(&self) -> Option { + Type::try_create_for_node_id(self.ir_node.id(), &self.semantic) + } +} + +pub type AndExpression = Rc; + +pub struct AndExpressionStruct { + pub(crate) ir_node: ir::AndExpression, + pub(crate) semantic: Rc, +} + +pub fn create_and_expression( + ir_node: &ir::AndExpression, + semantic: &Rc, +) -> AndExpression { + Rc::new(AndExpressionStruct { + ir_node: Rc::clone(ir_node), + semantic: Rc::clone(semantic), + }) +} + +impl AndExpressionStruct { + pub fn node_id(&self) -> NodeId { + self.ir_node.id() + } + + pub fn left_operand(&self) -> Expression { + create_expression(&self.ir_node.left_operand, &self.semantic) + } + + pub fn right_operand(&self) -> Expression { + create_expression(&self.ir_node.right_operand, &self.semantic) + } + + pub fn get_type(&self) -> Option { + Type::try_create_for_node_id(self.ir_node.id(), &self.semantic) + } +} + +pub type ArrayExpression = Rc; + +pub struct ArrayExpressionStruct { + pub(crate) ir_node: ir::ArrayExpression, + pub(crate) semantic: Rc, +} + +pub fn create_array_expression( + ir_node: &ir::ArrayExpression, + semantic: &Rc, +) -> ArrayExpression { + Rc::new(ArrayExpressionStruct { + ir_node: Rc::clone(ir_node), + semantic: Rc::clone(semantic), + }) +} + +impl ArrayExpressionStruct { + pub fn node_id(&self) -> NodeId { + self.ir_node.id() + } + + pub fn items(&self) -> ArrayValues { + create_array_values(&self.ir_node.items, &self.semantic) + } + + pub fn get_type(&self) -> Option { + Type::try_create_for_node_id(self.ir_node.id(), &self.semantic) + } +} + +pub type ArrayTypeName = Rc; + +pub struct ArrayTypeNameStruct { + pub(crate) ir_node: ir::ArrayTypeName, + pub(crate) semantic: Rc, +} + +pub fn create_array_type_name( + ir_node: &ir::ArrayTypeName, + semantic: &Rc, +) -> ArrayTypeName { + Rc::new(ArrayTypeNameStruct { + ir_node: Rc::clone(ir_node), + semantic: Rc::clone(semantic), + }) +} + +impl ArrayTypeNameStruct { + pub fn node_id(&self) -> NodeId { + self.ir_node.id() + } + + pub fn operand(&self) -> TypeName { + create_type_name(&self.ir_node.operand, &self.semantic) + } + + pub fn index(&self) -> Option { + self.ir_node + .index + .as_ref() + .map(|ir_node| create_expression(ir_node, &self.semantic)) + } + + pub fn get_type(&self) -> Option { + Type::try_create_for_node_id(self.ir_node.id(), &self.semantic) + } +} + +pub type AssemblyStatement = Rc; + +pub struct AssemblyStatementStruct { + pub(crate) ir_node: ir::AssemblyStatement, + pub(crate) semantic: Rc, +} + +pub fn create_assembly_statement( + ir_node: &ir::AssemblyStatement, + semantic: &Rc, +) -> AssemblyStatement { + Rc::new(AssemblyStatementStruct { + ir_node: Rc::clone(ir_node), + semantic: Rc::clone(semantic), + }) +} + +impl AssemblyStatementStruct { + pub fn node_id(&self) -> NodeId { + self.ir_node.id() + } + + pub fn label(&self) -> Option { + self.ir_node.label.as_ref().map(Rc::clone) + } + + pub fn flags(&self) -> Option> { + self.ir_node.flags.clone() + } + + pub fn body(&self) -> YulBlock { + create_yul_block(&self.ir_node.body, &self.semantic) + } + + pub fn get_type(&self) -> Option { + Type::try_create_for_node_id(self.ir_node.id(), &self.semantic) + } +} + +pub type AssignmentExpression = Rc; + +pub struct AssignmentExpressionStruct { + pub(crate) ir_node: ir::AssignmentExpression, + pub(crate) semantic: Rc, +} + +pub fn create_assignment_expression( + ir_node: &ir::AssignmentExpression, + semantic: &Rc, +) -> AssignmentExpression { + Rc::new(AssignmentExpressionStruct { + ir_node: Rc::clone(ir_node), + semantic: Rc::clone(semantic), + }) +} + +impl AssignmentExpressionStruct { + pub fn node_id(&self) -> NodeId { + self.ir_node.id() + } + + pub fn left_operand(&self) -> Expression { + create_expression(&self.ir_node.left_operand, &self.semantic) + } + + pub fn expression_assignment_expression_operator( + &self, + ) -> Expression_AssignmentExpression_Operator { + create_expression_assignment_expression_operator( + &self.ir_node.expression_assignment_expression_operator, + &self.semantic, + ) + } + + pub fn right_operand(&self) -> Expression { + create_expression(&self.ir_node.right_operand, &self.semantic) + } + + pub fn get_type(&self) -> Option { + Type::try_create_for_node_id(self.ir_node.id(), &self.semantic) + } +} + +pub type BitwiseAndExpression = Rc; + +pub struct BitwiseAndExpressionStruct { + pub(crate) ir_node: ir::BitwiseAndExpression, + pub(crate) semantic: Rc, +} + +pub fn create_bitwise_and_expression( + ir_node: &ir::BitwiseAndExpression, + semantic: &Rc, +) -> BitwiseAndExpression { + Rc::new(BitwiseAndExpressionStruct { + ir_node: Rc::clone(ir_node), + semantic: Rc::clone(semantic), + }) +} + +impl BitwiseAndExpressionStruct { + pub fn node_id(&self) -> NodeId { + self.ir_node.id() + } + + pub fn left_operand(&self) -> Expression { + create_expression(&self.ir_node.left_operand, &self.semantic) + } + + pub fn right_operand(&self) -> Expression { + create_expression(&self.ir_node.right_operand, &self.semantic) + } + + pub fn get_type(&self) -> Option { + Type::try_create_for_node_id(self.ir_node.id(), &self.semantic) + } +} + +pub type BitwiseOrExpression = Rc; + +pub struct BitwiseOrExpressionStruct { + pub(crate) ir_node: ir::BitwiseOrExpression, + pub(crate) semantic: Rc, +} + +pub fn create_bitwise_or_expression( + ir_node: &ir::BitwiseOrExpression, + semantic: &Rc, +) -> BitwiseOrExpression { + Rc::new(BitwiseOrExpressionStruct { + ir_node: Rc::clone(ir_node), + semantic: Rc::clone(semantic), + }) +} + +impl BitwiseOrExpressionStruct { + pub fn node_id(&self) -> NodeId { + self.ir_node.id() + } + + pub fn left_operand(&self) -> Expression { + create_expression(&self.ir_node.left_operand, &self.semantic) + } + + pub fn right_operand(&self) -> Expression { + create_expression(&self.ir_node.right_operand, &self.semantic) + } + + pub fn get_type(&self) -> Option { + Type::try_create_for_node_id(self.ir_node.id(), &self.semantic) + } +} + +pub type BitwiseXorExpression = Rc; + +pub struct BitwiseXorExpressionStruct { + pub(crate) ir_node: ir::BitwiseXorExpression, + pub(crate) semantic: Rc, +} + +pub fn create_bitwise_xor_expression( + ir_node: &ir::BitwiseXorExpression, + semantic: &Rc, +) -> BitwiseXorExpression { + Rc::new(BitwiseXorExpressionStruct { + ir_node: Rc::clone(ir_node), + semantic: Rc::clone(semantic), + }) +} + +impl BitwiseXorExpressionStruct { + pub fn node_id(&self) -> NodeId { + self.ir_node.id() + } + + pub fn left_operand(&self) -> Expression { + create_expression(&self.ir_node.left_operand, &self.semantic) + } + + pub fn right_operand(&self) -> Expression { + create_expression(&self.ir_node.right_operand, &self.semantic) + } + + pub fn get_type(&self) -> Option { + Type::try_create_for_node_id(self.ir_node.id(), &self.semantic) + } +} + +pub type Block = Rc; + +pub struct BlockStruct { + pub(crate) ir_node: ir::Block, + pub(crate) semantic: Rc, +} + +pub fn create_block(ir_node: &ir::Block, semantic: &Rc) -> Block { + Rc::new(BlockStruct { + ir_node: Rc::clone(ir_node), + semantic: Rc::clone(semantic), + }) +} + +impl BlockStruct { + pub fn node_id(&self) -> NodeId { + self.ir_node.id() + } + + pub fn statements(&self) -> Statements { + create_statements(&self.ir_node.statements, &self.semantic) + } + + pub fn get_type(&self) -> Option { + Type::try_create_for_node_id(self.ir_node.id(), &self.semantic) + } +} + +pub type BreakStatement = Rc; + +pub struct BreakStatementStruct { + pub(crate) ir_node: ir::BreakStatement, + pub(crate) semantic: Rc, +} + +pub fn create_break_statement( + ir_node: &ir::BreakStatement, + semantic: &Rc, +) -> BreakStatement { + Rc::new(BreakStatementStruct { + ir_node: Rc::clone(ir_node), + semantic: Rc::clone(semantic), + }) +} + +impl BreakStatementStruct { + pub fn node_id(&self) -> NodeId { + self.ir_node.id() + } + + pub fn get_type(&self) -> Option { + Type::try_create_for_node_id(self.ir_node.id(), &self.semantic) + } +} + +pub type CallOptionsExpression = Rc; + +pub struct CallOptionsExpressionStruct { + pub(crate) ir_node: ir::CallOptionsExpression, + pub(crate) semantic: Rc, +} + +pub fn create_call_options_expression( + ir_node: &ir::CallOptionsExpression, + semantic: &Rc, +) -> CallOptionsExpression { + Rc::new(CallOptionsExpressionStruct { + ir_node: Rc::clone(ir_node), + semantic: Rc::clone(semantic), + }) +} + +impl CallOptionsExpressionStruct { + pub fn node_id(&self) -> NodeId { + self.ir_node.id() + } + + pub fn operand(&self) -> Expression { + create_expression(&self.ir_node.operand, &self.semantic) + } + + pub fn options(&self) -> CallOptions { + create_call_options(&self.ir_node.options, &self.semantic) + } + + pub fn get_type(&self) -> Option { + Type::try_create_for_node_id(self.ir_node.id(), &self.semantic) + } +} + +pub type CatchClause = Rc; + +pub struct CatchClauseStruct { + pub(crate) ir_node: ir::CatchClause, + pub(crate) semantic: Rc, +} + +pub fn create_catch_clause( + ir_node: &ir::CatchClause, + semantic: &Rc, +) -> CatchClause { + Rc::new(CatchClauseStruct { + ir_node: Rc::clone(ir_node), + semantic: Rc::clone(semantic), + }) +} + +impl CatchClauseStruct { + pub fn node_id(&self) -> NodeId { + self.ir_node.id() + } + + pub fn error(&self) -> Option { + self.ir_node + .error + .as_ref() + .map(|ir_node| create_catch_clause_error(ir_node, &self.semantic)) + } + + pub fn body(&self) -> Block { + create_block(&self.ir_node.body, &self.semantic) + } + + pub fn get_type(&self) -> Option { + Type::try_create_for_node_id(self.ir_node.id(), &self.semantic) + } +} + +pub type CatchClauseError = Rc; + +pub struct CatchClauseErrorStruct { + pub(crate) ir_node: ir::CatchClauseError, + pub(crate) semantic: Rc, +} + +pub fn create_catch_clause_error( + ir_node: &ir::CatchClauseError, + semantic: &Rc, +) -> CatchClauseError { + Rc::new(CatchClauseErrorStruct { + ir_node: Rc::clone(ir_node), + semantic: Rc::clone(semantic), + }) +} + +impl CatchClauseErrorStruct { + pub fn node_id(&self) -> NodeId { + self.ir_node.id() + } + + pub fn name(&self) -> Option { + self.ir_node + .name + .as_ref() + .map(|ir_node| create_identifier(ir_node, &self.semantic)) + } + + pub fn parameters(&self) -> Parameters { + create_parameters(&self.ir_node.parameters, &self.semantic) + } + + pub fn get_type(&self) -> Option { + Type::try_create_for_node_id(self.ir_node.id(), &self.semantic) + } +} + +pub type ConditionalExpression = Rc; + +pub struct ConditionalExpressionStruct { + pub(crate) ir_node: ir::ConditionalExpression, + pub(crate) semantic: Rc, +} + +pub fn create_conditional_expression( + ir_node: &ir::ConditionalExpression, + semantic: &Rc, +) -> ConditionalExpression { + Rc::new(ConditionalExpressionStruct { + ir_node: Rc::clone(ir_node), + semantic: Rc::clone(semantic), + }) +} + +impl ConditionalExpressionStruct { + pub fn node_id(&self) -> NodeId { + self.ir_node.id() + } + + pub fn operand(&self) -> Expression { + create_expression(&self.ir_node.operand, &self.semantic) + } + + pub fn true_expression(&self) -> Expression { + create_expression(&self.ir_node.true_expression, &self.semantic) + } + + pub fn false_expression(&self) -> Expression { + create_expression(&self.ir_node.false_expression, &self.semantic) + } + + pub fn get_type(&self) -> Option { + Type::try_create_for_node_id(self.ir_node.id(), &self.semantic) + } +} + +pub type ConstantDefinition = Rc; + +pub struct ConstantDefinitionStruct { + pub(crate) ir_node: ir::ConstantDefinition, + pub(crate) semantic: Rc, +} + +pub fn create_constant_definition( + ir_node: &ir::ConstantDefinition, + semantic: &Rc, +) -> ConstantDefinition { + Rc::new(ConstantDefinitionStruct { + ir_node: Rc::clone(ir_node), + semantic: Rc::clone(semantic), + }) +} + +impl ConstantDefinitionStruct { + pub fn node_id(&self) -> NodeId { + self.ir_node.id() + } + + pub fn type_name(&self) -> TypeName { + create_type_name(&self.ir_node.type_name, &self.semantic) + } + + pub fn name(&self) -> Identifier { + create_identifier(&self.ir_node.name, &self.semantic) + } + + pub fn visibility(&self) -> Option { + self.ir_node + .visibility + .as_ref() + .map(|ir_node| create_state_variable_visibility(ir_node, &self.semantic)) + } + + pub fn value(&self) -> Option { + self.ir_node + .value + .as_ref() + .map(|ir_node| create_expression(ir_node, &self.semantic)) + } + + pub fn get_type(&self) -> Option { + Type::try_create_for_node_id(self.ir_node.id(), &self.semantic) + } +} + +pub type ContinueStatement = Rc; + +pub struct ContinueStatementStruct { + pub(crate) ir_node: ir::ContinueStatement, + pub(crate) semantic: Rc, +} + +pub fn create_continue_statement( + ir_node: &ir::ContinueStatement, + semantic: &Rc, +) -> ContinueStatement { + Rc::new(ContinueStatementStruct { + ir_node: Rc::clone(ir_node), + semantic: Rc::clone(semantic), + }) +} + +impl ContinueStatementStruct { + pub fn node_id(&self) -> NodeId { + self.ir_node.id() + } + + pub fn get_type(&self) -> Option { + Type::try_create_for_node_id(self.ir_node.id(), &self.semantic) + } +} + +pub type ContractDefinition = Rc; + +pub struct ContractDefinitionStruct { + pub(crate) ir_node: ir::ContractDefinition, + pub(crate) semantic: Rc, +} + +pub fn create_contract_definition( + ir_node: &ir::ContractDefinition, + semantic: &Rc, +) -> ContractDefinition { + Rc::new(ContractDefinitionStruct { + ir_node: Rc::clone(ir_node), + semantic: Rc::clone(semantic), + }) +} + +impl ContractDefinitionStruct { + pub fn node_id(&self) -> NodeId { + self.ir_node.id() + } + + pub fn abstract_keyword(&self) -> bool { + self.ir_node.abstract_keyword + } + + pub fn name(&self) -> Identifier { + create_identifier(&self.ir_node.name, &self.semantic) + } + + pub fn inheritance_types(&self) -> InheritanceTypes { + create_inheritance_types(&self.ir_node.inheritance_types, &self.semantic) + } + + pub fn storage_layout(&self) -> Option { + self.ir_node + .storage_layout + .as_ref() + .map(|ir_node| create_expression(ir_node, &self.semantic)) + } + + pub fn members(&self) -> ContractMembers { + create_contract_members(&self.ir_node.members, &self.semantic) + } + + pub fn get_type(&self) -> Option { + Type::try_create_for_node_id(self.ir_node.id(), &self.semantic) + } +} + +pub type DecimalNumberExpression = Rc; + +pub struct DecimalNumberExpressionStruct { + pub(crate) ir_node: ir::DecimalNumberExpression, + pub(crate) semantic: Rc, +} + +pub fn create_decimal_number_expression( + ir_node: &ir::DecimalNumberExpression, + semantic: &Rc, +) -> DecimalNumberExpression { + Rc::new(DecimalNumberExpressionStruct { + ir_node: Rc::clone(ir_node), + semantic: Rc::clone(semantic), + }) +} + +impl DecimalNumberExpressionStruct { + pub fn node_id(&self) -> NodeId { + self.ir_node.id() + } + + pub fn literal(&self) -> ir::DecimalLiteral { + Rc::clone(&self.ir_node.literal) + } + + pub fn unit(&self) -> Option { + self.ir_node + .unit + .as_ref() + .map(|ir_node| create_number_unit(ir_node, &self.semantic)) + } + + pub fn get_type(&self) -> Option { + Type::try_create_for_node_id(self.ir_node.id(), &self.semantic) + } +} + +pub type DoWhileStatement = Rc; + +pub struct DoWhileStatementStruct { + pub(crate) ir_node: ir::DoWhileStatement, + pub(crate) semantic: Rc, +} + +pub fn create_do_while_statement( + ir_node: &ir::DoWhileStatement, + semantic: &Rc, +) -> DoWhileStatement { + Rc::new(DoWhileStatementStruct { + ir_node: Rc::clone(ir_node), + semantic: Rc::clone(semantic), + }) +} + +impl DoWhileStatementStruct { + pub fn node_id(&self) -> NodeId { + self.ir_node.id() + } + + pub fn body(&self) -> Statement { + create_statement(&self.ir_node.body, &self.semantic) + } + + pub fn condition(&self) -> Expression { + create_expression(&self.ir_node.condition, &self.semantic) + } + + pub fn get_type(&self) -> Option { + Type::try_create_for_node_id(self.ir_node.id(), &self.semantic) + } +} + +pub type EmitStatement = Rc; + +pub struct EmitStatementStruct { + pub(crate) ir_node: ir::EmitStatement, + pub(crate) semantic: Rc, +} + +pub fn create_emit_statement( + ir_node: &ir::EmitStatement, + semantic: &Rc, +) -> EmitStatement { + Rc::new(EmitStatementStruct { + ir_node: Rc::clone(ir_node), + semantic: Rc::clone(semantic), + }) +} + +impl EmitStatementStruct { + pub fn node_id(&self) -> NodeId { + self.ir_node.id() + } + + pub fn event(&self) -> IdentifierPath { + create_identifier_path(&self.ir_node.event, &self.semantic) + } + + pub fn arguments(&self) -> ArgumentsDeclaration { + create_arguments_declaration(&self.ir_node.arguments, &self.semantic) + } + + pub fn get_type(&self) -> Option { + Type::try_create_for_node_id(self.ir_node.id(), &self.semantic) + } +} + +pub type EnumDefinition = Rc; + +pub struct EnumDefinitionStruct { + pub(crate) ir_node: ir::EnumDefinition, + pub(crate) semantic: Rc, +} + +pub fn create_enum_definition( + ir_node: &ir::EnumDefinition, + semantic: &Rc, +) -> EnumDefinition { + Rc::new(EnumDefinitionStruct { + ir_node: Rc::clone(ir_node), + semantic: Rc::clone(semantic), + }) +} + +impl EnumDefinitionStruct { + pub fn node_id(&self) -> NodeId { + self.ir_node.id() + } + + pub fn name(&self) -> Identifier { + create_identifier(&self.ir_node.name, &self.semantic) + } + + pub fn members(&self) -> EnumMembers { + create_enum_members(&self.ir_node.members, &self.semantic) + } + + pub fn get_type(&self) -> Option { + Type::try_create_for_node_id(self.ir_node.id(), &self.semantic) + } +} + +pub type EqualityExpression = Rc; + +pub struct EqualityExpressionStruct { + pub(crate) ir_node: ir::EqualityExpression, + pub(crate) semantic: Rc, +} + +pub fn create_equality_expression( + ir_node: &ir::EqualityExpression, + semantic: &Rc, +) -> EqualityExpression { + Rc::new(EqualityExpressionStruct { + ir_node: Rc::clone(ir_node), + semantic: Rc::clone(semantic), + }) +} + +impl EqualityExpressionStruct { + pub fn node_id(&self) -> NodeId { + self.ir_node.id() + } + + pub fn left_operand(&self) -> Expression { + create_expression(&self.ir_node.left_operand, &self.semantic) + } + + pub fn expression_equality_expression_operator( + &self, + ) -> Expression_EqualityExpression_Operator { + create_expression_equality_expression_operator( + &self.ir_node.expression_equality_expression_operator, + &self.semantic, + ) + } + + pub fn right_operand(&self) -> Expression { + create_expression(&self.ir_node.right_operand, &self.semantic) + } + + pub fn get_type(&self) -> Option { + Type::try_create_for_node_id(self.ir_node.id(), &self.semantic) + } +} + +pub type ErrorDefinition = Rc; + +pub struct ErrorDefinitionStruct { + pub(crate) ir_node: ir::ErrorDefinition, + pub(crate) semantic: Rc, +} + +pub fn create_error_definition( + ir_node: &ir::ErrorDefinition, + semantic: &Rc, +) -> ErrorDefinition { + Rc::new(ErrorDefinitionStruct { + ir_node: Rc::clone(ir_node), + semantic: Rc::clone(semantic), + }) +} + +impl ErrorDefinitionStruct { + pub fn node_id(&self) -> NodeId { + self.ir_node.id() + } + + pub fn name(&self) -> Identifier { + create_identifier(&self.ir_node.name, &self.semantic) + } + + pub fn parameters(&self) -> Parameters { + create_parameters(&self.ir_node.parameters, &self.semantic) + } + + pub fn get_type(&self) -> Option { + Type::try_create_for_node_id(self.ir_node.id(), &self.semantic) + } +} + +pub type EventDefinition = Rc; + +pub struct EventDefinitionStruct { + pub(crate) ir_node: ir::EventDefinition, + pub(crate) semantic: Rc, +} + +pub fn create_event_definition( + ir_node: &ir::EventDefinition, + semantic: &Rc, +) -> EventDefinition { + Rc::new(EventDefinitionStruct { + ir_node: Rc::clone(ir_node), + semantic: Rc::clone(semantic), + }) +} + +impl EventDefinitionStruct { + pub fn node_id(&self) -> NodeId { + self.ir_node.id() + } + + pub fn name(&self) -> Identifier { + create_identifier(&self.ir_node.name, &self.semantic) + } + + pub fn anonymous_keyword(&self) -> bool { + self.ir_node.anonymous_keyword + } + + pub fn parameters(&self) -> Parameters { + create_parameters(&self.ir_node.parameters, &self.semantic) + } + + pub fn get_type(&self) -> Option { + Type::try_create_for_node_id(self.ir_node.id(), &self.semantic) + } +} + +pub type ExperimentalPragma = Rc; + +pub struct ExperimentalPragmaStruct { + pub(crate) ir_node: ir::ExperimentalPragma, + pub(crate) semantic: Rc, +} + +pub fn create_experimental_pragma( + ir_node: &ir::ExperimentalPragma, + semantic: &Rc, +) -> ExperimentalPragma { + Rc::new(ExperimentalPragmaStruct { + ir_node: Rc::clone(ir_node), + semantic: Rc::clone(semantic), + }) +} + +impl ExperimentalPragmaStruct { + pub fn node_id(&self) -> NodeId { + self.ir_node.id() + } + + pub fn feature(&self) -> ExperimentalFeature { + create_experimental_feature(&self.ir_node.feature, &self.semantic) + } + + pub fn get_type(&self) -> Option { + Type::try_create_for_node_id(self.ir_node.id(), &self.semantic) + } +} + +pub type ExponentiationExpression = Rc; + +pub struct ExponentiationExpressionStruct { + pub(crate) ir_node: ir::ExponentiationExpression, + pub(crate) semantic: Rc, +} + +pub fn create_exponentiation_expression( + ir_node: &ir::ExponentiationExpression, + semantic: &Rc, +) -> ExponentiationExpression { + Rc::new(ExponentiationExpressionStruct { + ir_node: Rc::clone(ir_node), + semantic: Rc::clone(semantic), + }) +} + +impl ExponentiationExpressionStruct { + pub fn node_id(&self) -> NodeId { + self.ir_node.id() + } + + pub fn left_operand(&self) -> Expression { + create_expression(&self.ir_node.left_operand, &self.semantic) + } + + pub fn right_operand(&self) -> Expression { + create_expression(&self.ir_node.right_operand, &self.semantic) + } + + pub fn get_type(&self) -> Option { + Type::try_create_for_node_id(self.ir_node.id(), &self.semantic) + } +} + +pub type ExpressionStatement = Rc; + +pub struct ExpressionStatementStruct { + pub(crate) ir_node: ir::ExpressionStatement, + pub(crate) semantic: Rc, +} + +pub fn create_expression_statement( + ir_node: &ir::ExpressionStatement, + semantic: &Rc, +) -> ExpressionStatement { + Rc::new(ExpressionStatementStruct { + ir_node: Rc::clone(ir_node), + semantic: Rc::clone(semantic), + }) +} + +impl ExpressionStatementStruct { + pub fn node_id(&self) -> NodeId { + self.ir_node.id() + } + + pub fn expression(&self) -> Expression { + create_expression(&self.ir_node.expression, &self.semantic) + } + + pub fn get_type(&self) -> Option { + Type::try_create_for_node_id(self.ir_node.id(), &self.semantic) + } +} + +pub type ForStatement = Rc; + +pub struct ForStatementStruct { + pub(crate) ir_node: ir::ForStatement, + pub(crate) semantic: Rc, +} + +pub fn create_for_statement( + ir_node: &ir::ForStatement, + semantic: &Rc, +) -> ForStatement { + Rc::new(ForStatementStruct { + ir_node: Rc::clone(ir_node), + semantic: Rc::clone(semantic), + }) +} + +impl ForStatementStruct { + pub fn node_id(&self) -> NodeId { + self.ir_node.id() + } + + pub fn initialization(&self) -> ForStatementInitialization { + create_for_statement_initialization(&self.ir_node.initialization, &self.semantic) + } + + pub fn condition(&self) -> ForStatementCondition { + create_for_statement_condition(&self.ir_node.condition, &self.semantic) + } + + pub fn iterator(&self) -> Option { + self.ir_node + .iterator + .as_ref() + .map(|ir_node| create_expression(ir_node, &self.semantic)) + } + + pub fn body(&self) -> Statement { + create_statement(&self.ir_node.body, &self.semantic) + } + + pub fn get_type(&self) -> Option { + Type::try_create_for_node_id(self.ir_node.id(), &self.semantic) + } +} + +pub type FunctionCallExpression = Rc; + +pub struct FunctionCallExpressionStruct { + pub(crate) ir_node: ir::FunctionCallExpression, + pub(crate) semantic: Rc, +} + +pub fn create_function_call_expression( + ir_node: &ir::FunctionCallExpression, + semantic: &Rc, +) -> FunctionCallExpression { + Rc::new(FunctionCallExpressionStruct { + ir_node: Rc::clone(ir_node), + semantic: Rc::clone(semantic), + }) +} + +impl FunctionCallExpressionStruct { + pub fn node_id(&self) -> NodeId { + self.ir_node.id() + } + + pub fn operand(&self) -> Expression { + create_expression(&self.ir_node.operand, &self.semantic) + } + + pub fn arguments(&self) -> ArgumentsDeclaration { + create_arguments_declaration(&self.ir_node.arguments, &self.semantic) + } + + pub fn get_type(&self) -> Option { + Type::try_create_for_node_id(self.ir_node.id(), &self.semantic) + } +} + +pub type FunctionDefinition = Rc; + +pub struct FunctionDefinitionStruct { + pub(crate) ir_node: ir::FunctionDefinition, + pub(crate) semantic: Rc, +} + +pub fn create_function_definition( + ir_node: &ir::FunctionDefinition, + semantic: &Rc, +) -> FunctionDefinition { + Rc::new(FunctionDefinitionStruct { + ir_node: Rc::clone(ir_node), + semantic: Rc::clone(semantic), + }) +} + +impl FunctionDefinitionStruct { + pub fn node_id(&self) -> NodeId { + self.ir_node.id() + } + + pub fn kind(&self) -> FunctionKind { + create_function_kind(&self.ir_node.kind, &self.semantic) + } + + pub fn name(&self) -> Option { + self.ir_node + .name + .as_ref() + .map(|ir_node| create_identifier(ir_node, &self.semantic)) + } + + pub fn parameters(&self) -> Parameters { + create_parameters(&self.ir_node.parameters, &self.semantic) + } + + pub fn visibility(&self) -> FunctionVisibility { + create_function_visibility(&self.ir_node.visibility, &self.semantic) + } + + pub fn mutability(&self) -> FunctionMutability { + create_function_mutability(&self.ir_node.mutability, &self.semantic) + } + + pub fn virtual_keyword(&self) -> bool { + self.ir_node.virtual_keyword + } + + pub fn override_specifier(&self) -> Option { + self.ir_node + .override_specifier + .as_ref() + .map(|ir_node| create_override_paths(ir_node, &self.semantic)) + } + + pub fn modifier_invocations(&self) -> ModifierInvocations { + create_modifier_invocations(&self.ir_node.modifier_invocations, &self.semantic) + } + + pub fn returns(&self) -> Option { + self.ir_node + .returns + .as_ref() + .map(|ir_node| create_parameters(ir_node, &self.semantic)) + } + + pub fn body(&self) -> Option { + self.ir_node + .body + .as_ref() + .map(|ir_node| create_block(ir_node, &self.semantic)) + } + + pub fn get_type(&self) -> Option { + Type::try_create_for_node_id(self.ir_node.id(), &self.semantic) + } +} + +pub type FunctionType = Rc; + +pub struct FunctionTypeStruct { + pub(crate) ir_node: ir::FunctionType, + pub(crate) semantic: Rc, +} + +pub fn create_function_type( + ir_node: &ir::FunctionType, + semantic: &Rc, +) -> FunctionType { + Rc::new(FunctionTypeStruct { + ir_node: Rc::clone(ir_node), + semantic: Rc::clone(semantic), + }) +} + +impl FunctionTypeStruct { + pub fn node_id(&self) -> NodeId { + self.ir_node.id() + } + + pub fn parameters(&self) -> Parameters { + create_parameters(&self.ir_node.parameters, &self.semantic) + } + + pub fn visibility(&self) -> FunctionVisibility { + create_function_visibility(&self.ir_node.visibility, &self.semantic) + } + + pub fn mutability(&self) -> FunctionMutability { + create_function_mutability(&self.ir_node.mutability, &self.semantic) + } + + pub fn returns(&self) -> Option { + self.ir_node + .returns + .as_ref() + .map(|ir_node| create_parameters(ir_node, &self.semantic)) + } + + pub fn get_type(&self) -> Option { + Type::try_create_for_node_id(self.ir_node.id(), &self.semantic) + } +} + +pub type HexNumberExpression = Rc; + +pub struct HexNumberExpressionStruct { + pub(crate) ir_node: ir::HexNumberExpression, + pub(crate) semantic: Rc, +} + +pub fn create_hex_number_expression( + ir_node: &ir::HexNumberExpression, + semantic: &Rc, +) -> HexNumberExpression { + Rc::new(HexNumberExpressionStruct { + ir_node: Rc::clone(ir_node), + semantic: Rc::clone(semantic), + }) +} + +impl HexNumberExpressionStruct { + pub fn node_id(&self) -> NodeId { + self.ir_node.id() + } + + pub fn literal(&self) -> ir::HexLiteral { + Rc::clone(&self.ir_node.literal) + } + + pub fn get_type(&self) -> Option { + Type::try_create_for_node_id(self.ir_node.id(), &self.semantic) + } +} + +pub type IfStatement = Rc; + +pub struct IfStatementStruct { + pub(crate) ir_node: ir::IfStatement, + pub(crate) semantic: Rc, +} + +pub fn create_if_statement( + ir_node: &ir::IfStatement, + semantic: &Rc, +) -> IfStatement { + Rc::new(IfStatementStruct { + ir_node: Rc::clone(ir_node), + semantic: Rc::clone(semantic), + }) +} + +impl IfStatementStruct { + pub fn node_id(&self) -> NodeId { + self.ir_node.id() + } + + pub fn condition(&self) -> Expression { + create_expression(&self.ir_node.condition, &self.semantic) + } + + pub fn body(&self) -> Statement { + create_statement(&self.ir_node.body, &self.semantic) + } + + pub fn else_branch(&self) -> Option { + self.ir_node + .else_branch + .as_ref() + .map(|ir_node| create_statement(ir_node, &self.semantic)) + } + + pub fn get_type(&self) -> Option { + Type::try_create_for_node_id(self.ir_node.id(), &self.semantic) + } +} + +pub type ImportDeconstruction = Rc; + +pub struct ImportDeconstructionStruct { + pub(crate) ir_node: ir::ImportDeconstruction, + pub(crate) semantic: Rc, +} + +pub fn create_import_deconstruction( + ir_node: &ir::ImportDeconstruction, + semantic: &Rc, +) -> ImportDeconstruction { + Rc::new(ImportDeconstructionStruct { + ir_node: Rc::clone(ir_node), + semantic: Rc::clone(semantic), + }) +} + +impl ImportDeconstructionStruct { + pub fn node_id(&self) -> NodeId { + self.ir_node.id() + } + + pub fn symbols(&self) -> ImportDeconstructionSymbols { + create_import_deconstruction_symbols(&self.ir_node.symbols, &self.semantic) + } + + pub fn path(&self) -> ir::StringLiteral { + Rc::clone(&self.ir_node.path) + } + + pub fn get_type(&self) -> Option { + Type::try_create_for_node_id(self.ir_node.id(), &self.semantic) + } +} + +pub type ImportDeconstructionSymbol = Rc; + +pub struct ImportDeconstructionSymbolStruct { + pub(crate) ir_node: ir::ImportDeconstructionSymbol, + pub(crate) semantic: Rc, +} + +pub fn create_import_deconstruction_symbol( + ir_node: &ir::ImportDeconstructionSymbol, + semantic: &Rc, +) -> ImportDeconstructionSymbol { + Rc::new(ImportDeconstructionSymbolStruct { + ir_node: Rc::clone(ir_node), + semantic: Rc::clone(semantic), + }) +} + +impl ImportDeconstructionSymbolStruct { + pub fn node_id(&self) -> NodeId { + self.ir_node.id() + } + + pub fn name(&self) -> Identifier { + create_identifier(&self.ir_node.name, &self.semantic) + } + + pub fn alias(&self) -> Option { + self.ir_node + .alias + .as_ref() + .map(|ir_node| create_identifier(ir_node, &self.semantic)) + } + + pub fn get_type(&self) -> Option { + Type::try_create_for_node_id(self.ir_node.id(), &self.semantic) + } +} + +pub type IndexAccessExpression = Rc; + +pub struct IndexAccessExpressionStruct { + pub(crate) ir_node: ir::IndexAccessExpression, + pub(crate) semantic: Rc, +} + +pub fn create_index_access_expression( + ir_node: &ir::IndexAccessExpression, + semantic: &Rc, +) -> IndexAccessExpression { + Rc::new(IndexAccessExpressionStruct { + ir_node: Rc::clone(ir_node), + semantic: Rc::clone(semantic), + }) +} + +impl IndexAccessExpressionStruct { + pub fn node_id(&self) -> NodeId { + self.ir_node.id() + } + + pub fn operand(&self) -> Expression { + create_expression(&self.ir_node.operand, &self.semantic) + } + + pub fn start(&self) -> Option { + self.ir_node + .start + .as_ref() + .map(|ir_node| create_expression(ir_node, &self.semantic)) + } + + pub fn end(&self) -> Option { + self.ir_node + .end + .as_ref() + .map(|ir_node| create_expression(ir_node, &self.semantic)) + } + + pub fn get_type(&self) -> Option { + Type::try_create_for_node_id(self.ir_node.id(), &self.semantic) + } +} + +pub type InequalityExpression = Rc; + +pub struct InequalityExpressionStruct { + pub(crate) ir_node: ir::InequalityExpression, + pub(crate) semantic: Rc, +} + +pub fn create_inequality_expression( + ir_node: &ir::InequalityExpression, + semantic: &Rc, +) -> InequalityExpression { + Rc::new(InequalityExpressionStruct { + ir_node: Rc::clone(ir_node), + semantic: Rc::clone(semantic), + }) +} + +impl InequalityExpressionStruct { + pub fn node_id(&self) -> NodeId { + self.ir_node.id() + } + + pub fn left_operand(&self) -> Expression { + create_expression(&self.ir_node.left_operand, &self.semantic) + } + + pub fn expression_inequality_expression_operator( + &self, + ) -> Expression_InequalityExpression_Operator { + create_expression_inequality_expression_operator( + &self.ir_node.expression_inequality_expression_operator, + &self.semantic, + ) + } + + pub fn right_operand(&self) -> Expression { + create_expression(&self.ir_node.right_operand, &self.semantic) + } + + pub fn get_type(&self) -> Option { + Type::try_create_for_node_id(self.ir_node.id(), &self.semantic) + } +} + +pub type InheritanceType = Rc; + +pub struct InheritanceTypeStruct { + pub(crate) ir_node: ir::InheritanceType, + pub(crate) semantic: Rc, +} + +pub fn create_inheritance_type( + ir_node: &ir::InheritanceType, + semantic: &Rc, +) -> InheritanceType { + Rc::new(InheritanceTypeStruct { + ir_node: Rc::clone(ir_node), + semantic: Rc::clone(semantic), + }) +} + +impl InheritanceTypeStruct { + pub fn node_id(&self) -> NodeId { + self.ir_node.id() + } + + pub fn type_name(&self) -> IdentifierPath { + create_identifier_path(&self.ir_node.type_name, &self.semantic) + } + + pub fn arguments(&self) -> Option { + self.ir_node + .arguments + .as_ref() + .map(|ir_node| create_arguments_declaration(ir_node, &self.semantic)) + } + + pub fn get_type(&self) -> Option { + Type::try_create_for_node_id(self.ir_node.id(), &self.semantic) + } +} + +pub type InterfaceDefinition = Rc; + +pub struct InterfaceDefinitionStruct { + pub(crate) ir_node: ir::InterfaceDefinition, + pub(crate) semantic: Rc, +} + +pub fn create_interface_definition( + ir_node: &ir::InterfaceDefinition, + semantic: &Rc, +) -> InterfaceDefinition { + Rc::new(InterfaceDefinitionStruct { + ir_node: Rc::clone(ir_node), + semantic: Rc::clone(semantic), + }) +} + +impl InterfaceDefinitionStruct { + pub fn node_id(&self) -> NodeId { + self.ir_node.id() + } + + pub fn name(&self) -> Identifier { + create_identifier(&self.ir_node.name, &self.semantic) + } + + pub fn inheritance(&self) -> Option { + self.ir_node + .inheritance + .as_ref() + .map(|ir_node| create_inheritance_types(ir_node, &self.semantic)) + } + + pub fn members(&self) -> InterfaceMembers { + create_interface_members(&self.ir_node.members, &self.semantic) + } + + pub fn get_type(&self) -> Option { + Type::try_create_for_node_id(self.ir_node.id(), &self.semantic) + } +} + +pub type LibraryDefinition = Rc; + +pub struct LibraryDefinitionStruct { + pub(crate) ir_node: ir::LibraryDefinition, + pub(crate) semantic: Rc, +} + +pub fn create_library_definition( + ir_node: &ir::LibraryDefinition, + semantic: &Rc, +) -> LibraryDefinition { + Rc::new(LibraryDefinitionStruct { + ir_node: Rc::clone(ir_node), + semantic: Rc::clone(semantic), + }) +} + +impl LibraryDefinitionStruct { + pub fn node_id(&self) -> NodeId { + self.ir_node.id() + } + + pub fn name(&self) -> Identifier { + create_identifier(&self.ir_node.name, &self.semantic) + } + + pub fn members(&self) -> LibraryMembers { + create_library_members(&self.ir_node.members, &self.semantic) + } + + pub fn get_type(&self) -> Option { + Type::try_create_for_node_id(self.ir_node.id(), &self.semantic) + } +} + +pub type MappingType = Rc; + +pub struct MappingTypeStruct { + pub(crate) ir_node: ir::MappingType, + pub(crate) semantic: Rc, +} + +pub fn create_mapping_type( + ir_node: &ir::MappingType, + semantic: &Rc, +) -> MappingType { + Rc::new(MappingTypeStruct { + ir_node: Rc::clone(ir_node), + semantic: Rc::clone(semantic), + }) +} + +impl MappingTypeStruct { + pub fn node_id(&self) -> NodeId { + self.ir_node.id() + } + + pub fn key_type(&self) -> Parameter { + create_parameter(&self.ir_node.key_type, &self.semantic) + } + + pub fn value_type(&self) -> Parameter { + create_parameter(&self.ir_node.value_type, &self.semantic) + } + + pub fn get_type(&self) -> Option { + Type::try_create_for_node_id(self.ir_node.id(), &self.semantic) + } +} + +pub type MemberAccessExpression = Rc; + +pub struct MemberAccessExpressionStruct { + pub(crate) ir_node: ir::MemberAccessExpression, + pub(crate) semantic: Rc, +} + +pub fn create_member_access_expression( + ir_node: &ir::MemberAccessExpression, + semantic: &Rc, +) -> MemberAccessExpression { + Rc::new(MemberAccessExpressionStruct { + ir_node: Rc::clone(ir_node), + semantic: Rc::clone(semantic), + }) +} + +impl MemberAccessExpressionStruct { + pub fn node_id(&self) -> NodeId { + self.ir_node.id() + } + + pub fn operand(&self) -> Expression { + create_expression(&self.ir_node.operand, &self.semantic) + } + + pub fn member(&self) -> Identifier { + create_identifier(&self.ir_node.member, &self.semantic) + } + + pub fn get_type(&self) -> Option { + Type::try_create_for_node_id(self.ir_node.id(), &self.semantic) + } +} + +pub type ModifierInvocation = Rc; + +pub struct ModifierInvocationStruct { + pub(crate) ir_node: ir::ModifierInvocation, + pub(crate) semantic: Rc, +} + +pub fn create_modifier_invocation( + ir_node: &ir::ModifierInvocation, + semantic: &Rc, +) -> ModifierInvocation { + Rc::new(ModifierInvocationStruct { + ir_node: Rc::clone(ir_node), + semantic: Rc::clone(semantic), + }) +} + +impl ModifierInvocationStruct { + pub fn node_id(&self) -> NodeId { + self.ir_node.id() + } + + pub fn name(&self) -> IdentifierPath { + create_identifier_path(&self.ir_node.name, &self.semantic) + } + + pub fn arguments(&self) -> Option { + self.ir_node + .arguments + .as_ref() + .map(|ir_node| create_arguments_declaration(ir_node, &self.semantic)) + } + + pub fn get_type(&self) -> Option { + Type::try_create_for_node_id(self.ir_node.id(), &self.semantic) + } +} + +pub type MultiTypedDeclaration = Rc; + +pub struct MultiTypedDeclarationStruct { + pub(crate) ir_node: ir::MultiTypedDeclaration, + pub(crate) semantic: Rc, +} + +pub fn create_multi_typed_declaration( + ir_node: &ir::MultiTypedDeclaration, + semantic: &Rc, +) -> MultiTypedDeclaration { + Rc::new(MultiTypedDeclarationStruct { + ir_node: Rc::clone(ir_node), + semantic: Rc::clone(semantic), + }) +} + +impl MultiTypedDeclarationStruct { + pub fn node_id(&self) -> NodeId { + self.ir_node.id() + } + + pub fn elements(&self) -> MultiTypedDeclarationElements { + create_multi_typed_declaration_elements(&self.ir_node.elements, &self.semantic) + } + + pub fn value(&self) -> Expression { + create_expression(&self.ir_node.value, &self.semantic) + } + + pub fn get_type(&self) -> Option { + Type::try_create_for_node_id(self.ir_node.id(), &self.semantic) + } +} + +pub type MultiTypedDeclarationElement = Rc; + +pub struct MultiTypedDeclarationElementStruct { + pub(crate) ir_node: ir::MultiTypedDeclarationElement, + pub(crate) semantic: Rc, +} + +pub fn create_multi_typed_declaration_element( + ir_node: &ir::MultiTypedDeclarationElement, + semantic: &Rc, +) -> MultiTypedDeclarationElement { + Rc::new(MultiTypedDeclarationElementStruct { + ir_node: Rc::clone(ir_node), + semantic: Rc::clone(semantic), + }) +} + +impl MultiTypedDeclarationElementStruct { + pub fn node_id(&self) -> NodeId { + self.ir_node.id() + } + + pub fn member(&self) -> Option { + self.ir_node + .member + .as_ref() + .map(|ir_node| create_variable_declaration(ir_node, &self.semantic)) + } + + pub fn get_type(&self) -> Option { + Type::try_create_for_node_id(self.ir_node.id(), &self.semantic) + } +} + +pub type MultiplicativeExpression = Rc; + +pub struct MultiplicativeExpressionStruct { + pub(crate) ir_node: ir::MultiplicativeExpression, + pub(crate) semantic: Rc, +} + +pub fn create_multiplicative_expression( + ir_node: &ir::MultiplicativeExpression, + semantic: &Rc, +) -> MultiplicativeExpression { + Rc::new(MultiplicativeExpressionStruct { + ir_node: Rc::clone(ir_node), + semantic: Rc::clone(semantic), + }) +} + +impl MultiplicativeExpressionStruct { + pub fn node_id(&self) -> NodeId { + self.ir_node.id() + } + + pub fn left_operand(&self) -> Expression { + create_expression(&self.ir_node.left_operand, &self.semantic) + } + + pub fn expression_multiplicative_expression_operator( + &self, + ) -> Expression_MultiplicativeExpression_Operator { + create_expression_multiplicative_expression_operator( + &self.ir_node.expression_multiplicative_expression_operator, + &self.semantic, + ) + } + + pub fn right_operand(&self) -> Expression { + create_expression(&self.ir_node.right_operand, &self.semantic) + } + + pub fn get_type(&self) -> Option { + Type::try_create_for_node_id(self.ir_node.id(), &self.semantic) + } +} + +pub type NamedArgument = Rc; + +pub struct NamedArgumentStruct { + pub(crate) ir_node: ir::NamedArgument, + pub(crate) semantic: Rc, +} + +pub fn create_named_argument( + ir_node: &ir::NamedArgument, + semantic: &Rc, +) -> NamedArgument { + Rc::new(NamedArgumentStruct { + ir_node: Rc::clone(ir_node), + semantic: Rc::clone(semantic), + }) +} + +impl NamedArgumentStruct { + pub fn node_id(&self) -> NodeId { + self.ir_node.id() + } + + pub fn name(&self) -> Identifier { + create_identifier(&self.ir_node.name, &self.semantic) + } + + pub fn value(&self) -> Expression { + create_expression(&self.ir_node.value, &self.semantic) + } + + pub fn get_type(&self) -> Option { + Type::try_create_for_node_id(self.ir_node.id(), &self.semantic) + } +} + +pub type NewExpression = Rc; + +pub struct NewExpressionStruct { + pub(crate) ir_node: ir::NewExpression, + pub(crate) semantic: Rc, +} + +pub fn create_new_expression( + ir_node: &ir::NewExpression, + semantic: &Rc, +) -> NewExpression { + Rc::new(NewExpressionStruct { + ir_node: Rc::clone(ir_node), + semantic: Rc::clone(semantic), + }) +} + +impl NewExpressionStruct { + pub fn node_id(&self) -> NodeId { + self.ir_node.id() + } + + pub fn type_name(&self) -> TypeName { + create_type_name(&self.ir_node.type_name, &self.semantic) + } + + pub fn get_type(&self) -> Option { + Type::try_create_for_node_id(self.ir_node.id(), &self.semantic) + } +} + +pub type OrExpression = Rc; + +pub struct OrExpressionStruct { + pub(crate) ir_node: ir::OrExpression, + pub(crate) semantic: Rc, +} + +pub fn create_or_expression( + ir_node: &ir::OrExpression, + semantic: &Rc, +) -> OrExpression { + Rc::new(OrExpressionStruct { + ir_node: Rc::clone(ir_node), + semantic: Rc::clone(semantic), + }) +} + +impl OrExpressionStruct { + pub fn node_id(&self) -> NodeId { + self.ir_node.id() + } + + pub fn left_operand(&self) -> Expression { + create_expression(&self.ir_node.left_operand, &self.semantic) + } + + pub fn right_operand(&self) -> Expression { + create_expression(&self.ir_node.right_operand, &self.semantic) + } + + pub fn get_type(&self) -> Option { + Type::try_create_for_node_id(self.ir_node.id(), &self.semantic) + } +} + +pub type Parameter = Rc; + +pub struct ParameterStruct { + pub(crate) ir_node: ir::Parameter, + pub(crate) semantic: Rc, +} + +pub fn create_parameter(ir_node: &ir::Parameter, semantic: &Rc) -> Parameter { + Rc::new(ParameterStruct { + ir_node: Rc::clone(ir_node), + semantic: Rc::clone(semantic), + }) +} + +impl ParameterStruct { + pub fn node_id(&self) -> NodeId { + self.ir_node.id() + } + + pub fn type_name(&self) -> TypeName { + create_type_name(&self.ir_node.type_name, &self.semantic) + } + + pub fn storage_location(&self) -> Option { + self.ir_node + .storage_location + .as_ref() + .map(|ir_node| create_storage_location(ir_node, &self.semantic)) + } + + pub fn name(&self) -> Option { + self.ir_node + .name + .as_ref() + .map(|ir_node| create_identifier(ir_node, &self.semantic)) + } + + pub fn indexed(&self) -> bool { + self.ir_node.indexed + } + + pub fn get_type(&self) -> Option { + Type::try_create_for_node_id(self.ir_node.id(), &self.semantic) + } +} + +pub type PathImport = Rc; + +pub struct PathImportStruct { + pub(crate) ir_node: ir::PathImport, + pub(crate) semantic: Rc, +} + +pub fn create_path_import(ir_node: &ir::PathImport, semantic: &Rc) -> PathImport { + Rc::new(PathImportStruct { + ir_node: Rc::clone(ir_node), + semantic: Rc::clone(semantic), + }) +} + +impl PathImportStruct { + pub fn node_id(&self) -> NodeId { + self.ir_node.id() + } + + pub fn path(&self) -> ir::StringLiteral { + Rc::clone(&self.ir_node.path) + } + + pub fn alias(&self) -> Option { + self.ir_node + .alias + .as_ref() + .map(|ir_node| create_identifier(ir_node, &self.semantic)) + } + + pub fn get_type(&self) -> Option { + Type::try_create_for_node_id(self.ir_node.id(), &self.semantic) + } +} + +pub type PostfixExpression = Rc; + +pub struct PostfixExpressionStruct { + pub(crate) ir_node: ir::PostfixExpression, + pub(crate) semantic: Rc, +} + +pub fn create_postfix_expression( + ir_node: &ir::PostfixExpression, + semantic: &Rc, +) -> PostfixExpression { + Rc::new(PostfixExpressionStruct { + ir_node: Rc::clone(ir_node), + semantic: Rc::clone(semantic), + }) +} + +impl PostfixExpressionStruct { + pub fn node_id(&self) -> NodeId { + self.ir_node.id() + } + + pub fn operand(&self) -> Expression { + create_expression(&self.ir_node.operand, &self.semantic) + } + + pub fn expression_postfix_expression_operator(&self) -> Expression_PostfixExpression_Operator { + create_expression_postfix_expression_operator( + &self.ir_node.expression_postfix_expression_operator, + &self.semantic, + ) + } + + pub fn get_type(&self) -> Option { + Type::try_create_for_node_id(self.ir_node.id(), &self.semantic) + } +} + +pub type PragmaDirective = Rc; + +pub struct PragmaDirectiveStruct { + pub(crate) ir_node: ir::PragmaDirective, + pub(crate) semantic: Rc, +} + +pub fn create_pragma_directive( + ir_node: &ir::PragmaDirective, + semantic: &Rc, +) -> PragmaDirective { + Rc::new(PragmaDirectiveStruct { + ir_node: Rc::clone(ir_node), + semantic: Rc::clone(semantic), + }) +} + +impl PragmaDirectiveStruct { + pub fn node_id(&self) -> NodeId { + self.ir_node.id() + } + + pub fn pragma(&self) -> Pragma { + create_pragma(&self.ir_node.pragma, &self.semantic) + } + + pub fn get_type(&self) -> Option { + Type::try_create_for_node_id(self.ir_node.id(), &self.semantic) + } +} + +pub type PrefixExpression = Rc; + +pub struct PrefixExpressionStruct { + pub(crate) ir_node: ir::PrefixExpression, + pub(crate) semantic: Rc, +} + +pub fn create_prefix_expression( + ir_node: &ir::PrefixExpression, + semantic: &Rc, +) -> PrefixExpression { + Rc::new(PrefixExpressionStruct { + ir_node: Rc::clone(ir_node), + semantic: Rc::clone(semantic), + }) +} + +impl PrefixExpressionStruct { + pub fn node_id(&self) -> NodeId { + self.ir_node.id() + } + + pub fn expression_prefix_expression_operator(&self) -> Expression_PrefixExpression_Operator { + create_expression_prefix_expression_operator( + &self.ir_node.expression_prefix_expression_operator, + &self.semantic, + ) + } + + pub fn operand(&self) -> Expression { + create_expression(&self.ir_node.operand, &self.semantic) + } + + pub fn get_type(&self) -> Option { + Type::try_create_for_node_id(self.ir_node.id(), &self.semantic) + } +} + +pub type ReturnStatement = Rc; + +pub struct ReturnStatementStruct { + pub(crate) ir_node: ir::ReturnStatement, + pub(crate) semantic: Rc, +} + +pub fn create_return_statement( + ir_node: &ir::ReturnStatement, + semantic: &Rc, +) -> ReturnStatement { + Rc::new(ReturnStatementStruct { + ir_node: Rc::clone(ir_node), + semantic: Rc::clone(semantic), + }) +} + +impl ReturnStatementStruct { + pub fn node_id(&self) -> NodeId { + self.ir_node.id() + } + + pub fn expression(&self) -> Option { + self.ir_node + .expression + .as_ref() + .map(|ir_node| create_expression(ir_node, &self.semantic)) + } + + pub fn get_type(&self) -> Option { + Type::try_create_for_node_id(self.ir_node.id(), &self.semantic) + } +} + +pub type RevertStatement = Rc; + +pub struct RevertStatementStruct { + pub(crate) ir_node: ir::RevertStatement, + pub(crate) semantic: Rc, +} + +pub fn create_revert_statement( + ir_node: &ir::RevertStatement, + semantic: &Rc, +) -> RevertStatement { + Rc::new(RevertStatementStruct { + ir_node: Rc::clone(ir_node), + semantic: Rc::clone(semantic), + }) +} + +impl RevertStatementStruct { + pub fn node_id(&self) -> NodeId { + self.ir_node.id() + } + + pub fn error(&self) -> IdentifierPath { + create_identifier_path(&self.ir_node.error, &self.semantic) + } + + pub fn arguments(&self) -> ArgumentsDeclaration { + create_arguments_declaration(&self.ir_node.arguments, &self.semantic) + } + + pub fn get_type(&self) -> Option { + Type::try_create_for_node_id(self.ir_node.id(), &self.semantic) + } +} + +pub type ShiftExpression = Rc; + +pub struct ShiftExpressionStruct { + pub(crate) ir_node: ir::ShiftExpression, + pub(crate) semantic: Rc, +} + +pub fn create_shift_expression( + ir_node: &ir::ShiftExpression, + semantic: &Rc, +) -> ShiftExpression { + Rc::new(ShiftExpressionStruct { + ir_node: Rc::clone(ir_node), + semantic: Rc::clone(semantic), + }) +} + +impl ShiftExpressionStruct { + pub fn node_id(&self) -> NodeId { + self.ir_node.id() + } + + pub fn left_operand(&self) -> Expression { + create_expression(&self.ir_node.left_operand, &self.semantic) + } + + pub fn expression_shift_expression_operator(&self) -> Expression_ShiftExpression_Operator { + create_expression_shift_expression_operator( + &self.ir_node.expression_shift_expression_operator, + &self.semantic, + ) + } + + pub fn right_operand(&self) -> Expression { + create_expression(&self.ir_node.right_operand, &self.semantic) + } + + pub fn get_type(&self) -> Option { + Type::try_create_for_node_id(self.ir_node.id(), &self.semantic) + } +} + +pub type SingleTypedDeclaration = Rc; + +pub struct SingleTypedDeclarationStruct { + pub(crate) ir_node: ir::SingleTypedDeclaration, + pub(crate) semantic: Rc, +} + +pub fn create_single_typed_declaration( + ir_node: &ir::SingleTypedDeclaration, + semantic: &Rc, +) -> SingleTypedDeclaration { + Rc::new(SingleTypedDeclarationStruct { + ir_node: Rc::clone(ir_node), + semantic: Rc::clone(semantic), + }) +} + +impl SingleTypedDeclarationStruct { + pub fn node_id(&self) -> NodeId { + self.ir_node.id() + } + + pub fn declaration(&self) -> VariableDeclaration { + create_variable_declaration(&self.ir_node.declaration, &self.semantic) + } + + pub fn value(&self) -> Option { + self.ir_node + .value + .as_ref() + .map(|ir_node| create_expression(ir_node, &self.semantic)) + } + + pub fn get_type(&self) -> Option { + Type::try_create_for_node_id(self.ir_node.id(), &self.semantic) + } +} + +pub type SourceUnit = Rc; + +pub struct SourceUnitStruct { + pub(crate) ir_node: ir::SourceUnit, + pub(crate) semantic: Rc, +} + +pub fn create_source_unit(ir_node: &ir::SourceUnit, semantic: &Rc) -> SourceUnit { + Rc::new(SourceUnitStruct { + ir_node: Rc::clone(ir_node), + semantic: Rc::clone(semantic), + }) +} + +impl SourceUnitStruct { + pub fn node_id(&self) -> NodeId { + self.ir_node.id() + } + + pub fn members(&self) -> SourceUnitMembers { + create_source_unit_members(&self.ir_node.members, &self.semantic) + } + + pub fn get_type(&self) -> Option { + Type::try_create_for_node_id(self.ir_node.id(), &self.semantic) + } +} + +pub type StateVariableDefinition = Rc; + +pub struct StateVariableDefinitionStruct { + pub(crate) ir_node: ir::StateVariableDefinition, + pub(crate) semantic: Rc, +} + +pub fn create_state_variable_definition( + ir_node: &ir::StateVariableDefinition, + semantic: &Rc, +) -> StateVariableDefinition { + Rc::new(StateVariableDefinitionStruct { + ir_node: Rc::clone(ir_node), + semantic: Rc::clone(semantic), + }) +} + +impl StateVariableDefinitionStruct { + pub fn node_id(&self) -> NodeId { + self.ir_node.id() + } + + pub fn type_name(&self) -> TypeName { + create_type_name(&self.ir_node.type_name, &self.semantic) + } + + pub fn name(&self) -> Identifier { + create_identifier(&self.ir_node.name, &self.semantic) + } + + pub fn value(&self) -> Option { + self.ir_node + .value + .as_ref() + .map(|ir_node| create_expression(ir_node, &self.semantic)) + } + + pub fn visibility(&self) -> StateVariableVisibility { + create_state_variable_visibility(&self.ir_node.visibility, &self.semantic) + } + + pub fn mutability(&self) -> StateVariableMutability { + create_state_variable_mutability(&self.ir_node.mutability, &self.semantic) + } + + pub fn override_specifier(&self) -> Option { + self.ir_node + .override_specifier + .as_ref() + .map(|ir_node| create_override_paths(ir_node, &self.semantic)) + } + + pub fn get_type(&self) -> Option { + Type::try_create_for_node_id(self.ir_node.id(), &self.semantic) + } +} + +pub type StructDefinition = Rc; + +pub struct StructDefinitionStruct { + pub(crate) ir_node: ir::StructDefinition, + pub(crate) semantic: Rc, +} + +pub fn create_struct_definition( + ir_node: &ir::StructDefinition, + semantic: &Rc, +) -> StructDefinition { + Rc::new(StructDefinitionStruct { + ir_node: Rc::clone(ir_node), + semantic: Rc::clone(semantic), + }) +} + +impl StructDefinitionStruct { + pub fn node_id(&self) -> NodeId { + self.ir_node.id() + } + + pub fn name(&self) -> Identifier { + create_identifier(&self.ir_node.name, &self.semantic) + } + + pub fn members(&self) -> StructMembers { + create_struct_members(&self.ir_node.members, &self.semantic) + } + + pub fn get_type(&self) -> Option { + Type::try_create_for_node_id(self.ir_node.id(), &self.semantic) + } +} + +pub type StructMember = Rc; + +pub struct StructMemberStruct { + pub(crate) ir_node: ir::StructMember, + pub(crate) semantic: Rc, +} + +pub fn create_struct_member( + ir_node: &ir::StructMember, + semantic: &Rc, +) -> StructMember { + Rc::new(StructMemberStruct { + ir_node: Rc::clone(ir_node), + semantic: Rc::clone(semantic), + }) +} + +impl StructMemberStruct { + pub fn node_id(&self) -> NodeId { + self.ir_node.id() + } + + pub fn type_name(&self) -> TypeName { + create_type_name(&self.ir_node.type_name, &self.semantic) + } + + pub fn name(&self) -> Identifier { + create_identifier(&self.ir_node.name, &self.semantic) + } + + pub fn get_type(&self) -> Option { + Type::try_create_for_node_id(self.ir_node.id(), &self.semantic) + } +} + +pub type TryStatement = Rc; + +pub struct TryStatementStruct { + pub(crate) ir_node: ir::TryStatement, + pub(crate) semantic: Rc, +} + +pub fn create_try_statement( + ir_node: &ir::TryStatement, + semantic: &Rc, +) -> TryStatement { + Rc::new(TryStatementStruct { + ir_node: Rc::clone(ir_node), + semantic: Rc::clone(semantic), + }) +} + +impl TryStatementStruct { + pub fn node_id(&self) -> NodeId { + self.ir_node.id() + } + + pub fn expression(&self) -> Expression { + create_expression(&self.ir_node.expression, &self.semantic) + } + + pub fn returns(&self) -> Option { + self.ir_node + .returns + .as_ref() + .map(|ir_node| create_parameters(ir_node, &self.semantic)) + } + + pub fn body(&self) -> Block { + create_block(&self.ir_node.body, &self.semantic) + } + + pub fn catch_clauses(&self) -> CatchClauses { + create_catch_clauses(&self.ir_node.catch_clauses, &self.semantic) + } + + pub fn get_type(&self) -> Option { + Type::try_create_for_node_id(self.ir_node.id(), &self.semantic) + } +} + +pub type TupleExpression = Rc; + +pub struct TupleExpressionStruct { + pub(crate) ir_node: ir::TupleExpression, + pub(crate) semantic: Rc, +} + +pub fn create_tuple_expression( + ir_node: &ir::TupleExpression, + semantic: &Rc, +) -> TupleExpression { + Rc::new(TupleExpressionStruct { + ir_node: Rc::clone(ir_node), + semantic: Rc::clone(semantic), + }) +} + +impl TupleExpressionStruct { + pub fn node_id(&self) -> NodeId { + self.ir_node.id() + } + + pub fn items(&self) -> TupleValues { + create_tuple_values(&self.ir_node.items, &self.semantic) + } + + pub fn get_type(&self) -> Option { + Type::try_create_for_node_id(self.ir_node.id(), &self.semantic) + } +} + +pub type TupleValue = Rc; + +pub struct TupleValueStruct { + pub(crate) ir_node: ir::TupleValue, + pub(crate) semantic: Rc, +} + +pub fn create_tuple_value(ir_node: &ir::TupleValue, semantic: &Rc) -> TupleValue { + Rc::new(TupleValueStruct { + ir_node: Rc::clone(ir_node), + semantic: Rc::clone(semantic), + }) +} + +impl TupleValueStruct { + pub fn node_id(&self) -> NodeId { + self.ir_node.id() + } + + pub fn expression(&self) -> Option { + self.ir_node + .expression + .as_ref() + .map(|ir_node| create_expression(ir_node, &self.semantic)) + } + + pub fn get_type(&self) -> Option { + Type::try_create_for_node_id(self.ir_node.id(), &self.semantic) + } +} + +pub type TypeExpression = Rc; + +pub struct TypeExpressionStruct { + pub(crate) ir_node: ir::TypeExpression, + pub(crate) semantic: Rc, +} + +pub fn create_type_expression( + ir_node: &ir::TypeExpression, + semantic: &Rc, +) -> TypeExpression { + Rc::new(TypeExpressionStruct { + ir_node: Rc::clone(ir_node), + semantic: Rc::clone(semantic), + }) +} + +impl TypeExpressionStruct { + pub fn node_id(&self) -> NodeId { + self.ir_node.id() + } + + pub fn type_name(&self) -> TypeName { + create_type_name(&self.ir_node.type_name, &self.semantic) + } + + pub fn get_type(&self) -> Option { + Type::try_create_for_node_id(self.ir_node.id(), &self.semantic) + } +} + +pub type UncheckedBlock = Rc; + +pub struct UncheckedBlockStruct { + pub(crate) ir_node: ir::UncheckedBlock, + pub(crate) semantic: Rc, +} + +pub fn create_unchecked_block( + ir_node: &ir::UncheckedBlock, + semantic: &Rc, +) -> UncheckedBlock { + Rc::new(UncheckedBlockStruct { + ir_node: Rc::clone(ir_node), + semantic: Rc::clone(semantic), + }) +} + +impl UncheckedBlockStruct { + pub fn node_id(&self) -> NodeId { + self.ir_node.id() + } + + pub fn block(&self) -> Block { + create_block(&self.ir_node.block, &self.semantic) + } + + pub fn get_type(&self) -> Option { + Type::try_create_for_node_id(self.ir_node.id(), &self.semantic) + } +} + +pub type UserDefinedValueTypeDefinition = Rc; + +pub struct UserDefinedValueTypeDefinitionStruct { + pub(crate) ir_node: ir::UserDefinedValueTypeDefinition, + pub(crate) semantic: Rc, +} + +pub fn create_user_defined_value_type_definition( + ir_node: &ir::UserDefinedValueTypeDefinition, + semantic: &Rc, +) -> UserDefinedValueTypeDefinition { + Rc::new(UserDefinedValueTypeDefinitionStruct { + ir_node: Rc::clone(ir_node), + semantic: Rc::clone(semantic), + }) +} + +impl UserDefinedValueTypeDefinitionStruct { + pub fn node_id(&self) -> NodeId { + self.ir_node.id() + } + + pub fn name(&self) -> Identifier { + create_identifier(&self.ir_node.name, &self.semantic) + } + + pub fn value_type(&self) -> ElementaryType { + create_elementary_type(&self.ir_node.value_type, &self.semantic) + } + + pub fn get_type(&self) -> Option { + Type::try_create_for_node_id(self.ir_node.id(), &self.semantic) + } +} + +pub type UsingDeconstruction = Rc; + +pub struct UsingDeconstructionStruct { + pub(crate) ir_node: ir::UsingDeconstruction, + pub(crate) semantic: Rc, +} + +pub fn create_using_deconstruction( + ir_node: &ir::UsingDeconstruction, + semantic: &Rc, +) -> UsingDeconstruction { + Rc::new(UsingDeconstructionStruct { + ir_node: Rc::clone(ir_node), + semantic: Rc::clone(semantic), + }) +} + +impl UsingDeconstructionStruct { + pub fn node_id(&self) -> NodeId { + self.ir_node.id() + } + + pub fn symbols(&self) -> UsingDeconstructionSymbols { + create_using_deconstruction_symbols(&self.ir_node.symbols, &self.semantic) + } + + pub fn get_type(&self) -> Option { + Type::try_create_for_node_id(self.ir_node.id(), &self.semantic) + } +} + +pub type UsingDeconstructionSymbol = Rc; + +pub struct UsingDeconstructionSymbolStruct { + pub(crate) ir_node: ir::UsingDeconstructionSymbol, + pub(crate) semantic: Rc, +} + +pub fn create_using_deconstruction_symbol( + ir_node: &ir::UsingDeconstructionSymbol, + semantic: &Rc, +) -> UsingDeconstructionSymbol { + Rc::new(UsingDeconstructionSymbolStruct { + ir_node: Rc::clone(ir_node), + semantic: Rc::clone(semantic), + }) +} + +impl UsingDeconstructionSymbolStruct { + pub fn node_id(&self) -> NodeId { + self.ir_node.id() + } + + pub fn name(&self) -> IdentifierPath { + create_identifier_path(&self.ir_node.name, &self.semantic) + } + + pub fn alias(&self) -> Option { + self.ir_node + .alias + .as_ref() + .map(|ir_node| create_using_operator(ir_node, &self.semantic)) + } + + pub fn get_type(&self) -> Option { + Type::try_create_for_node_id(self.ir_node.id(), &self.semantic) + } +} + +pub type UsingDirective = Rc; + +pub struct UsingDirectiveStruct { + pub(crate) ir_node: ir::UsingDirective, + pub(crate) semantic: Rc, +} + +pub fn create_using_directive( + ir_node: &ir::UsingDirective, + semantic: &Rc, +) -> UsingDirective { + Rc::new(UsingDirectiveStruct { + ir_node: Rc::clone(ir_node), + semantic: Rc::clone(semantic), + }) +} + +impl UsingDirectiveStruct { + pub fn node_id(&self) -> NodeId { + self.ir_node.id() + } + + pub fn clause(&self) -> UsingClause { + create_using_clause(&self.ir_node.clause, &self.semantic) + } + + pub fn target(&self) -> UsingTarget { + create_using_target(&self.ir_node.target, &self.semantic) + } + + pub fn global_keyword(&self) -> bool { + self.ir_node.global_keyword + } + + pub fn get_type(&self) -> Option { + Type::try_create_for_node_id(self.ir_node.id(), &self.semantic) + } +} + +pub type VariableDeclaration = Rc; + +pub struct VariableDeclarationStruct { + pub(crate) ir_node: ir::VariableDeclaration, + pub(crate) semantic: Rc, +} + +pub fn create_variable_declaration( + ir_node: &ir::VariableDeclaration, + semantic: &Rc, +) -> VariableDeclaration { + Rc::new(VariableDeclarationStruct { + ir_node: Rc::clone(ir_node), + semantic: Rc::clone(semantic), + }) +} + +impl VariableDeclarationStruct { + pub fn node_id(&self) -> NodeId { + self.ir_node.id() + } + + pub fn type_name(&self) -> TypeName { + create_type_name(&self.ir_node.type_name, &self.semantic) + } + + pub fn storage_location(&self) -> Option { + self.ir_node + .storage_location + .as_ref() + .map(|ir_node| create_storage_location(ir_node, &self.semantic)) + } + + pub fn name(&self) -> Identifier { + create_identifier(&self.ir_node.name, &self.semantic) + } + + pub fn get_type(&self) -> Option { + Type::try_create_for_node_id(self.ir_node.id(), &self.semantic) + } +} + +pub type VariableDeclarationStatement = Rc; + +pub struct VariableDeclarationStatementStruct { + pub(crate) ir_node: ir::VariableDeclarationStatement, + pub(crate) semantic: Rc, +} + +pub fn create_variable_declaration_statement( + ir_node: &ir::VariableDeclarationStatement, + semantic: &Rc, +) -> VariableDeclarationStatement { + Rc::new(VariableDeclarationStatementStruct { + ir_node: Rc::clone(ir_node), + semantic: Rc::clone(semantic), + }) +} + +impl VariableDeclarationStatementStruct { + pub fn node_id(&self) -> NodeId { + self.ir_node.id() + } + + pub fn target(&self) -> VariableDeclarationTarget { + create_variable_declaration_target(&self.ir_node.target, &self.semantic) + } + + pub fn get_type(&self) -> Option { + Type::try_create_for_node_id(self.ir_node.id(), &self.semantic) + } +} + +pub type VersionPragma = Rc; + +pub struct VersionPragmaStruct { + pub(crate) ir_node: ir::VersionPragma, + pub(crate) semantic: Rc, +} + +pub fn create_version_pragma( + ir_node: &ir::VersionPragma, + semantic: &Rc, +) -> VersionPragma { + Rc::new(VersionPragmaStruct { + ir_node: Rc::clone(ir_node), + semantic: Rc::clone(semantic), + }) +} + +impl VersionPragmaStruct { + pub fn node_id(&self) -> NodeId { + self.ir_node.id() + } + + pub fn sets(&self) -> VersionExpressionSets { + create_version_expression_sets(&self.ir_node.sets, &self.semantic) + } + + pub fn get_type(&self) -> Option { + Type::try_create_for_node_id(self.ir_node.id(), &self.semantic) + } +} + +pub type VersionRange = Rc; + +pub struct VersionRangeStruct { + pub(crate) ir_node: ir::VersionRange, + pub(crate) semantic: Rc, +} + +pub fn create_version_range( + ir_node: &ir::VersionRange, + semantic: &Rc, +) -> VersionRange { + Rc::new(VersionRangeStruct { + ir_node: Rc::clone(ir_node), + semantic: Rc::clone(semantic), + }) +} + +impl VersionRangeStruct { + pub fn node_id(&self) -> NodeId { + self.ir_node.id() + } + + pub fn start(&self) -> VersionLiteral { + create_version_literal(&self.ir_node.start, &self.semantic) + } + + pub fn end(&self) -> VersionLiteral { + create_version_literal(&self.ir_node.end, &self.semantic) + } + + pub fn get_type(&self) -> Option { + Type::try_create_for_node_id(self.ir_node.id(), &self.semantic) + } +} + +pub type VersionTerm = Rc; + +pub struct VersionTermStruct { + pub(crate) ir_node: ir::VersionTerm, + pub(crate) semantic: Rc, +} + +pub fn create_version_term( + ir_node: &ir::VersionTerm, + semantic: &Rc, +) -> VersionTerm { + Rc::new(VersionTermStruct { + ir_node: Rc::clone(ir_node), + semantic: Rc::clone(semantic), + }) +} + +impl VersionTermStruct { + pub fn node_id(&self) -> NodeId { + self.ir_node.id() + } + + pub fn operator(&self) -> Option { + self.ir_node + .operator + .as_ref() + .map(|ir_node| create_version_operator(ir_node, &self.semantic)) + } + + pub fn literal(&self) -> VersionLiteral { + create_version_literal(&self.ir_node.literal, &self.semantic) + } + + pub fn get_type(&self) -> Option { + Type::try_create_for_node_id(self.ir_node.id(), &self.semantic) + } +} + +pub type WhileStatement = Rc; + +pub struct WhileStatementStruct { + pub(crate) ir_node: ir::WhileStatement, + pub(crate) semantic: Rc, +} + +pub fn create_while_statement( + ir_node: &ir::WhileStatement, + semantic: &Rc, +) -> WhileStatement { + Rc::new(WhileStatementStruct { + ir_node: Rc::clone(ir_node), + semantic: Rc::clone(semantic), + }) +} + +impl WhileStatementStruct { + pub fn node_id(&self) -> NodeId { + self.ir_node.id() + } + + pub fn condition(&self) -> Expression { + create_expression(&self.ir_node.condition, &self.semantic) + } + + pub fn body(&self) -> Statement { + create_statement(&self.ir_node.body, &self.semantic) + } + + pub fn get_type(&self) -> Option { + Type::try_create_for_node_id(self.ir_node.id(), &self.semantic) + } +} + +pub type YulBlock = Rc; + +pub struct YulBlockStruct { + pub(crate) ir_node: ir::YulBlock, + pub(crate) semantic: Rc, +} + +pub fn create_yul_block(ir_node: &ir::YulBlock, semantic: &Rc) -> YulBlock { + Rc::new(YulBlockStruct { + ir_node: Rc::clone(ir_node), + semantic: Rc::clone(semantic), + }) +} + +impl YulBlockStruct { + pub fn node_id(&self) -> NodeId { + self.ir_node.id() + } + + pub fn statements(&self) -> YulStatements { + create_yul_statements(&self.ir_node.statements, &self.semantic) + } + + pub fn get_type(&self) -> Option { + Type::try_create_for_node_id(self.ir_node.id(), &self.semantic) + } +} + +pub type YulBreakStatement = Rc; + +pub struct YulBreakStatementStruct { + pub(crate) ir_node: ir::YulBreakStatement, + pub(crate) semantic: Rc, +} + +pub fn create_yul_break_statement( + ir_node: &ir::YulBreakStatement, + semantic: &Rc, +) -> YulBreakStatement { + Rc::new(YulBreakStatementStruct { + ir_node: Rc::clone(ir_node), + semantic: Rc::clone(semantic), + }) +} + +impl YulBreakStatementStruct { + pub fn node_id(&self) -> NodeId { + self.ir_node.id() + } + + pub fn get_type(&self) -> Option { + Type::try_create_for_node_id(self.ir_node.id(), &self.semantic) + } +} + +pub type YulContinueStatement = Rc; + +pub struct YulContinueStatementStruct { + pub(crate) ir_node: ir::YulContinueStatement, + pub(crate) semantic: Rc, +} + +pub fn create_yul_continue_statement( + ir_node: &ir::YulContinueStatement, + semantic: &Rc, +) -> YulContinueStatement { + Rc::new(YulContinueStatementStruct { + ir_node: Rc::clone(ir_node), + semantic: Rc::clone(semantic), + }) +} + +impl YulContinueStatementStruct { + pub fn node_id(&self) -> NodeId { + self.ir_node.id() + } + + pub fn get_type(&self) -> Option { + Type::try_create_for_node_id(self.ir_node.id(), &self.semantic) + } +} + +pub type YulDefaultCase = Rc; + +pub struct YulDefaultCaseStruct { + pub(crate) ir_node: ir::YulDefaultCase, + pub(crate) semantic: Rc, +} + +pub fn create_yul_default_case( + ir_node: &ir::YulDefaultCase, + semantic: &Rc, +) -> YulDefaultCase { + Rc::new(YulDefaultCaseStruct { + ir_node: Rc::clone(ir_node), + semantic: Rc::clone(semantic), + }) +} + +impl YulDefaultCaseStruct { + pub fn node_id(&self) -> NodeId { + self.ir_node.id() + } + + pub fn body(&self) -> YulBlock { + create_yul_block(&self.ir_node.body, &self.semantic) + } + + pub fn get_type(&self) -> Option { + Type::try_create_for_node_id(self.ir_node.id(), &self.semantic) + } +} + +pub type YulForStatement = Rc; + +pub struct YulForStatementStruct { + pub(crate) ir_node: ir::YulForStatement, + pub(crate) semantic: Rc, +} + +pub fn create_yul_for_statement( + ir_node: &ir::YulForStatement, + semantic: &Rc, +) -> YulForStatement { + Rc::new(YulForStatementStruct { + ir_node: Rc::clone(ir_node), + semantic: Rc::clone(semantic), + }) +} + +impl YulForStatementStruct { + pub fn node_id(&self) -> NodeId { + self.ir_node.id() + } + + pub fn initialization(&self) -> YulBlock { + create_yul_block(&self.ir_node.initialization, &self.semantic) + } + + pub fn condition(&self) -> YulExpression { + create_yul_expression(&self.ir_node.condition, &self.semantic) + } + + pub fn iterator(&self) -> YulBlock { + create_yul_block(&self.ir_node.iterator, &self.semantic) + } + + pub fn body(&self) -> YulBlock { + create_yul_block(&self.ir_node.body, &self.semantic) + } + + pub fn get_type(&self) -> Option { + Type::try_create_for_node_id(self.ir_node.id(), &self.semantic) + } +} + +pub type YulFunctionCallExpression = Rc; + +pub struct YulFunctionCallExpressionStruct { + pub(crate) ir_node: ir::YulFunctionCallExpression, + pub(crate) semantic: Rc, +} + +pub fn create_yul_function_call_expression( + ir_node: &ir::YulFunctionCallExpression, + semantic: &Rc, +) -> YulFunctionCallExpression { + Rc::new(YulFunctionCallExpressionStruct { + ir_node: Rc::clone(ir_node), + semantic: Rc::clone(semantic), + }) +} + +impl YulFunctionCallExpressionStruct { + pub fn node_id(&self) -> NodeId { + self.ir_node.id() + } + + pub fn operand(&self) -> YulExpression { + create_yul_expression(&self.ir_node.operand, &self.semantic) + } + + pub fn arguments(&self) -> YulArguments { + create_yul_arguments(&self.ir_node.arguments, &self.semantic) + } + + pub fn get_type(&self) -> Option { + Type::try_create_for_node_id(self.ir_node.id(), &self.semantic) + } +} + +pub type YulFunctionDefinition = Rc; + +pub struct YulFunctionDefinitionStruct { + pub(crate) ir_node: ir::YulFunctionDefinition, + pub(crate) semantic: Rc, +} + +pub fn create_yul_function_definition( + ir_node: &ir::YulFunctionDefinition, + semantic: &Rc, +) -> YulFunctionDefinition { + Rc::new(YulFunctionDefinitionStruct { + ir_node: Rc::clone(ir_node), + semantic: Rc::clone(semantic), + }) +} + +impl YulFunctionDefinitionStruct { + pub fn node_id(&self) -> NodeId { + self.ir_node.id() + } + + pub fn name(&self) -> Identifier { + create_identifier(&self.ir_node.name, &self.semantic) + } + + pub fn parameters(&self) -> YulParameters { + create_yul_parameters(&self.ir_node.parameters, &self.semantic) + } + + pub fn returns(&self) -> Option { + self.ir_node + .returns + .as_ref() + .map(|ir_node| create_yul_variable_names(ir_node, &self.semantic)) + } + + pub fn body(&self) -> YulBlock { + create_yul_block(&self.ir_node.body, &self.semantic) + } + + pub fn get_type(&self) -> Option { + Type::try_create_for_node_id(self.ir_node.id(), &self.semantic) + } +} + +pub type YulIfStatement = Rc; + +pub struct YulIfStatementStruct { + pub(crate) ir_node: ir::YulIfStatement, + pub(crate) semantic: Rc, +} + +pub fn create_yul_if_statement( + ir_node: &ir::YulIfStatement, + semantic: &Rc, +) -> YulIfStatement { + Rc::new(YulIfStatementStruct { + ir_node: Rc::clone(ir_node), + semantic: Rc::clone(semantic), + }) +} + +impl YulIfStatementStruct { + pub fn node_id(&self) -> NodeId { + self.ir_node.id() + } + + pub fn condition(&self) -> YulExpression { + create_yul_expression(&self.ir_node.condition, &self.semantic) + } + + pub fn body(&self) -> YulBlock { + create_yul_block(&self.ir_node.body, &self.semantic) + } + + pub fn get_type(&self) -> Option { + Type::try_create_for_node_id(self.ir_node.id(), &self.semantic) + } +} + +pub type YulLeaveStatement = Rc; + +pub struct YulLeaveStatementStruct { + pub(crate) ir_node: ir::YulLeaveStatement, + pub(crate) semantic: Rc, +} + +pub fn create_yul_leave_statement( + ir_node: &ir::YulLeaveStatement, + semantic: &Rc, +) -> YulLeaveStatement { + Rc::new(YulLeaveStatementStruct { + ir_node: Rc::clone(ir_node), + semantic: Rc::clone(semantic), + }) +} + +impl YulLeaveStatementStruct { + pub fn node_id(&self) -> NodeId { + self.ir_node.id() + } + + pub fn get_type(&self) -> Option { + Type::try_create_for_node_id(self.ir_node.id(), &self.semantic) + } +} + +pub type YulSwitchStatement = Rc; + +pub struct YulSwitchStatementStruct { + pub(crate) ir_node: ir::YulSwitchStatement, + pub(crate) semantic: Rc, +} + +pub fn create_yul_switch_statement( + ir_node: &ir::YulSwitchStatement, + semantic: &Rc, +) -> YulSwitchStatement { + Rc::new(YulSwitchStatementStruct { + ir_node: Rc::clone(ir_node), + semantic: Rc::clone(semantic), + }) +} + +impl YulSwitchStatementStruct { + pub fn node_id(&self) -> NodeId { + self.ir_node.id() + } + + pub fn expression(&self) -> YulExpression { + create_yul_expression(&self.ir_node.expression, &self.semantic) + } + + pub fn cases(&self) -> YulSwitchCases { + create_yul_switch_cases(&self.ir_node.cases, &self.semantic) + } + + pub fn get_type(&self) -> Option { + Type::try_create_for_node_id(self.ir_node.id(), &self.semantic) + } +} + +pub type YulValueCase = Rc; + +pub struct YulValueCaseStruct { + pub(crate) ir_node: ir::YulValueCase, + pub(crate) semantic: Rc, +} + +pub fn create_yul_value_case( + ir_node: &ir::YulValueCase, + semantic: &Rc, +) -> YulValueCase { + Rc::new(YulValueCaseStruct { + ir_node: Rc::clone(ir_node), + semantic: Rc::clone(semantic), + }) +} + +impl YulValueCaseStruct { + pub fn node_id(&self) -> NodeId { + self.ir_node.id() + } + + pub fn value(&self) -> YulLiteral { + create_yul_literal(&self.ir_node.value, &self.semantic) + } + + pub fn body(&self) -> YulBlock { + create_yul_block(&self.ir_node.body, &self.semantic) + } + + pub fn get_type(&self) -> Option { + Type::try_create_for_node_id(self.ir_node.id(), &self.semantic) + } +} + +pub type YulVariableAssignmentStatement = Rc; + +pub struct YulVariableAssignmentStatementStruct { + pub(crate) ir_node: ir::YulVariableAssignmentStatement, + pub(crate) semantic: Rc, +} + +pub fn create_yul_variable_assignment_statement( + ir_node: &ir::YulVariableAssignmentStatement, + semantic: &Rc, +) -> YulVariableAssignmentStatement { + Rc::new(YulVariableAssignmentStatementStruct { + ir_node: Rc::clone(ir_node), + semantic: Rc::clone(semantic), + }) +} + +impl YulVariableAssignmentStatementStruct { + pub fn node_id(&self) -> NodeId { + self.ir_node.id() + } + + pub fn variables(&self) -> YulPaths { + create_yul_paths(&self.ir_node.variables, &self.semantic) + } + + pub fn expression(&self) -> YulExpression { + create_yul_expression(&self.ir_node.expression, &self.semantic) + } + + pub fn get_type(&self) -> Option { + Type::try_create_for_node_id(self.ir_node.id(), &self.semantic) + } +} + +pub type YulVariableDeclarationStatement = Rc; + +pub struct YulVariableDeclarationStatementStruct { + pub(crate) ir_node: ir::YulVariableDeclarationStatement, + pub(crate) semantic: Rc, +} + +pub fn create_yul_variable_declaration_statement( + ir_node: &ir::YulVariableDeclarationStatement, + semantic: &Rc, +) -> YulVariableDeclarationStatement { + Rc::new(YulVariableDeclarationStatementStruct { + ir_node: Rc::clone(ir_node), + semantic: Rc::clone(semantic), + }) +} + +impl YulVariableDeclarationStatementStruct { + pub fn node_id(&self) -> NodeId { + self.ir_node.id() + } + + pub fn variables(&self) -> YulVariableNames { + create_yul_variable_names(&self.ir_node.variables, &self.semantic) + } + + pub fn value(&self) -> Option { + self.ir_node + .value + .as_ref() + .map(|ir_node| create_yul_variable_declaration_value(ir_node, &self.semantic)) + } + + pub fn get_type(&self) -> Option { + Type::try_create_for_node_id(self.ir_node.id(), &self.semantic) + } +} + +pub type YulVariableDeclarationValue = Rc; + +pub struct YulVariableDeclarationValueStruct { + pub(crate) ir_node: ir::YulVariableDeclarationValue, + pub(crate) semantic: Rc, +} + +pub fn create_yul_variable_declaration_value( + ir_node: &ir::YulVariableDeclarationValue, + semantic: &Rc, +) -> YulVariableDeclarationValue { + Rc::new(YulVariableDeclarationValueStruct { + ir_node: Rc::clone(ir_node), + semantic: Rc::clone(semantic), + }) +} + +impl YulVariableDeclarationValueStruct { + pub fn node_id(&self) -> NodeId { + self.ir_node.id() + } + + pub fn expression(&self) -> YulExpression { + create_yul_expression(&self.ir_node.expression, &self.semantic) + } + + pub fn get_type(&self) -> Option { + Type::try_create_for_node_id(self.ir_node.id(), &self.semantic) + } +} + +// +// Choices +// + +pub enum AbicoderVersion { + AbicoderV1Keyword, + AbicoderV2Keyword, +} + +#[allow(clippy::too_many_lines)] +pub(crate) fn create_abicoder_version( + ir_node: &ir::AbicoderVersion, + semantic: &Rc, +) -> AbicoderVersion { + match ir_node { + ir::AbicoderVersion::AbicoderV1Keyword => AbicoderVersion::AbicoderV1Keyword, + ir::AbicoderVersion::AbicoderV2Keyword => AbicoderVersion::AbicoderV2Keyword, + } +} + +pub enum ArgumentsDeclaration { + PositionalArguments(PositionalArguments), + NamedArguments(NamedArguments), +} + +#[allow(clippy::too_many_lines)] +pub(crate) fn create_arguments_declaration( + ir_node: &ir::ArgumentsDeclaration, + semantic: &Rc, +) -> ArgumentsDeclaration { + match ir_node { + ir::ArgumentsDeclaration::PositionalArguments(nodes) => { + ArgumentsDeclaration::PositionalArguments(create_positional_arguments(nodes, semantic)) + } + + ir::ArgumentsDeclaration::NamedArguments(nodes) => { + ArgumentsDeclaration::NamedArguments(create_named_arguments(nodes, semantic)) + } + } +} + +pub enum ContractMember { + UsingDirective(UsingDirective), + FunctionDefinition(FunctionDefinition), + StructDefinition(StructDefinition), + EnumDefinition(EnumDefinition), + EventDefinition(EventDefinition), + ErrorDefinition(ErrorDefinition), + UserDefinedValueTypeDefinition(UserDefinedValueTypeDefinition), + StateVariableDefinition(StateVariableDefinition), + ConstantDefinition(ConstantDefinition), +} + +#[allow(clippy::too_many_lines)] +pub(crate) fn create_contract_member( + ir_node: &ir::ContractMember, + semantic: &Rc, +) -> ContractMember { + match ir_node { + ir::ContractMember::UsingDirective(variant) => { + ContractMember::UsingDirective(create_using_directive(variant, semantic)) + } + ir::ContractMember::FunctionDefinition(variant) => { + ContractMember::FunctionDefinition(create_function_definition(variant, semantic)) + } + ir::ContractMember::StructDefinition(variant) => { + ContractMember::StructDefinition(create_struct_definition(variant, semantic)) + } + ir::ContractMember::EnumDefinition(variant) => { + ContractMember::EnumDefinition(create_enum_definition(variant, semantic)) + } + ir::ContractMember::EventDefinition(variant) => { + ContractMember::EventDefinition(create_event_definition(variant, semantic)) + } + ir::ContractMember::ErrorDefinition(variant) => { + ContractMember::ErrorDefinition(create_error_definition(variant, semantic)) + } + ir::ContractMember::UserDefinedValueTypeDefinition(variant) => { + ContractMember::UserDefinedValueTypeDefinition( + create_user_defined_value_type_definition(variant, semantic), + ) + } + ir::ContractMember::StateVariableDefinition(variant) => { + ContractMember::StateVariableDefinition(create_state_variable_definition( + variant, semantic, + )) + } + ir::ContractMember::ConstantDefinition(variant) => { + ContractMember::ConstantDefinition(create_constant_definition(variant, semantic)) + } + } +} + +pub enum ElementaryType { + BoolKeyword, + StringKeyword, + AddressType(AddressType), + BytesKeyword(ir::BytesKeyword), + IntKeyword(ir::IntKeyword), + UintKeyword(ir::UintKeyword), + FixedKeyword(ir::FixedKeyword), + UfixedKeyword(ir::UfixedKeyword), +} + +#[allow(clippy::too_many_lines)] +pub(crate) fn create_elementary_type( + ir_node: &ir::ElementaryType, + semantic: &Rc, +) -> ElementaryType { + match ir_node { + ir::ElementaryType::BoolKeyword => ElementaryType::BoolKeyword, + ir::ElementaryType::StringKeyword => ElementaryType::StringKeyword, + ir::ElementaryType::AddressType(variant) => { + ElementaryType::AddressType(create_address_type(variant, semantic)) + } + ir::ElementaryType::BytesKeyword(variant) => { + ElementaryType::BytesKeyword(Rc::clone(variant)) + } + ir::ElementaryType::IntKeyword(variant) => ElementaryType::IntKeyword(Rc::clone(variant)), + ir::ElementaryType::UintKeyword(variant) => ElementaryType::UintKeyword(Rc::clone(variant)), + ir::ElementaryType::FixedKeyword(variant) => { + ElementaryType::FixedKeyword(Rc::clone(variant)) + } + ir::ElementaryType::UfixedKeyword(variant) => { + ElementaryType::UfixedKeyword(Rc::clone(variant)) + } + } +} + +pub enum ExperimentalFeature { + ABIEncoderV2Keyword, + SMTCheckerKeyword, + StringLiteral(ir::StringLiteral), +} + +#[allow(clippy::too_many_lines)] +pub(crate) fn create_experimental_feature( + ir_node: &ir::ExperimentalFeature, + semantic: &Rc, +) -> ExperimentalFeature { + match ir_node { + ir::ExperimentalFeature::ABIEncoderV2Keyword => ExperimentalFeature::ABIEncoderV2Keyword, + ir::ExperimentalFeature::SMTCheckerKeyword => ExperimentalFeature::SMTCheckerKeyword, + ir::ExperimentalFeature::StringLiteral(variant) => { + ExperimentalFeature::StringLiteral(Rc::clone(variant)) + } + } +} + +pub enum Expression { + AssignmentExpression(AssignmentExpression), + ConditionalExpression(ConditionalExpression), + OrExpression(OrExpression), + AndExpression(AndExpression), + EqualityExpression(EqualityExpression), + InequalityExpression(InequalityExpression), + BitwiseOrExpression(BitwiseOrExpression), + BitwiseXorExpression(BitwiseXorExpression), + BitwiseAndExpression(BitwiseAndExpression), + ShiftExpression(ShiftExpression), + AdditiveExpression(AdditiveExpression), + MultiplicativeExpression(MultiplicativeExpression), + ExponentiationExpression(ExponentiationExpression), + PostfixExpression(PostfixExpression), + PrefixExpression(PrefixExpression), + FunctionCallExpression(FunctionCallExpression), + CallOptionsExpression(CallOptionsExpression), + MemberAccessExpression(MemberAccessExpression), + IndexAccessExpression(IndexAccessExpression), + NewExpression(NewExpression), + TupleExpression(TupleExpression), + TypeExpression(TypeExpression), + ArrayExpression(ArrayExpression), + HexNumberExpression(HexNumberExpression), + DecimalNumberExpression(DecimalNumberExpression), + StringExpression(StringExpression), + ElementaryType(ElementaryType), + PayableKeyword, + ThisKeyword, + SuperKeyword, + TrueKeyword, + FalseKeyword, + Identifier(Identifier), +} + +#[allow(clippy::too_many_lines)] +pub(crate) fn create_expression( + ir_node: &ir::Expression, + semantic: &Rc, +) -> Expression { + match ir_node { + ir::Expression::AssignmentExpression(variant) => { + Expression::AssignmentExpression(create_assignment_expression(variant, semantic)) + } + ir::Expression::ConditionalExpression(variant) => { + Expression::ConditionalExpression(create_conditional_expression(variant, semantic)) + } + ir::Expression::OrExpression(variant) => { + Expression::OrExpression(create_or_expression(variant, semantic)) + } + ir::Expression::AndExpression(variant) => { + Expression::AndExpression(create_and_expression(variant, semantic)) + } + ir::Expression::EqualityExpression(variant) => { + Expression::EqualityExpression(create_equality_expression(variant, semantic)) + } + ir::Expression::InequalityExpression(variant) => { + Expression::InequalityExpression(create_inequality_expression(variant, semantic)) + } + ir::Expression::BitwiseOrExpression(variant) => { + Expression::BitwiseOrExpression(create_bitwise_or_expression(variant, semantic)) + } + ir::Expression::BitwiseXorExpression(variant) => { + Expression::BitwiseXorExpression(create_bitwise_xor_expression(variant, semantic)) + } + ir::Expression::BitwiseAndExpression(variant) => { + Expression::BitwiseAndExpression(create_bitwise_and_expression(variant, semantic)) + } + ir::Expression::ShiftExpression(variant) => { + Expression::ShiftExpression(create_shift_expression(variant, semantic)) + } + ir::Expression::AdditiveExpression(variant) => { + Expression::AdditiveExpression(create_additive_expression(variant, semantic)) + } + ir::Expression::MultiplicativeExpression(variant) => Expression::MultiplicativeExpression( + create_multiplicative_expression(variant, semantic), + ), + ir::Expression::ExponentiationExpression(variant) => Expression::ExponentiationExpression( + create_exponentiation_expression(variant, semantic), + ), + ir::Expression::PostfixExpression(variant) => { + Expression::PostfixExpression(create_postfix_expression(variant, semantic)) + } + ir::Expression::PrefixExpression(variant) => { + Expression::PrefixExpression(create_prefix_expression(variant, semantic)) + } + ir::Expression::FunctionCallExpression(variant) => { + Expression::FunctionCallExpression(create_function_call_expression(variant, semantic)) + } + ir::Expression::CallOptionsExpression(variant) => { + Expression::CallOptionsExpression(create_call_options_expression(variant, semantic)) + } + ir::Expression::MemberAccessExpression(variant) => { + Expression::MemberAccessExpression(create_member_access_expression(variant, semantic)) + } + ir::Expression::IndexAccessExpression(variant) => { + Expression::IndexAccessExpression(create_index_access_expression(variant, semantic)) + } + ir::Expression::NewExpression(variant) => { + Expression::NewExpression(create_new_expression(variant, semantic)) + } + ir::Expression::TupleExpression(variant) => { + Expression::TupleExpression(create_tuple_expression(variant, semantic)) + } + ir::Expression::TypeExpression(variant) => { + Expression::TypeExpression(create_type_expression(variant, semantic)) + } + ir::Expression::ArrayExpression(variant) => { + Expression::ArrayExpression(create_array_expression(variant, semantic)) + } + ir::Expression::HexNumberExpression(variant) => { + Expression::HexNumberExpression(create_hex_number_expression(variant, semantic)) + } + ir::Expression::DecimalNumberExpression(variant) => { + Expression::DecimalNumberExpression(create_decimal_number_expression(variant, semantic)) + } + ir::Expression::StringExpression(variant) => { + Expression::StringExpression(create_string_expression(variant, semantic)) + } + ir::Expression::ElementaryType(variant) => { + Expression::ElementaryType(create_elementary_type(variant, semantic)) + } + ir::Expression::PayableKeyword => Expression::PayableKeyword, + ir::Expression::ThisKeyword => Expression::ThisKeyword, + ir::Expression::SuperKeyword => Expression::SuperKeyword, + ir::Expression::TrueKeyword => Expression::TrueKeyword, + ir::Expression::FalseKeyword => Expression::FalseKeyword, + ir::Expression::Identifier(variant) => { + Expression::Identifier(create_identifier(variant, semantic)) + } + } +} + +pub enum Expression_AdditiveExpression_Operator { + Minus, + Plus, +} + +#[allow(clippy::too_many_lines)] +pub(crate) fn create_expression_additive_expression_operator( + ir_node: &ir::Expression_AdditiveExpression_Operator, + semantic: &Rc, +) -> Expression_AdditiveExpression_Operator { + match ir_node { + ir::Expression_AdditiveExpression_Operator::Minus => { + Expression_AdditiveExpression_Operator::Minus + } + ir::Expression_AdditiveExpression_Operator::Plus => { + Expression_AdditiveExpression_Operator::Plus + } + } +} + +pub enum Expression_AssignmentExpression_Operator { + AmpersandEqual, + AsteriskEqual, + BarEqual, + CaretEqual, + Equal, + GreaterThanGreaterThanEqual, + GreaterThanGreaterThanGreaterThanEqual, + LessThanLessThanEqual, + MinusEqual, + PercentEqual, + PlusEqual, + SlashEqual, +} + +#[allow(clippy::too_many_lines)] +pub(crate) fn create_expression_assignment_expression_operator( + ir_node: &ir::Expression_AssignmentExpression_Operator, + semantic: &Rc, +) -> Expression_AssignmentExpression_Operator { + match ir_node { + ir::Expression_AssignmentExpression_Operator::AmpersandEqual => { + Expression_AssignmentExpression_Operator::AmpersandEqual + } + ir::Expression_AssignmentExpression_Operator::AsteriskEqual => { + Expression_AssignmentExpression_Operator::AsteriskEqual + } + ir::Expression_AssignmentExpression_Operator::BarEqual => { + Expression_AssignmentExpression_Operator::BarEqual + } + ir::Expression_AssignmentExpression_Operator::CaretEqual => { + Expression_AssignmentExpression_Operator::CaretEqual + } + ir::Expression_AssignmentExpression_Operator::Equal => { + Expression_AssignmentExpression_Operator::Equal + } + ir::Expression_AssignmentExpression_Operator::GreaterThanGreaterThanEqual => { + Expression_AssignmentExpression_Operator::GreaterThanGreaterThanEqual + } + ir::Expression_AssignmentExpression_Operator::GreaterThanGreaterThanGreaterThanEqual => { + Expression_AssignmentExpression_Operator::GreaterThanGreaterThanGreaterThanEqual + } + ir::Expression_AssignmentExpression_Operator::LessThanLessThanEqual => { + Expression_AssignmentExpression_Operator::LessThanLessThanEqual + } + ir::Expression_AssignmentExpression_Operator::MinusEqual => { + Expression_AssignmentExpression_Operator::MinusEqual + } + ir::Expression_AssignmentExpression_Operator::PercentEqual => { + Expression_AssignmentExpression_Operator::PercentEqual + } + ir::Expression_AssignmentExpression_Operator::PlusEqual => { + Expression_AssignmentExpression_Operator::PlusEqual + } + ir::Expression_AssignmentExpression_Operator::SlashEqual => { + Expression_AssignmentExpression_Operator::SlashEqual + } + } +} + +pub enum Expression_EqualityExpression_Operator { + BangEqual, + EqualEqual, +} + +#[allow(clippy::too_many_lines)] +pub(crate) fn create_expression_equality_expression_operator( + ir_node: &ir::Expression_EqualityExpression_Operator, + semantic: &Rc, +) -> Expression_EqualityExpression_Operator { + match ir_node { + ir::Expression_EqualityExpression_Operator::BangEqual => { + Expression_EqualityExpression_Operator::BangEqual + } + ir::Expression_EqualityExpression_Operator::EqualEqual => { + Expression_EqualityExpression_Operator::EqualEqual + } + } +} + +pub enum Expression_InequalityExpression_Operator { + GreaterThan, + GreaterThanEqual, + LessThan, + LessThanEqual, +} + +#[allow(clippy::too_many_lines)] +pub(crate) fn create_expression_inequality_expression_operator( + ir_node: &ir::Expression_InequalityExpression_Operator, + semantic: &Rc, +) -> Expression_InequalityExpression_Operator { + match ir_node { + ir::Expression_InequalityExpression_Operator::GreaterThan => { + Expression_InequalityExpression_Operator::GreaterThan + } + ir::Expression_InequalityExpression_Operator::GreaterThanEqual => { + Expression_InequalityExpression_Operator::GreaterThanEqual + } + ir::Expression_InequalityExpression_Operator::LessThan => { + Expression_InequalityExpression_Operator::LessThan + } + ir::Expression_InequalityExpression_Operator::LessThanEqual => { + Expression_InequalityExpression_Operator::LessThanEqual + } + } +} + +pub enum Expression_MultiplicativeExpression_Operator { + Asterisk, + Percent, + Slash, +} + +#[allow(clippy::too_many_lines)] +pub(crate) fn create_expression_multiplicative_expression_operator( + ir_node: &ir::Expression_MultiplicativeExpression_Operator, + semantic: &Rc, +) -> Expression_MultiplicativeExpression_Operator { + match ir_node { + ir::Expression_MultiplicativeExpression_Operator::Asterisk => { + Expression_MultiplicativeExpression_Operator::Asterisk + } + ir::Expression_MultiplicativeExpression_Operator::Percent => { + Expression_MultiplicativeExpression_Operator::Percent + } + ir::Expression_MultiplicativeExpression_Operator::Slash => { + Expression_MultiplicativeExpression_Operator::Slash + } + } +} + +pub enum Expression_PostfixExpression_Operator { + MinusMinus, + PlusPlus, +} + +#[allow(clippy::too_many_lines)] +pub(crate) fn create_expression_postfix_expression_operator( + ir_node: &ir::Expression_PostfixExpression_Operator, + semantic: &Rc, +) -> Expression_PostfixExpression_Operator { + match ir_node { + ir::Expression_PostfixExpression_Operator::MinusMinus => { + Expression_PostfixExpression_Operator::MinusMinus + } + ir::Expression_PostfixExpression_Operator::PlusPlus => { + Expression_PostfixExpression_Operator::PlusPlus + } + } +} + +pub enum Expression_PrefixExpression_Operator { + Bang, + DeleteKeyword, + Minus, + MinusMinus, + PlusPlus, + Tilde, +} + +#[allow(clippy::too_many_lines)] +pub(crate) fn create_expression_prefix_expression_operator( + ir_node: &ir::Expression_PrefixExpression_Operator, + semantic: &Rc, +) -> Expression_PrefixExpression_Operator { + match ir_node { + ir::Expression_PrefixExpression_Operator::Bang => { + Expression_PrefixExpression_Operator::Bang + } + ir::Expression_PrefixExpression_Operator::DeleteKeyword => { + Expression_PrefixExpression_Operator::DeleteKeyword + } + ir::Expression_PrefixExpression_Operator::Minus => { + Expression_PrefixExpression_Operator::Minus + } + ir::Expression_PrefixExpression_Operator::MinusMinus => { + Expression_PrefixExpression_Operator::MinusMinus + } + ir::Expression_PrefixExpression_Operator::PlusPlus => { + Expression_PrefixExpression_Operator::PlusPlus + } + ir::Expression_PrefixExpression_Operator::Tilde => { + Expression_PrefixExpression_Operator::Tilde + } + } +} + +pub enum Expression_ShiftExpression_Operator { + GreaterThanGreaterThan, + GreaterThanGreaterThanGreaterThan, + LessThanLessThan, +} + +#[allow(clippy::too_many_lines)] +pub(crate) fn create_expression_shift_expression_operator( + ir_node: &ir::Expression_ShiftExpression_Operator, + semantic: &Rc, +) -> Expression_ShiftExpression_Operator { + match ir_node { + ir::Expression_ShiftExpression_Operator::GreaterThanGreaterThan => { + Expression_ShiftExpression_Operator::GreaterThanGreaterThan + } + ir::Expression_ShiftExpression_Operator::GreaterThanGreaterThanGreaterThan => { + Expression_ShiftExpression_Operator::GreaterThanGreaterThanGreaterThan + } + ir::Expression_ShiftExpression_Operator::LessThanLessThan => { + Expression_ShiftExpression_Operator::LessThanLessThan + } + } +} + +pub enum ForStatementCondition { + ExpressionStatement(ExpressionStatement), + Semicolon, +} + +#[allow(clippy::too_many_lines)] +pub(crate) fn create_for_statement_condition( + ir_node: &ir::ForStatementCondition, + semantic: &Rc, +) -> ForStatementCondition { + match ir_node { + ir::ForStatementCondition::ExpressionStatement(variant) => { + ForStatementCondition::ExpressionStatement(create_expression_statement( + variant, semantic, + )) + } + ir::ForStatementCondition::Semicolon => ForStatementCondition::Semicolon, + } +} + +pub enum ForStatementInitialization { + VariableDeclarationStatement(VariableDeclarationStatement), + ExpressionStatement(ExpressionStatement), + Semicolon, +} + +#[allow(clippy::too_many_lines)] +pub(crate) fn create_for_statement_initialization( + ir_node: &ir::ForStatementInitialization, + semantic: &Rc, +) -> ForStatementInitialization { + match ir_node { + ir::ForStatementInitialization::VariableDeclarationStatement(variant) => { + ForStatementInitialization::VariableDeclarationStatement( + create_variable_declaration_statement(variant, semantic), + ) + } + ir::ForStatementInitialization::ExpressionStatement(variant) => { + ForStatementInitialization::ExpressionStatement(create_expression_statement( + variant, semantic, + )) + } + ir::ForStatementInitialization::Semicolon => ForStatementInitialization::Semicolon, + } +} + +pub enum FunctionKind { + Regular, + Constructor, + Fallback, + Receive, + Modifier, +} + +#[allow(clippy::too_many_lines)] +pub(crate) fn create_function_kind( + ir_node: &ir::FunctionKind, + semantic: &Rc, +) -> FunctionKind { + match ir_node { + ir::FunctionKind::Regular => FunctionKind::Regular, + ir::FunctionKind::Constructor => FunctionKind::Constructor, + ir::FunctionKind::Fallback => FunctionKind::Fallback, + ir::FunctionKind::Receive => FunctionKind::Receive, + ir::FunctionKind::Modifier => FunctionKind::Modifier, + } +} + +pub enum FunctionMutability { + Pure, + View, + NonPayable, + Payable, +} + +#[allow(clippy::too_many_lines)] +pub(crate) fn create_function_mutability( + ir_node: &ir::FunctionMutability, + semantic: &Rc, +) -> FunctionMutability { + match ir_node { + ir::FunctionMutability::Pure => FunctionMutability::Pure, + ir::FunctionMutability::View => FunctionMutability::View, + ir::FunctionMutability::NonPayable => FunctionMutability::NonPayable, + ir::FunctionMutability::Payable => FunctionMutability::Payable, + } +} + +pub enum FunctionVisibility { + Public, + Private, + Internal, + External, +} + +#[allow(clippy::too_many_lines)] +pub(crate) fn create_function_visibility( + ir_node: &ir::FunctionVisibility, + semantic: &Rc, +) -> FunctionVisibility { + match ir_node { + ir::FunctionVisibility::Public => FunctionVisibility::Public, + ir::FunctionVisibility::Private => FunctionVisibility::Private, + ir::FunctionVisibility::Internal => FunctionVisibility::Internal, + ir::FunctionVisibility::External => FunctionVisibility::External, + } +} + +pub enum ImportClause { + PathImport(PathImport), + ImportDeconstruction(ImportDeconstruction), +} + +#[allow(clippy::too_many_lines)] +pub(crate) fn create_import_clause( + ir_node: &ir::ImportClause, + semantic: &Rc, +) -> ImportClause { + match ir_node { + ir::ImportClause::PathImport(variant) => { + ImportClause::PathImport(create_path_import(variant, semantic)) + } + ir::ImportClause::ImportDeconstruction(variant) => { + ImportClause::ImportDeconstruction(create_import_deconstruction(variant, semantic)) + } + } +} + +pub enum NumberUnit { + WeiKeyword, + GweiKeyword, + EtherKeyword, + SecondsKeyword, + MinutesKeyword, + HoursKeyword, + DaysKeyword, + WeeksKeyword, +} + +#[allow(clippy::too_many_lines)] +pub(crate) fn create_number_unit( + ir_node: &ir::NumberUnit, + semantic: &Rc, +) -> NumberUnit { + match ir_node { + ir::NumberUnit::WeiKeyword => NumberUnit::WeiKeyword, + ir::NumberUnit::GweiKeyword => NumberUnit::GweiKeyword, + ir::NumberUnit::EtherKeyword => NumberUnit::EtherKeyword, + ir::NumberUnit::SecondsKeyword => NumberUnit::SecondsKeyword, + ir::NumberUnit::MinutesKeyword => NumberUnit::MinutesKeyword, + ir::NumberUnit::HoursKeyword => NumberUnit::HoursKeyword, + ir::NumberUnit::DaysKeyword => NumberUnit::DaysKeyword, + ir::NumberUnit::WeeksKeyword => NumberUnit::WeeksKeyword, + } +} + +pub enum Pragma { + VersionPragma(VersionPragma), + AbicoderPragma(AbicoderPragma), + ExperimentalPragma(ExperimentalPragma), +} + +#[allow(clippy::too_many_lines)] +pub(crate) fn create_pragma(ir_node: &ir::Pragma, semantic: &Rc) -> Pragma { + match ir_node { + ir::Pragma::VersionPragma(variant) => { + Pragma::VersionPragma(create_version_pragma(variant, semantic)) + } + ir::Pragma::AbicoderPragma(variant) => { + Pragma::AbicoderPragma(create_abicoder_pragma(variant, semantic)) + } + ir::Pragma::ExperimentalPragma(variant) => { + Pragma::ExperimentalPragma(create_experimental_pragma(variant, semantic)) + } + } +} + +pub enum SourceUnitMember { + PragmaDirective(PragmaDirective), + ImportClause(ImportClause), + ContractDefinition(ContractDefinition), + InterfaceDefinition(InterfaceDefinition), + LibraryDefinition(LibraryDefinition), + StructDefinition(StructDefinition), + EnumDefinition(EnumDefinition), + FunctionDefinition(FunctionDefinition), + ErrorDefinition(ErrorDefinition), + UserDefinedValueTypeDefinition(UserDefinedValueTypeDefinition), + UsingDirective(UsingDirective), + EventDefinition(EventDefinition), + ConstantDefinition(ConstantDefinition), +} + +#[allow(clippy::too_many_lines)] +pub(crate) fn create_source_unit_member( + ir_node: &ir::SourceUnitMember, + semantic: &Rc, +) -> SourceUnitMember { + match ir_node { + ir::SourceUnitMember::PragmaDirective(variant) => { + SourceUnitMember::PragmaDirective(create_pragma_directive(variant, semantic)) + } + ir::SourceUnitMember::ImportClause(variant) => { + SourceUnitMember::ImportClause(create_import_clause(variant, semantic)) + } + ir::SourceUnitMember::ContractDefinition(variant) => { + SourceUnitMember::ContractDefinition(create_contract_definition(variant, semantic)) + } + ir::SourceUnitMember::InterfaceDefinition(variant) => { + SourceUnitMember::InterfaceDefinition(create_interface_definition(variant, semantic)) + } + ir::SourceUnitMember::LibraryDefinition(variant) => { + SourceUnitMember::LibraryDefinition(create_library_definition(variant, semantic)) + } + ir::SourceUnitMember::StructDefinition(variant) => { + SourceUnitMember::StructDefinition(create_struct_definition(variant, semantic)) + } + ir::SourceUnitMember::EnumDefinition(variant) => { + SourceUnitMember::EnumDefinition(create_enum_definition(variant, semantic)) + } + ir::SourceUnitMember::FunctionDefinition(variant) => { + SourceUnitMember::FunctionDefinition(create_function_definition(variant, semantic)) + } + ir::SourceUnitMember::ErrorDefinition(variant) => { + SourceUnitMember::ErrorDefinition(create_error_definition(variant, semantic)) + } + ir::SourceUnitMember::UserDefinedValueTypeDefinition(variant) => { + SourceUnitMember::UserDefinedValueTypeDefinition( + create_user_defined_value_type_definition(variant, semantic), + ) + } + ir::SourceUnitMember::UsingDirective(variant) => { + SourceUnitMember::UsingDirective(create_using_directive(variant, semantic)) + } + ir::SourceUnitMember::EventDefinition(variant) => { + SourceUnitMember::EventDefinition(create_event_definition(variant, semantic)) + } + ir::SourceUnitMember::ConstantDefinition(variant) => { + SourceUnitMember::ConstantDefinition(create_constant_definition(variant, semantic)) + } + } +} + +pub enum StateVariableMutability { + Mutable, + Constant, + Immutable, + Transient, +} + +#[allow(clippy::too_many_lines)] +pub(crate) fn create_state_variable_mutability( + ir_node: &ir::StateVariableMutability, + semantic: &Rc, +) -> StateVariableMutability { + match ir_node { + ir::StateVariableMutability::Mutable => StateVariableMutability::Mutable, + ir::StateVariableMutability::Constant => StateVariableMutability::Constant, + ir::StateVariableMutability::Immutable => StateVariableMutability::Immutable, + ir::StateVariableMutability::Transient => StateVariableMutability::Transient, + } +} + +pub enum StateVariableVisibility { + Public, + Private, + Internal, +} + +#[allow(clippy::too_many_lines)] +pub(crate) fn create_state_variable_visibility( + ir_node: &ir::StateVariableVisibility, + semantic: &Rc, +) -> StateVariableVisibility { + match ir_node { + ir::StateVariableVisibility::Public => StateVariableVisibility::Public, + ir::StateVariableVisibility::Private => StateVariableVisibility::Private, + ir::StateVariableVisibility::Internal => StateVariableVisibility::Internal, + } +} + +pub enum Statement { + IfStatement(IfStatement), + ForStatement(ForStatement), + WhileStatement(WhileStatement), + DoWhileStatement(DoWhileStatement), + ContinueStatement(ContinueStatement), + BreakStatement(BreakStatement), + ReturnStatement(ReturnStatement), + EmitStatement(EmitStatement), + TryStatement(TryStatement), + RevertStatement(RevertStatement), + AssemblyStatement(AssemblyStatement), + Block(Block), + UncheckedBlock(UncheckedBlock), + VariableDeclarationStatement(VariableDeclarationStatement), + ExpressionStatement(ExpressionStatement), +} + +#[allow(clippy::too_many_lines)] +pub(crate) fn create_statement( + ir_node: &ir::Statement, + semantic: &Rc, +) -> Statement { + match ir_node { + ir::Statement::IfStatement(variant) => { + Statement::IfStatement(create_if_statement(variant, semantic)) + } + ir::Statement::ForStatement(variant) => { + Statement::ForStatement(create_for_statement(variant, semantic)) + } + ir::Statement::WhileStatement(variant) => { + Statement::WhileStatement(create_while_statement(variant, semantic)) + } + ir::Statement::DoWhileStatement(variant) => { + Statement::DoWhileStatement(create_do_while_statement(variant, semantic)) + } + ir::Statement::ContinueStatement(variant) => { + Statement::ContinueStatement(create_continue_statement(variant, semantic)) + } + ir::Statement::BreakStatement(variant) => { + Statement::BreakStatement(create_break_statement(variant, semantic)) + } + ir::Statement::ReturnStatement(variant) => { + Statement::ReturnStatement(create_return_statement(variant, semantic)) + } + ir::Statement::EmitStatement(variant) => { + Statement::EmitStatement(create_emit_statement(variant, semantic)) + } + ir::Statement::TryStatement(variant) => { + Statement::TryStatement(create_try_statement(variant, semantic)) + } + ir::Statement::RevertStatement(variant) => { + Statement::RevertStatement(create_revert_statement(variant, semantic)) + } + ir::Statement::AssemblyStatement(variant) => { + Statement::AssemblyStatement(create_assembly_statement(variant, semantic)) + } + ir::Statement::Block(variant) => Statement::Block(create_block(variant, semantic)), + ir::Statement::UncheckedBlock(variant) => { + Statement::UncheckedBlock(create_unchecked_block(variant, semantic)) + } + ir::Statement::VariableDeclarationStatement(variant) => { + Statement::VariableDeclarationStatement(create_variable_declaration_statement( + variant, semantic, + )) + } + ir::Statement::ExpressionStatement(variant) => { + Statement::ExpressionStatement(create_expression_statement(variant, semantic)) + } + } +} + +pub enum StorageLocation { + MemoryKeyword, + StorageKeyword, + CallDataKeyword, +} + +#[allow(clippy::too_many_lines)] +pub(crate) fn create_storage_location( + ir_node: &ir::StorageLocation, + semantic: &Rc, +) -> StorageLocation { + match ir_node { + ir::StorageLocation::MemoryKeyword => StorageLocation::MemoryKeyword, + ir::StorageLocation::StorageKeyword => StorageLocation::StorageKeyword, + ir::StorageLocation::CallDataKeyword => StorageLocation::CallDataKeyword, + } +} + +pub enum StringExpression { + StringLiterals(Vec), + HexStringLiterals(Vec), + UnicodeStringLiterals(Vec), +} + +#[allow(clippy::too_many_lines)] +pub(crate) fn create_string_expression( + ir_node: &ir::StringExpression, + semantic: &Rc, +) -> StringExpression { + match ir_node { + ir::StringExpression::StringLiterals(nodes) => { + StringExpression::StringLiterals(nodes.clone()) + } + + ir::StringExpression::HexStringLiterals(nodes) => { + StringExpression::HexStringLiterals(nodes.clone()) + } + + ir::StringExpression::UnicodeStringLiterals(nodes) => { + StringExpression::UnicodeStringLiterals(nodes.clone()) + } + } +} + +pub enum TypeName { + ArrayTypeName(ArrayTypeName), + FunctionType(FunctionType), + MappingType(MappingType), + ElementaryType(ElementaryType), + IdentifierPath(IdentifierPath), +} + +#[allow(clippy::too_many_lines)] +pub(crate) fn create_type_name(ir_node: &ir::TypeName, semantic: &Rc) -> TypeName { + match ir_node { + ir::TypeName::ArrayTypeName(variant) => { + TypeName::ArrayTypeName(create_array_type_name(variant, semantic)) + } + ir::TypeName::FunctionType(variant) => { + TypeName::FunctionType(create_function_type(variant, semantic)) + } + ir::TypeName::MappingType(variant) => { + TypeName::MappingType(create_mapping_type(variant, semantic)) + } + ir::TypeName::ElementaryType(variant) => { + TypeName::ElementaryType(create_elementary_type(variant, semantic)) + } + ir::TypeName::IdentifierPath(nodes) => { + TypeName::IdentifierPath(create_identifier_path(nodes, semantic)) + } + } +} + +pub enum UsingClause { + IdentifierPath(IdentifierPath), + UsingDeconstruction(UsingDeconstruction), +} + +#[allow(clippy::too_many_lines)] +pub(crate) fn create_using_clause( + ir_node: &ir::UsingClause, + semantic: &Rc, +) -> UsingClause { + match ir_node { + ir::UsingClause::IdentifierPath(nodes) => { + UsingClause::IdentifierPath(create_identifier_path(nodes, semantic)) + } + + ir::UsingClause::UsingDeconstruction(variant) => { + UsingClause::UsingDeconstruction(create_using_deconstruction(variant, semantic)) + } + } +} + +pub enum UsingOperator { + Ampersand, + Asterisk, + BangEqual, + Bar, + Caret, + EqualEqual, + GreaterThan, + GreaterThanEqual, + LessThan, + LessThanEqual, + Minus, + Percent, + Plus, + Slash, + Tilde, +} + +#[allow(clippy::too_many_lines)] +pub(crate) fn create_using_operator( + ir_node: &ir::UsingOperator, + semantic: &Rc, +) -> UsingOperator { + match ir_node { + ir::UsingOperator::Ampersand => UsingOperator::Ampersand, + ir::UsingOperator::Asterisk => UsingOperator::Asterisk, + ir::UsingOperator::BangEqual => UsingOperator::BangEqual, + ir::UsingOperator::Bar => UsingOperator::Bar, + ir::UsingOperator::Caret => UsingOperator::Caret, + ir::UsingOperator::EqualEqual => UsingOperator::EqualEqual, + ir::UsingOperator::GreaterThan => UsingOperator::GreaterThan, + ir::UsingOperator::GreaterThanEqual => UsingOperator::GreaterThanEqual, + ir::UsingOperator::LessThan => UsingOperator::LessThan, + ir::UsingOperator::LessThanEqual => UsingOperator::LessThanEqual, + ir::UsingOperator::Minus => UsingOperator::Minus, + ir::UsingOperator::Percent => UsingOperator::Percent, + ir::UsingOperator::Plus => UsingOperator::Plus, + ir::UsingOperator::Slash => UsingOperator::Slash, + ir::UsingOperator::Tilde => UsingOperator::Tilde, + } +} + +pub enum UsingTarget { + TypeName(TypeName), + Asterisk, +} + +#[allow(clippy::too_many_lines)] +pub(crate) fn create_using_target( + ir_node: &ir::UsingTarget, + semantic: &Rc, +) -> UsingTarget { + match ir_node { + ir::UsingTarget::TypeName(variant) => { + UsingTarget::TypeName(create_type_name(variant, semantic)) + } + ir::UsingTarget::Asterisk => UsingTarget::Asterisk, + } +} + +pub enum VariableDeclarationTarget { + SingleTypedDeclaration(SingleTypedDeclaration), + MultiTypedDeclaration(MultiTypedDeclaration), +} + +#[allow(clippy::too_many_lines)] +pub(crate) fn create_variable_declaration_target( + ir_node: &ir::VariableDeclarationTarget, + semantic: &Rc, +) -> VariableDeclarationTarget { + match ir_node { + ir::VariableDeclarationTarget::SingleTypedDeclaration(variant) => { + VariableDeclarationTarget::SingleTypedDeclaration(create_single_typed_declaration( + variant, semantic, + )) + } + ir::VariableDeclarationTarget::MultiTypedDeclaration(variant) => { + VariableDeclarationTarget::MultiTypedDeclaration(create_multi_typed_declaration( + variant, semantic, + )) + } + } +} + +pub enum VersionExpression { + VersionRange(VersionRange), + VersionTerm(VersionTerm), +} + +#[allow(clippy::too_many_lines)] +pub(crate) fn create_version_expression( + ir_node: &ir::VersionExpression, + semantic: &Rc, +) -> VersionExpression { + match ir_node { + ir::VersionExpression::VersionRange(variant) => { + VersionExpression::VersionRange(create_version_range(variant, semantic)) + } + ir::VersionExpression::VersionTerm(variant) => { + VersionExpression::VersionTerm(create_version_term(variant, semantic)) + } + } +} + +pub enum VersionLiteral { + SimpleVersionLiteral(Vec), + StringLiteral(ir::StringLiteral), +} + +#[allow(clippy::too_many_lines)] +pub(crate) fn create_version_literal( + ir_node: &ir::VersionLiteral, + semantic: &Rc, +) -> VersionLiteral { + match ir_node { + ir::VersionLiteral::SimpleVersionLiteral(nodes) => { + VersionLiteral::SimpleVersionLiteral(nodes.clone()) + } + + ir::VersionLiteral::StringLiteral(variant) => { + VersionLiteral::StringLiteral(Rc::clone(variant)) + } + } +} + +pub enum VersionOperator { + PragmaCaret, + PragmaTilde, + PragmaEqual, + PragmaLessThan, + PragmaGreaterThan, + PragmaLessThanEqual, + PragmaGreaterThanEqual, +} + +#[allow(clippy::too_many_lines)] +pub(crate) fn create_version_operator( + ir_node: &ir::VersionOperator, + semantic: &Rc, +) -> VersionOperator { + match ir_node { + ir::VersionOperator::PragmaCaret => VersionOperator::PragmaCaret, + ir::VersionOperator::PragmaTilde => VersionOperator::PragmaTilde, + ir::VersionOperator::PragmaEqual => VersionOperator::PragmaEqual, + ir::VersionOperator::PragmaLessThan => VersionOperator::PragmaLessThan, + ir::VersionOperator::PragmaGreaterThan => VersionOperator::PragmaGreaterThan, + ir::VersionOperator::PragmaLessThanEqual => VersionOperator::PragmaLessThanEqual, + ir::VersionOperator::PragmaGreaterThanEqual => VersionOperator::PragmaGreaterThanEqual, + } +} + +pub enum YulExpression { + YulFunctionCallExpression(YulFunctionCallExpression), + YulLiteral(YulLiteral), + YulPath(YulPath), +} + +#[allow(clippy::too_many_lines)] +pub(crate) fn create_yul_expression( + ir_node: &ir::YulExpression, + semantic: &Rc, +) -> YulExpression { + match ir_node { + ir::YulExpression::YulFunctionCallExpression(variant) => { + YulExpression::YulFunctionCallExpression(create_yul_function_call_expression( + variant, semantic, + )) + } + ir::YulExpression::YulLiteral(variant) => { + YulExpression::YulLiteral(create_yul_literal(variant, semantic)) + } + ir::YulExpression::YulPath(nodes) => { + YulExpression::YulPath(create_yul_path(nodes, semantic)) + } + } +} + +pub enum YulLiteral { + TrueKeyword, + FalseKeyword, + DecimalLiteral(ir::DecimalLiteral), + HexLiteral(ir::HexLiteral), + HexStringLiteral(ir::HexStringLiteral), + StringLiteral(ir::StringLiteral), +} + +#[allow(clippy::too_many_lines)] +pub(crate) fn create_yul_literal( + ir_node: &ir::YulLiteral, + semantic: &Rc, +) -> YulLiteral { + match ir_node { + ir::YulLiteral::TrueKeyword => YulLiteral::TrueKeyword, + ir::YulLiteral::FalseKeyword => YulLiteral::FalseKeyword, + ir::YulLiteral::DecimalLiteral(variant) => YulLiteral::DecimalLiteral(Rc::clone(variant)), + ir::YulLiteral::HexLiteral(variant) => YulLiteral::HexLiteral(Rc::clone(variant)), + ir::YulLiteral::HexStringLiteral(variant) => { + YulLiteral::HexStringLiteral(Rc::clone(variant)) + } + ir::YulLiteral::StringLiteral(variant) => YulLiteral::StringLiteral(Rc::clone(variant)), + } +} + +pub enum YulStatement { + YulBlock(YulBlock), + YulFunctionDefinition(YulFunctionDefinition), + YulIfStatement(YulIfStatement), + YulForStatement(YulForStatement), + YulSwitchStatement(YulSwitchStatement), + YulLeaveStatement(YulLeaveStatement), + YulBreakStatement(YulBreakStatement), + YulContinueStatement(YulContinueStatement), + YulVariableAssignmentStatement(YulVariableAssignmentStatement), + YulVariableDeclarationStatement(YulVariableDeclarationStatement), + YulExpression(YulExpression), +} + +#[allow(clippy::too_many_lines)] +pub(crate) fn create_yul_statement( + ir_node: &ir::YulStatement, + semantic: &Rc, +) -> YulStatement { + match ir_node { + ir::YulStatement::YulBlock(variant) => { + YulStatement::YulBlock(create_yul_block(variant, semantic)) + } + ir::YulStatement::YulFunctionDefinition(variant) => { + YulStatement::YulFunctionDefinition(create_yul_function_definition(variant, semantic)) + } + ir::YulStatement::YulIfStatement(variant) => { + YulStatement::YulIfStatement(create_yul_if_statement(variant, semantic)) + } + ir::YulStatement::YulForStatement(variant) => { + YulStatement::YulForStatement(create_yul_for_statement(variant, semantic)) + } + ir::YulStatement::YulSwitchStatement(variant) => { + YulStatement::YulSwitchStatement(create_yul_switch_statement(variant, semantic)) + } + ir::YulStatement::YulLeaveStatement(variant) => { + YulStatement::YulLeaveStatement(create_yul_leave_statement(variant, semantic)) + } + ir::YulStatement::YulBreakStatement(variant) => { + YulStatement::YulBreakStatement(create_yul_break_statement(variant, semantic)) + } + ir::YulStatement::YulContinueStatement(variant) => { + YulStatement::YulContinueStatement(create_yul_continue_statement(variant, semantic)) + } + ir::YulStatement::YulVariableAssignmentStatement(variant) => { + YulStatement::YulVariableAssignmentStatement(create_yul_variable_assignment_statement( + variant, semantic, + )) + } + ir::YulStatement::YulVariableDeclarationStatement(variant) => { + YulStatement::YulVariableDeclarationStatement( + create_yul_variable_declaration_statement(variant, semantic), + ) + } + ir::YulStatement::YulExpression(variant) => { + YulStatement::YulExpression(create_yul_expression(variant, semantic)) + } + } +} + +pub enum YulSwitchCase { + YulDefaultCase(YulDefaultCase), + YulValueCase(YulValueCase), +} + +#[allow(clippy::too_many_lines)] +pub(crate) fn create_yul_switch_case( + ir_node: &ir::YulSwitchCase, + semantic: &Rc, +) -> YulSwitchCase { + match ir_node { + ir::YulSwitchCase::YulDefaultCase(variant) => { + YulSwitchCase::YulDefaultCase(create_yul_default_case(variant, semantic)) + } + ir::YulSwitchCase::YulValueCase(variant) => { + YulSwitchCase::YulValueCase(create_yul_value_case(variant, semantic)) + } + } +} + +// +// Repeated & Separated +// + +pub type ArrayValues = Rc; + +pub(crate) fn create_array_values( + nodes: &[ir::Expression], + semantic: &Rc, +) -> ArrayValues { + Rc::new(ArrayValuesStruct { + ir_nodes: nodes.to_vec(), + semantic: Rc::clone(semantic), + }) +} + +pub struct ArrayValuesStruct { + pub(crate) ir_nodes: Vec, + pub(crate) semantic: Rc, +} + +impl ArrayValuesStruct { + pub fn iter(&self) -> impl Iterator + use<'_> { + self.ir_nodes + .iter() + .map(|ir_node| create_expression(ir_node, &self.semantic)) + } + pub fn len(&self) -> usize { + self.ir_nodes.len() + } + pub fn is_empty(&self) -> bool { + self.ir_nodes.is_empty() + } +} + +pub type CallOptions = Rc; + +pub(crate) fn create_call_options( + nodes: &[ir::NamedArgument], + semantic: &Rc, +) -> CallOptions { + Rc::new(CallOptionsStruct { + ir_nodes: nodes.to_vec(), + semantic: Rc::clone(semantic), + }) +} + +pub struct CallOptionsStruct { + pub(crate) ir_nodes: Vec, + pub(crate) semantic: Rc, +} + +impl CallOptionsStruct { + pub fn iter(&self) -> impl Iterator + use<'_> { + self.ir_nodes + .iter() + .map(|ir_node| create_named_argument(ir_node, &self.semantic)) + } + pub fn len(&self) -> usize { + self.ir_nodes.len() + } + pub fn is_empty(&self) -> bool { + self.ir_nodes.is_empty() + } +} + +pub type CatchClauses = Rc; + +pub(crate) fn create_catch_clauses( + nodes: &[ir::CatchClause], + semantic: &Rc, +) -> CatchClauses { + Rc::new(CatchClausesStruct { + ir_nodes: nodes.to_vec(), + semantic: Rc::clone(semantic), + }) +} + +pub struct CatchClausesStruct { + pub(crate) ir_nodes: Vec, + pub(crate) semantic: Rc, +} + +impl CatchClausesStruct { + pub fn iter(&self) -> impl Iterator + use<'_> { + self.ir_nodes + .iter() + .map(|ir_node| create_catch_clause(ir_node, &self.semantic)) + } + pub fn len(&self) -> usize { + self.ir_nodes.len() + } + pub fn is_empty(&self) -> bool { + self.ir_nodes.is_empty() + } +} + +pub type ContractMembers = Rc; + +pub(crate) fn create_contract_members( + nodes: &[ir::ContractMember], + semantic: &Rc, +) -> ContractMembers { + Rc::new(ContractMembersStruct { + ir_nodes: nodes.to_vec(), + semantic: Rc::clone(semantic), + }) +} + +pub struct ContractMembersStruct { + pub(crate) ir_nodes: Vec, + pub(crate) semantic: Rc, +} + +impl ContractMembersStruct { + pub fn iter(&self) -> impl Iterator + use<'_> { + self.ir_nodes + .iter() + .map(|ir_node| create_contract_member(ir_node, &self.semantic)) + } + pub fn len(&self) -> usize { + self.ir_nodes.len() + } + pub fn is_empty(&self) -> bool { + self.ir_nodes.is_empty() + } +} + +pub type EnumMembers = Rc; + +pub(crate) fn create_enum_members( + nodes: &[ir::Identifier], + semantic: &Rc, +) -> EnumMembers { + Rc::new(EnumMembersStruct { + ir_nodes: nodes.to_vec(), + semantic: Rc::clone(semantic), + }) +} + +pub struct EnumMembersStruct { + pub(crate) ir_nodes: Vec, + pub(crate) semantic: Rc, +} + +impl EnumMembersStruct { + pub fn iter(&self) -> impl Iterator + use<'_> { + self.ir_nodes + .iter() + .map(|ir_node| create_identifier(ir_node, &self.semantic)) + } + pub fn len(&self) -> usize { + self.ir_nodes.len() + } + pub fn is_empty(&self) -> bool { + self.ir_nodes.is_empty() + } +} + +pub type IdentifierPath = Rc; + +pub(crate) fn create_identifier_path( + nodes: &[ir::Identifier], + semantic: &Rc, +) -> IdentifierPath { + Rc::new(IdentifierPathStruct { + ir_nodes: nodes.to_vec(), + semantic: Rc::clone(semantic), + }) +} + +pub struct IdentifierPathStruct { + pub(crate) ir_nodes: Vec, + pub(crate) semantic: Rc, +} + +impl IdentifierPathStruct { + pub fn iter(&self) -> impl Iterator + use<'_> { + self.ir_nodes + .iter() + .map(|ir_node| create_identifier(ir_node, &self.semantic)) + } + pub fn len(&self) -> usize { + self.ir_nodes.len() + } + pub fn is_empty(&self) -> bool { + self.ir_nodes.is_empty() + } +} + +pub type ImportDeconstructionSymbols = Rc; + +pub(crate) fn create_import_deconstruction_symbols( + nodes: &[ir::ImportDeconstructionSymbol], + semantic: &Rc, +) -> ImportDeconstructionSymbols { + Rc::new(ImportDeconstructionSymbolsStruct { + ir_nodes: nodes.to_vec(), + semantic: Rc::clone(semantic), + }) +} + +pub struct ImportDeconstructionSymbolsStruct { + pub(crate) ir_nodes: Vec, + pub(crate) semantic: Rc, +} + +impl ImportDeconstructionSymbolsStruct { + pub fn iter(&self) -> impl Iterator + use<'_> { + self.ir_nodes + .iter() + .map(|ir_node| create_import_deconstruction_symbol(ir_node, &self.semantic)) + } + pub fn len(&self) -> usize { + self.ir_nodes.len() + } + pub fn is_empty(&self) -> bool { + self.ir_nodes.is_empty() + } +} + +pub type InheritanceTypes = Rc; + +pub(crate) fn create_inheritance_types( + nodes: &[ir::InheritanceType], + semantic: &Rc, +) -> InheritanceTypes { + Rc::new(InheritanceTypesStruct { + ir_nodes: nodes.to_vec(), + semantic: Rc::clone(semantic), + }) +} + +pub struct InheritanceTypesStruct { + pub(crate) ir_nodes: Vec, + pub(crate) semantic: Rc, +} + +impl InheritanceTypesStruct { + pub fn iter(&self) -> impl Iterator + use<'_> { + self.ir_nodes + .iter() + .map(|ir_node| create_inheritance_type(ir_node, &self.semantic)) + } + pub fn len(&self) -> usize { + self.ir_nodes.len() + } + pub fn is_empty(&self) -> bool { + self.ir_nodes.is_empty() + } +} + +pub type InterfaceMembers = Rc; + +pub(crate) fn create_interface_members( + nodes: &[ir::ContractMember], + semantic: &Rc, +) -> InterfaceMembers { + Rc::new(InterfaceMembersStruct { + ir_nodes: nodes.to_vec(), + semantic: Rc::clone(semantic), + }) +} + +pub struct InterfaceMembersStruct { + pub(crate) ir_nodes: Vec, + pub(crate) semantic: Rc, +} + +impl InterfaceMembersStruct { + pub fn iter(&self) -> impl Iterator + use<'_> { + self.ir_nodes + .iter() + .map(|ir_node| create_contract_member(ir_node, &self.semantic)) + } + pub fn len(&self) -> usize { + self.ir_nodes.len() + } + pub fn is_empty(&self) -> bool { + self.ir_nodes.is_empty() + } +} + +pub type LibraryMembers = Rc; + +pub(crate) fn create_library_members( + nodes: &[ir::ContractMember], + semantic: &Rc, +) -> LibraryMembers { + Rc::new(LibraryMembersStruct { + ir_nodes: nodes.to_vec(), + semantic: Rc::clone(semantic), + }) +} + +pub struct LibraryMembersStruct { + pub(crate) ir_nodes: Vec, + pub(crate) semantic: Rc, +} + +impl LibraryMembersStruct { + pub fn iter(&self) -> impl Iterator + use<'_> { + self.ir_nodes + .iter() + .map(|ir_node| create_contract_member(ir_node, &self.semantic)) + } + pub fn len(&self) -> usize { + self.ir_nodes.len() + } + pub fn is_empty(&self) -> bool { + self.ir_nodes.is_empty() + } +} + +pub type ModifierInvocations = Rc; + +pub(crate) fn create_modifier_invocations( + nodes: &[ir::ModifierInvocation], + semantic: &Rc, +) -> ModifierInvocations { + Rc::new(ModifierInvocationsStruct { + ir_nodes: nodes.to_vec(), + semantic: Rc::clone(semantic), + }) +} + +pub struct ModifierInvocationsStruct { + pub(crate) ir_nodes: Vec, + pub(crate) semantic: Rc, +} + +impl ModifierInvocationsStruct { + pub fn iter(&self) -> impl Iterator + use<'_> { + self.ir_nodes + .iter() + .map(|ir_node| create_modifier_invocation(ir_node, &self.semantic)) + } + pub fn len(&self) -> usize { + self.ir_nodes.len() + } + pub fn is_empty(&self) -> bool { + self.ir_nodes.is_empty() + } +} + +pub type MultiTypedDeclarationElements = Rc; + +pub(crate) fn create_multi_typed_declaration_elements( + nodes: &[ir::MultiTypedDeclarationElement], + semantic: &Rc, +) -> MultiTypedDeclarationElements { + Rc::new(MultiTypedDeclarationElementsStruct { + ir_nodes: nodes.to_vec(), + semantic: Rc::clone(semantic), + }) +} + +pub struct MultiTypedDeclarationElementsStruct { + pub(crate) ir_nodes: Vec, + pub(crate) semantic: Rc, +} + +impl MultiTypedDeclarationElementsStruct { + pub fn iter(&self) -> impl Iterator + use<'_> { + self.ir_nodes + .iter() + .map(|ir_node| create_multi_typed_declaration_element(ir_node, &self.semantic)) + } + pub fn len(&self) -> usize { + self.ir_nodes.len() + } + pub fn is_empty(&self) -> bool { + self.ir_nodes.is_empty() + } +} + +pub type NamedArguments = Rc; + +pub(crate) fn create_named_arguments( + nodes: &[ir::NamedArgument], + semantic: &Rc, +) -> NamedArguments { + Rc::new(NamedArgumentsStruct { + ir_nodes: nodes.to_vec(), + semantic: Rc::clone(semantic), + }) +} + +pub struct NamedArgumentsStruct { + pub(crate) ir_nodes: Vec, + pub(crate) semantic: Rc, +} + +impl NamedArgumentsStruct { + pub fn iter(&self) -> impl Iterator + use<'_> { + self.ir_nodes + .iter() + .map(|ir_node| create_named_argument(ir_node, &self.semantic)) + } + pub fn len(&self) -> usize { + self.ir_nodes.len() + } + pub fn is_empty(&self) -> bool { + self.ir_nodes.is_empty() + } +} + +pub type OverridePaths = Rc; + +pub(crate) fn create_override_paths( + nodes: &[ir::IdentifierPath], + semantic: &Rc, +) -> OverridePaths { + Rc::new(OverridePathsStruct { + ir_nodes: nodes.to_vec(), + semantic: Rc::clone(semantic), + }) +} + +pub struct OverridePathsStruct { + pub(crate) ir_nodes: Vec, + pub(crate) semantic: Rc, +} + +impl OverridePathsStruct { + pub fn iter(&self) -> impl Iterator + use<'_> { + self.ir_nodes + .iter() + .map(|ir_node| create_identifier_path(ir_node, &self.semantic)) + } + pub fn len(&self) -> usize { + self.ir_nodes.len() + } + pub fn is_empty(&self) -> bool { + self.ir_nodes.is_empty() + } +} + +pub type Parameters = Rc; + +pub(crate) fn create_parameters( + nodes: &[ir::Parameter], + semantic: &Rc, +) -> Parameters { + Rc::new(ParametersStruct { + ir_nodes: nodes.to_vec(), + semantic: Rc::clone(semantic), + }) +} + +pub struct ParametersStruct { + pub(crate) ir_nodes: Vec, + pub(crate) semantic: Rc, +} + +impl ParametersStruct { + pub fn iter(&self) -> impl Iterator + use<'_> { + self.ir_nodes + .iter() + .map(|ir_node| create_parameter(ir_node, &self.semantic)) + } + pub fn len(&self) -> usize { + self.ir_nodes.len() + } + pub fn is_empty(&self) -> bool { + self.ir_nodes.is_empty() + } +} + +pub type PositionalArguments = Rc; + +pub(crate) fn create_positional_arguments( + nodes: &[ir::Expression], + semantic: &Rc, +) -> PositionalArguments { + Rc::new(PositionalArgumentsStruct { + ir_nodes: nodes.to_vec(), + semantic: Rc::clone(semantic), + }) +} + +pub struct PositionalArgumentsStruct { + pub(crate) ir_nodes: Vec, + pub(crate) semantic: Rc, +} + +impl PositionalArgumentsStruct { + pub fn iter(&self) -> impl Iterator + use<'_> { + self.ir_nodes + .iter() + .map(|ir_node| create_expression(ir_node, &self.semantic)) + } + pub fn len(&self) -> usize { + self.ir_nodes.len() + } + pub fn is_empty(&self) -> bool { + self.ir_nodes.is_empty() + } +} + +pub type SourceUnitMembers = Rc; + +pub(crate) fn create_source_unit_members( + nodes: &[ir::SourceUnitMember], + semantic: &Rc, +) -> SourceUnitMembers { + Rc::new(SourceUnitMembersStruct { + ir_nodes: nodes.to_vec(), + semantic: Rc::clone(semantic), + }) +} + +pub struct SourceUnitMembersStruct { + pub(crate) ir_nodes: Vec, + pub(crate) semantic: Rc, +} + +impl SourceUnitMembersStruct { + pub fn iter(&self) -> impl Iterator + use<'_> { + self.ir_nodes + .iter() + .map(|ir_node| create_source_unit_member(ir_node, &self.semantic)) + } + pub fn len(&self) -> usize { + self.ir_nodes.len() + } + pub fn is_empty(&self) -> bool { + self.ir_nodes.is_empty() + } +} + +pub type Statements = Rc; + +pub(crate) fn create_statements( + nodes: &[ir::Statement], + semantic: &Rc, +) -> Statements { + Rc::new(StatementsStruct { + ir_nodes: nodes.to_vec(), + semantic: Rc::clone(semantic), + }) +} + +pub struct StatementsStruct { + pub(crate) ir_nodes: Vec, + pub(crate) semantic: Rc, +} + +impl StatementsStruct { + pub fn iter(&self) -> impl Iterator + use<'_> { + self.ir_nodes + .iter() + .map(|ir_node| create_statement(ir_node, &self.semantic)) + } + pub fn len(&self) -> usize { + self.ir_nodes.len() + } + pub fn is_empty(&self) -> bool { + self.ir_nodes.is_empty() + } +} + +pub type StructMembers = Rc; + +pub(crate) fn create_struct_members( + nodes: &[ir::StructMember], + semantic: &Rc, +) -> StructMembers { + Rc::new(StructMembersStruct { + ir_nodes: nodes.to_vec(), + semantic: Rc::clone(semantic), + }) +} + +pub struct StructMembersStruct { + pub(crate) ir_nodes: Vec, + pub(crate) semantic: Rc, +} + +impl StructMembersStruct { + pub fn iter(&self) -> impl Iterator + use<'_> { + self.ir_nodes + .iter() + .map(|ir_node| create_struct_member(ir_node, &self.semantic)) + } + pub fn len(&self) -> usize { + self.ir_nodes.len() + } + pub fn is_empty(&self) -> bool { + self.ir_nodes.is_empty() + } +} + +pub type TupleValues = Rc; + +pub(crate) fn create_tuple_values( + nodes: &[ir::TupleValue], + semantic: &Rc, +) -> TupleValues { + Rc::new(TupleValuesStruct { + ir_nodes: nodes.to_vec(), + semantic: Rc::clone(semantic), + }) +} + +pub struct TupleValuesStruct { + pub(crate) ir_nodes: Vec, + pub(crate) semantic: Rc, +} + +impl TupleValuesStruct { + pub fn iter(&self) -> impl Iterator + use<'_> { + self.ir_nodes + .iter() + .map(|ir_node| create_tuple_value(ir_node, &self.semantic)) + } + pub fn len(&self) -> usize { + self.ir_nodes.len() + } + pub fn is_empty(&self) -> bool { + self.ir_nodes.is_empty() + } +} + +pub type UsingDeconstructionSymbols = Rc; + +pub(crate) fn create_using_deconstruction_symbols( + nodes: &[ir::UsingDeconstructionSymbol], + semantic: &Rc, +) -> UsingDeconstructionSymbols { + Rc::new(UsingDeconstructionSymbolsStruct { + ir_nodes: nodes.to_vec(), + semantic: Rc::clone(semantic), + }) +} + +pub struct UsingDeconstructionSymbolsStruct { + pub(crate) ir_nodes: Vec, + pub(crate) semantic: Rc, +} + +impl UsingDeconstructionSymbolsStruct { + pub fn iter(&self) -> impl Iterator + use<'_> { + self.ir_nodes + .iter() + .map(|ir_node| create_using_deconstruction_symbol(ir_node, &self.semantic)) + } + pub fn len(&self) -> usize { + self.ir_nodes.len() + } + pub fn is_empty(&self) -> bool { + self.ir_nodes.is_empty() + } +} + +pub type VersionExpressionSet = Rc; + +pub(crate) fn create_version_expression_set( + nodes: &[ir::VersionExpression], + semantic: &Rc, +) -> VersionExpressionSet { + Rc::new(VersionExpressionSetStruct { + ir_nodes: nodes.to_vec(), + semantic: Rc::clone(semantic), + }) +} + +pub struct VersionExpressionSetStruct { + pub(crate) ir_nodes: Vec, + pub(crate) semantic: Rc, +} + +impl VersionExpressionSetStruct { + pub fn iter(&self) -> impl Iterator + use<'_> { + self.ir_nodes + .iter() + .map(|ir_node| create_version_expression(ir_node, &self.semantic)) + } + pub fn len(&self) -> usize { + self.ir_nodes.len() + } + pub fn is_empty(&self) -> bool { + self.ir_nodes.is_empty() + } +} + +pub type VersionExpressionSets = Rc; + +pub(crate) fn create_version_expression_sets( + nodes: &[ir::VersionExpressionSet], + semantic: &Rc, +) -> VersionExpressionSets { + Rc::new(VersionExpressionSetsStruct { + ir_nodes: nodes.to_vec(), + semantic: Rc::clone(semantic), + }) +} + +pub struct VersionExpressionSetsStruct { + pub(crate) ir_nodes: Vec, + pub(crate) semantic: Rc, +} + +impl VersionExpressionSetsStruct { + pub fn iter(&self) -> impl Iterator + use<'_> { + self.ir_nodes + .iter() + .map(|ir_node| create_version_expression_set(ir_node, &self.semantic)) + } + pub fn len(&self) -> usize { + self.ir_nodes.len() + } + pub fn is_empty(&self) -> bool { + self.ir_nodes.is_empty() + } +} + +pub type YulArguments = Rc; + +pub(crate) fn create_yul_arguments( + nodes: &[ir::YulExpression], + semantic: &Rc, +) -> YulArguments { + Rc::new(YulArgumentsStruct { + ir_nodes: nodes.to_vec(), + semantic: Rc::clone(semantic), + }) +} + +pub struct YulArgumentsStruct { + pub(crate) ir_nodes: Vec, + pub(crate) semantic: Rc, +} + +impl YulArgumentsStruct { + pub fn iter(&self) -> impl Iterator + use<'_> { + self.ir_nodes + .iter() + .map(|ir_node| create_yul_expression(ir_node, &self.semantic)) + } + pub fn len(&self) -> usize { + self.ir_nodes.len() + } + pub fn is_empty(&self) -> bool { + self.ir_nodes.is_empty() + } +} + +pub type YulParameters = Rc; + +pub(crate) fn create_yul_parameters( + nodes: &[ir::Identifier], + semantic: &Rc, +) -> YulParameters { + Rc::new(YulParametersStruct { + ir_nodes: nodes.to_vec(), + semantic: Rc::clone(semantic), + }) +} + +pub struct YulParametersStruct { + pub(crate) ir_nodes: Vec, + pub(crate) semantic: Rc, +} + +impl YulParametersStruct { + pub fn iter(&self) -> impl Iterator + use<'_> { + self.ir_nodes + .iter() + .map(|ir_node| create_identifier(ir_node, &self.semantic)) + } + pub fn len(&self) -> usize { + self.ir_nodes.len() + } + pub fn is_empty(&self) -> bool { + self.ir_nodes.is_empty() + } +} + +pub type YulPath = Rc; + +pub(crate) fn create_yul_path(nodes: &[ir::Identifier], semantic: &Rc) -> YulPath { + Rc::new(YulPathStruct { + ir_nodes: nodes.to_vec(), + semantic: Rc::clone(semantic), + }) +} + +pub struct YulPathStruct { + pub(crate) ir_nodes: Vec, + pub(crate) semantic: Rc, +} + +impl YulPathStruct { + pub fn iter(&self) -> impl Iterator + use<'_> { + self.ir_nodes + .iter() + .map(|ir_node| create_identifier(ir_node, &self.semantic)) + } + pub fn len(&self) -> usize { + self.ir_nodes.len() + } + pub fn is_empty(&self) -> bool { + self.ir_nodes.is_empty() + } +} + +pub type YulPaths = Rc; + +pub(crate) fn create_yul_paths(nodes: &[ir::YulPath], semantic: &Rc) -> YulPaths { + Rc::new(YulPathsStruct { + ir_nodes: nodes.to_vec(), + semantic: Rc::clone(semantic), + }) +} + +pub struct YulPathsStruct { + pub(crate) ir_nodes: Vec, + pub(crate) semantic: Rc, +} + +impl YulPathsStruct { + pub fn iter(&self) -> impl Iterator + use<'_> { + self.ir_nodes + .iter() + .map(|ir_node| create_yul_path(ir_node, &self.semantic)) + } + pub fn len(&self) -> usize { + self.ir_nodes.len() + } + pub fn is_empty(&self) -> bool { + self.ir_nodes.is_empty() + } +} + +pub type YulStatements = Rc; + +pub(crate) fn create_yul_statements( + nodes: &[ir::YulStatement], + semantic: &Rc, +) -> YulStatements { + Rc::new(YulStatementsStruct { + ir_nodes: nodes.to_vec(), + semantic: Rc::clone(semantic), + }) +} + +pub struct YulStatementsStruct { + pub(crate) ir_nodes: Vec, + pub(crate) semantic: Rc, +} + +impl YulStatementsStruct { + pub fn iter(&self) -> impl Iterator + use<'_> { + self.ir_nodes + .iter() + .map(|ir_node| create_yul_statement(ir_node, &self.semantic)) + } + pub fn len(&self) -> usize { + self.ir_nodes.len() + } + pub fn is_empty(&self) -> bool { + self.ir_nodes.is_empty() + } +} + +pub type YulSwitchCases = Rc; + +pub(crate) fn create_yul_switch_cases( + nodes: &[ir::YulSwitchCase], + semantic: &Rc, +) -> YulSwitchCases { + Rc::new(YulSwitchCasesStruct { + ir_nodes: nodes.to_vec(), + semantic: Rc::clone(semantic), + }) +} + +pub struct YulSwitchCasesStruct { + pub(crate) ir_nodes: Vec, + pub(crate) semantic: Rc, +} + +impl YulSwitchCasesStruct { + pub fn iter(&self) -> impl Iterator + use<'_> { + self.ir_nodes + .iter() + .map(|ir_node| create_yul_switch_case(ir_node, &self.semantic)) + } + pub fn len(&self) -> usize { + self.ir_nodes.len() + } + pub fn is_empty(&self) -> bool { + self.ir_nodes.is_empty() + } +} + +pub type YulVariableNames = Rc; + +pub(crate) fn create_yul_variable_names( + nodes: &[ir::Identifier], + semantic: &Rc, +) -> YulVariableNames { + Rc::new(YulVariableNamesStruct { + ir_nodes: nodes.to_vec(), + semantic: Rc::clone(semantic), + }) +} + +pub struct YulVariableNamesStruct { + pub(crate) ir_nodes: Vec, + pub(crate) semantic: Rc, +} + +impl YulVariableNamesStruct { + pub fn iter(&self) -> impl Iterator + use<'_> { + self.ir_nodes + .iter() + .map(|ir_node| create_identifier(ir_node, &self.semantic)) + } + pub fn len(&self) -> usize { + self.ir_nodes.len() + } + pub fn is_empty(&self) -> bool { + self.ir_nodes.is_empty() + } +} + +// +// Identifiers +// + +pub type Identifier = Rc; + +pub struct IdentifierStruct { + pub(crate) ir_node: ir::Identifier, + pub(crate) semantic: Rc, +} + +pub(crate) fn create_identifier( + ir_node: &ir::Identifier, + semantic: &Rc, +) -> Identifier { + Rc::new(IdentifierStruct { + ir_node: Rc::clone(ir_node), + semantic: Rc::clone(semantic), + }) +} + +impl IdentifierStruct { + pub fn id(self: &Rc) -> NodeId { + self.ir_node.id() + } + + pub fn unparse(&self) -> &str { + self.ir_node.unparse(self.semantic.interner()) + } + + pub fn get_type(&self) -> Option { + Type::try_create_for_node_id(self.ir_node.id(), &self.semantic) + } +} diff --git a/crates/solidity-v2/outputs/cargo/ast/src/ast/nodes.rs.jinja2 b/crates/solidity-v2/outputs/cargo/ast/src/ast/nodes.rs.jinja2 new file mode 100644 index 0000000000..add4f96a9e --- /dev/null +++ b/crates/solidity-v2/outputs/cargo/ast/src/ast/nodes.rs.jinja2 @@ -0,0 +1,256 @@ +{%- set target = model.ir_language_model.target -%} +#![allow(unused)] +#![allow(non_camel_case_types)] +use std::rc::Rc; + +use slang_solidity_v2_ir::ir::{self, NodeId}; +use slang_solidity_v2_semantic::context::SemanticContext; +use super::types::Type; + +// +// Sequences +// + +{% for parent_type, sequence in target.sequences %} + pub type {{ parent_type }} = Rc<{{ parent_type }}Struct>; + + pub struct {{ parent_type }}Struct { + pub(crate) ir_node: ir::{{ parent_type }}, + pub(crate) semantic: Rc, + } + + pub fn create_{{ parent_type | snake_case }}( + ir_node: &ir::{{ parent_type }}, + semantic: &Rc, + ) -> {{ parent_type }} { + Rc::new({{ parent_type }}Struct { + ir_node: Rc::clone(ir_node), + semantic: Rc::clone(semantic), + }) + } + + impl {{ parent_type }}Struct { + pub fn node_id(&self) -> NodeId { + self.ir_node.id() + } + {% for field in sequence.fields -%} + {% if field.is_optional %} + {% if field.type.kind == "UniqueTerminal" %} + pub fn {{ field.label }}(&self) -> bool { + self.ir_node.{{ field.label }} + } + {% elif target.sequences is containing(field.type.name) or + target.choices is containing(field.type.name) or + (field.type.is_terminal and target.terminals[field.type.name].is_identifier) %} + pub fn {{ field.label }}(&self) -> Option<{{ field.type.name }}> { + self.ir_node.{{ field.label }}.as_ref().map(|ir_node| { + create_{{ field.type.name | snake_case }}(ir_node, &self.semantic) + }) + } + {% elif field.type.is_terminal %} + {# non-identifier terminals #} + pub fn {{ field.label }}(&self) -> Option { + self.ir_node.{{ field.label }}.as_ref().map(Rc::clone) + } + {% elif target.collections is containing(field.type.name) %} + {% set item_type = target.collections[field.type.name].item_type %} + {% if not item_type.is_terminal or + target.terminals[item_type.name].is_identifier %} + pub fn {{ field.label }}(&self) -> Option<{{ field.type.name }}> { + self.ir_node.{{ field.label }}.as_ref().map(|ir_node| { + create_{{ field.type.name | snake_case }}(ir_node, &self.semantic) + }) + } + {% elif item_type.is_terminal %} + {# non-identifier terminals #} + pub fn {{ field.label }}(&self) -> Option> { + self.ir_node.{{ field.label }}.clone() + } + {% endif -%} + {% endif %} + {% else %} {# not field.is_optional #} + {% if target.sequences is containing(field.type.name) or + target.choices is containing(field.type.name) or + (field.type.is_terminal and target.terminals[field.type.name].is_identifier) %} + pub fn {{ field.label }}(&self) -> {{ field.type.name }} { + create_{{ field.type.name | snake_case }}(&self.ir_node.{{ field.label }}, &self.semantic) + } + {% elif field.type.is_terminal %} + {# non-identifier terminals #} + pub fn {{ field.label }}(&self) -> ir::{{ field.type.name }} { + Rc::clone(&self.ir_node.{{ field.label }}) + } + {% elif target.collections is containing(field.type.name) %} + {% set item_type = target.collections[field.type.name].item_type %} + {% if not item_type.is_terminal or + target.terminals[item_type.name].is_identifier %} + pub fn {{ field.label }}(&self) -> {{ field.type.name }} { + create_{{ field.type.name | snake_case }}( + &self.ir_node.{{ field.label }}, &self.semantic + ) + } + {% else %} + {# non-identifier terminals #} + pub fn {{ field.label }}(&self) -> Vec { + self.ir_node.{{ field.label }}.clone() + } + {% endif %} + {% endif %} + {% endif %} + {% endfor %} + + pub fn get_type(&self) -> Option { + Type::try_create_for_node_id(self.ir_node.id(), &self.semantic) + } + } + +{% endfor %} + +// +// Choices +// + +{% for parent_type, choice in target.choices %} + pub enum {{ parent_type }} { + {% for variant in choice.variants -%} + {{ variant.name }} + {%- if target.sequences is containing(variant.name) or + target.choices is containing(variant.name) or + (variant.kind == "Terminal" and target.terminals[variant.name].is_identifier) -%} + ({{ variant.name }}) + {%- elif target.collections is containing(variant.name) -%} + {% set item_type = target.collections[variant.name].item_type %} + {% if not item_type.is_terminal or + target.terminals[item_type.name].is_identifier %} + {# collection of non-terminals or identifier terminals #} + ({{ variant.name }}) + {% elif item_type.kind == "Terminal" %} + {# collection of non-identifier terminals #} + (Vec) + {% else %} + {{ throw(message="Cannot generate choice of collection of unique terminals") }} + {% endif %} + {% elif variant.kind == "Terminal" %} + {# non-identifier terminals #} + (ir::{{ variant.name }}) + {%- endif -%} + , + {%- endfor -%} + } + + #[allow(clippy::too_many_lines)] + pub(crate) fn create_{{ parent_type | snake_case }}( + ir_node: &ir::{{ parent_type }}, + semantic: &Rc, + ) -> {{ parent_type }}{ + match ir_node { + {% for variant in choice.variants -%} + ir::{{ parent_type }}::{{ variant.name }} + {%- if target.sequences is containing(variant.name) or + target.choices is containing(variant.name) or + (variant.kind == "Terminal" and target.terminals[variant.name].is_identifier) -%} + (variant) => {{ parent_type }}::{{ variant.name }}( + create_{{ variant.name | snake_case }}(variant, semantic) + ), + {%- elif target.collections is containing(variant.name) -%} + {% set item_type = target.collections[variant.name].item_type %} + {% if not item_type.is_terminal or target.terminals[item_type.name].is_identifier %} + {# collection of non-terminals or identifier terminals #} + (nodes) => {{ parent_type }}::{{ variant.name }}( + create_{{ variant.name | snake_case }}(nodes, semantic) + ), + {% elif item_type.kind == "Terminal" %} + {# collection of non-identifier non-unique terminals #} + (nodes) => {{ parent_type }}::{{ variant.name }}(nodes.clone()), + {% endif %} + {% elif variant.kind == "Terminal" %} + {# non-identifier non-unique terminals #} + (variant) => {{ parent_type }}::{{ variant.name }}(Rc::clone(variant)), + {%- else -%} + => {{ parent_type }}::{{ variant.name }}, + {%- endif -%} + {%- endfor %} + } + } + +{% endfor %} + +// +// Repeated & Separated +// + +{% for parent_type, collection in target.collections -%} + {%- if not collection.item_type.is_terminal or + target.terminals[collection.item_type.name].is_identifier %} + pub type {{ parent_type }} = Rc<{{ parent_type }}Struct>; + + pub(crate) fn create_{{ parent_type | snake_case }}( + nodes: &[ir::{{ collection.item_type.name }}], + semantic: &Rc, + ) -> {{ parent_type }} { + Rc::new({{ parent_type }}Struct { + ir_nodes: nodes.to_vec(), + semantic: Rc::clone(semantic), + }) + } + + pub struct {{ parent_type }}Struct { + pub(crate) ir_nodes: Vec, + pub(crate) semantic: Rc, + } + + impl {{ parent_type }}Struct { + pub fn iter(&self) -> impl Iterator + use<'_> { + self.ir_nodes + .iter() + .map(|ir_node| create_{{ collection.item_type.name | snake_case }}(ir_node, &self.semantic)) + } + pub fn len(&self) -> usize { + self.ir_nodes.len() + } + pub fn is_empty(&self) -> bool { + self.ir_nodes.is_empty() + } + } + {% endif -%} + +{% endfor %} + +// +// Identifiers +// + +{% for terminal_type, terminal in target.terminals %} + {% if terminal.is_identifier %} + pub type {{ terminal_type }} = Rc<{{ terminal_type }}Struct>; + + pub struct {{ terminal_type }}Struct { + pub(crate) ir_node: ir::{{ terminal_type }}, + pub(crate) semantic: Rc, + } + + pub(crate) fn create_{{ terminal_type | snake_case }}( + ir_node: &ir::{{ terminal_type }}, + semantic: &Rc, + ) -> {{ terminal_type }} { + Rc::new({{ terminal_type }}Struct { + ir_node: Rc::clone(ir_node), + semantic: Rc::clone(semantic), + }) + } + + impl {{ terminal_type }}Struct { + pub fn id(self: &Rc) -> NodeId { + self.ir_node.id() + } + + pub fn unparse(&self) -> &str { + self.ir_node.unparse(self.semantic.interner()) + } + + pub fn get_type(&self) -> Option { + Type::try_create_for_node_id(self.ir_node.id(), &self.semantic) + } + } + {% endif %} +{% endfor %} diff --git a/crates/solidity-v2/outputs/cargo/ast/src/ast/references.rs b/crates/solidity-v2/outputs/cargo/ast/src/ast/references.rs new file mode 100644 index 0000000000..3031dba25e --- /dev/null +++ b/crates/solidity-v2/outputs/cargo/ast/src/ast/references.rs @@ -0,0 +1,57 @@ +use std::rc::Rc; + +use slang_solidity_v2_ir::ir::{self, NodeId}; +use slang_solidity_v2_semantic::built_ins::BuiltIn; +use slang_solidity_v2_semantic::context::SemanticContext; + +use super::{create_identifier, Definition, Identifier}; + +pub struct Reference { + identifier: Identifier, +} + +impl Reference { + pub fn try_create(ir_node: &ir::Identifier, semantic: &Rc) -> Option { + // ensure the terminal node is actually functioning as a reference + semantic + .binder() + .find_reference_by_identifier_node_id(ir_node.id())?; + + Some(Self { + identifier: create_identifier(ir_node, semantic), + }) + } + + pub fn name(&self) -> String { + self.identifier.name() + } + + pub fn resolve_to_definition(&self) -> Option { + self.identifier.resolve_to_definition() + } + + pub fn resolve_to_immediate_definition(&self) -> Option { + self.identifier.resolve_to_immediate_definition() + } + + pub fn resolve_to_built_in(&self) -> Option { + self.identifier.resolve_to_built_in() + } +} + +pub(crate) fn references_binding_to_definition( + node_id: NodeId, + semantic: &Rc, +) -> Vec { + semantic + .binder() + .get_references_by_definition_id(node_id) + .iter() + .filter_map(|node_id| { + semantic + .binder() + .find_reference_by_identifier_node_id(*node_id) + .and_then(|reference| Reference::try_create(&reference.identifier, semantic)) + }) + .collect() +} diff --git a/crates/solidity-v2/outputs/cargo/ast/src/ast/types.rs b/crates/solidity-v2/outputs/cargo/ast/src/ast/types.rs new file mode 100644 index 0000000000..20f501bed0 --- /dev/null +++ b/crates/solidity-v2/outputs/cargo/ast/src/ast/types.rs @@ -0,0 +1,381 @@ +use std::rc::Rc; + +use paste::paste; +use slang_solidity_v2_ir::ir::NodeId; +use slang_solidity_v2_semantic::context::SemanticContext; +use slang_solidity_v2_semantic::types::{self, DataLocation, FunctionTypeKind, TypeId}; + +use super::Definition; + +// __SLANG_TYPE_TYPES__ keep in sync with binder types +#[derive(Clone)] +pub enum Type { + Address(AddressType), + Array(ArrayType), + Boolean(BooleanType), + ByteArray(ByteArrayType), + Bytes(BytesType), + Contract(ContractType), + Enum(EnumType), + FixedSizeArray(FixedSizeArrayType), + FixedPointNumber(FixedPointNumberType), + Function(FunctionType), + Integer(IntegerType), + Interface(InterfaceType), + Literal(LiteralType), + Mapping(MappingType), + String(StringType), + Struct(StructType), + Tuple(TupleType), + UserDefinedValue(UserDefinedValueType), + Void(VoidType), +} + +macro_rules! define_type_variant { + ($type:ident) => { + paste! { + #[derive(Clone)] + pub struct [<$type Type>] { + type_id: TypeId, + semantic: Rc, + } + + impl [<$type Type>] { + #[allow(unused)] + fn internal_type(&self) -> &types::Type { + self.semantic.types().get_type_by_id(self.type_id) + } + } + } + }; +} + +define_type_variant!(Address); +define_type_variant!(Array); +define_type_variant!(Boolean); +define_type_variant!(ByteArray); +define_type_variant!(Bytes); +define_type_variant!(Contract); +define_type_variant!(Enum); +define_type_variant!(FixedSizeArray); +define_type_variant!(FixedPointNumber); +define_type_variant!(Function); +define_type_variant!(Integer); +define_type_variant!(Interface); +define_type_variant!(Literal); +define_type_variant!(Mapping); +define_type_variant!(String); +define_type_variant!(Struct); +define_type_variant!(Tuple); +define_type_variant!(UserDefinedValue); +define_type_variant!(Void); + +impl Type { + pub fn try_create_for_node_id(node_id: NodeId, semantic: &Rc) -> Option { + let type_id = semantic.binder().node_typing(node_id).as_type_id()?; + Some(Self::create(type_id, semantic)) + } + + pub fn create(type_id: TypeId, semantic: &Rc) -> Self { + let type_ = semantic.types().get_type_by_id(type_id); + let semantic = Rc::clone(semantic); + match type_ { + types::Type::Address { .. } => Self::Address(AddressType { type_id, semantic }), + types::Type::Array { .. } => Self::Array(ArrayType { type_id, semantic }), + types::Type::Boolean => Self::Boolean(BooleanType { type_id, semantic }), + types::Type::ByteArray { .. } => Self::ByteArray(ByteArrayType { type_id, semantic }), + types::Type::Bytes { .. } => Self::Bytes(BytesType { type_id, semantic }), + types::Type::Contract { .. } => Self::Contract(ContractType { type_id, semantic }), + types::Type::Enum { .. } => Self::Enum(EnumType { type_id, semantic }), + types::Type::FixedSizeArray { .. } => { + Self::FixedSizeArray(FixedSizeArrayType { type_id, semantic }) + } + types::Type::FixedPointNumber { .. } => { + Self::FixedPointNumber(FixedPointNumberType { type_id, semantic }) + } + types::Type::Function(_) => Self::Function(FunctionType { type_id, semantic }), + types::Type::Integer { .. } => Self::Integer(IntegerType { type_id, semantic }), + types::Type::Interface { .. } => Self::Interface(InterfaceType { type_id, semantic }), + types::Type::Literal(_) => Self::Literal(LiteralType { type_id, semantic }), + types::Type::Mapping { .. } => Self::Mapping(MappingType { type_id, semantic }), + types::Type::String { .. } => Self::String(StringType { type_id, semantic }), + types::Type::Struct { .. } => Self::Struct(StructType { type_id, semantic }), + types::Type::Tuple { .. } => Self::Tuple(TupleType { type_id, semantic }), + types::Type::UserDefinedValue { .. } => { + Self::UserDefinedValue(UserDefinedValueType { type_id, semantic }) + } + types::Type::Void => Self::Void(VoidType { type_id, semantic }), + } + } + + pub fn type_id(&self) -> TypeId { + match self { + Type::Address(details) => details.type_id, + Type::Array(details) => details.type_id, + Type::Boolean(details) => details.type_id, + Type::ByteArray(details) => details.type_id, + Type::Bytes(details) => details.type_id, + Type::Contract(details) => details.type_id, + Type::Enum(details) => details.type_id, + Type::FixedSizeArray(details) => details.type_id, + Type::FixedPointNumber(details) => details.type_id, + Type::Function(details) => details.type_id, + Type::Integer(details) => details.type_id, + Type::Interface(details) => details.type_id, + Type::Literal(details) => details.type_id, + Type::Mapping(details) => details.type_id, + Type::String(details) => details.type_id, + Type::Struct(details) => details.type_id, + Type::Tuple(details) => details.type_id, + Type::UserDefinedValue(details) => details.type_id, + Type::Void(details) => details.type_id, + } + } +} + +impl AddressType { + pub fn payable(&self) -> bool { + let types::Type::Address { payable } = self.internal_type() else { + unreachable!("invalid address type"); + }; + *payable + } +} + +impl ArrayType { + pub fn element_type(&self) -> Type { + let types::Type::Array { element_type, .. } = self.internal_type() else { + unreachable!("invalid array type"); + }; + Type::create(*element_type, &self.semantic) + } + pub fn location(&self) -> DataLocation { + let types::Type::Array { location, .. } = self.internal_type() else { + unreachable!("invalid array type"); + }; + *location + } +} + +impl BooleanType {} + +impl ByteArrayType { + pub fn width(&self) -> u32 { + let types::Type::ByteArray { width } = self.internal_type() else { + unreachable!("invalid byte array type"); + }; + *width + } +} + +impl BytesType { + pub fn location(&self) -> DataLocation { + let types::Type::Bytes { location } = self.internal_type() else { + unreachable!("invalid bytes type"); + }; + *location + } +} + +impl ContractType { + pub fn definition(&self) -> Definition { + let types::Type::Contract { definition_id } = self.internal_type() else { + unreachable!("invalid contract type"); + }; + Definition::try_create(*definition_id, &self.semantic).expect("invalid contract definition") + } +} + +impl EnumType { + pub fn definition(&self) -> Definition { + let types::Type::Enum { definition_id } = self.internal_type() else { + unreachable!("invalid enum type"); + }; + Definition::try_create(*definition_id, &self.semantic).expect("invalid enum definition") + } +} + +impl FixedSizeArrayType { + pub fn element_type(&self) -> Type { + let types::Type::FixedSizeArray { element_type, .. } = self.internal_type() else { + unreachable!("invalid fixed-size array type"); + }; + Type::create(*element_type, &self.semantic) + } + pub fn location(&self) -> DataLocation { + let types::Type::FixedSizeArray { location, .. } = self.internal_type() else { + unreachable!("invalid fixed-size array type"); + }; + *location + } + pub fn size(&self) -> usize { + let types::Type::FixedSizeArray { size, .. } = self.internal_type() else { + unreachable!("invalid fixed-size array type"); + }; + *size + } +} + +impl FixedPointNumberType { + pub fn signed(&self) -> bool { + let types::Type::FixedPointNumber { signed, .. } = self.internal_type() else { + unreachable!("invalid fixed point number type"); + }; + *signed + } + pub fn bits(&self) -> u32 { + let types::Type::FixedPointNumber { bits, .. } = self.internal_type() else { + unreachable!("invalid fixed point number type"); + }; + *bits + } + pub fn precision_bits(&self) -> u32 { + let types::Type::FixedPointNumber { precision_bits, .. } = self.internal_type() else { + unreachable!("invalid fixed point number type"); + }; + *precision_bits + } +} + +impl FunctionType { + pub fn associated_definition(&self) -> Option { + let types::Type::Function(function_type) = self.internal_type() else { + unreachable!("invalid function type"); + }; + function_type.definition_id.map(|definition_id| { + Definition::try_create(definition_id, &self.semantic) + .expect("invalid function definition") + }) + } + + pub fn implicit_receiver_type(&self) -> Option { + let types::Type::Function(function_type) = self.internal_type() else { + unreachable!("invalid function type"); + }; + function_type + .implicit_receiver_type + .map(|type_id| Type::create(type_id, &self.semantic)) + } + + pub fn parameter_types(&self) -> Vec { + let types::Type::Function(function_type) = self.internal_type() else { + unreachable!("invalid function type"); + }; + function_type + .parameter_types + .iter() + .map(|type_id| Type::create(*type_id, &self.semantic)) + .collect() + } + + pub fn return_type(&self) -> Type { + let types::Type::Function(function_type) = self.internal_type() else { + unreachable!("invalid function type"); + }; + Type::create(function_type.return_type, &self.semantic) + } + + pub fn external(&self) -> bool { + let types::Type::Function(function_type) = self.internal_type() else { + unreachable!("invalid function type"); + }; + function_type.external + } + + pub fn kind(&self) -> FunctionTypeKind { + let types::Type::Function(function_type) = self.internal_type() else { + unreachable!("invalid function type"); + }; + function_type.kind + } +} + +impl IntegerType { + pub fn signed(&self) -> bool { + let types::Type::Integer { signed, .. } = self.internal_type() else { + unreachable!("invalid integer type"); + }; + *signed + } + pub fn bits(&self) -> u32 { + let types::Type::Integer { bits, .. } = self.internal_type() else { + unreachable!("invalid integer type"); + }; + *bits + } +} + +impl InterfaceType { + pub fn definition(&self) -> Definition { + let types::Type::Interface { definition_id } = self.internal_type() else { + unreachable!("invalid interface type"); + }; + Definition::try_create(*definition_id, &self.semantic) + .expect("invalid interface definition") + } +} + +impl LiteralType {} + +impl MappingType { + pub fn key_type(&self) -> Type { + let types::Type::Mapping { key_type_id, .. } = self.internal_type() else { + unreachable!("invalid mapping type"); + }; + Type::create(*key_type_id, &self.semantic) + } + pub fn value_type(&self) -> Type { + let types::Type::Mapping { value_type_id, .. } = self.internal_type() else { + unreachable!("invalid mapping type"); + }; + Type::create(*value_type_id, &self.semantic) + } +} + +impl StringType { + pub fn location(&self) -> DataLocation { + let types::Type::String { location } = self.internal_type() else { + unreachable!("invalid string type"); + }; + *location + } +} + +impl StructType { + pub fn definition(&self) -> Definition { + let types::Type::Struct { definition_id, .. } = self.internal_type() else { + unreachable!("invalid struct type"); + }; + Definition::try_create(*definition_id, &self.semantic).expect("invalid struct definition") + } + pub fn location(&self) -> DataLocation { + let types::Type::Struct { location, .. } = self.internal_type() else { + unreachable!("invalid struct type"); + }; + *location + } +} + +impl TupleType { + pub fn types(&self) -> Vec { + let types::Type::Tuple { types } = self.internal_type() else { + unreachable!("invalid tuple type"); + }; + types + .iter() + .map(|type_id| Type::create(*type_id, &self.semantic)) + .collect() + } +} + +impl UserDefinedValueType { + pub fn definition(&self) -> Definition { + let types::Type::UserDefinedValue { definition_id } = self.internal_type() else { + unreachable!("invalid user defined value type"); + }; + Definition::try_create(*definition_id, &self.semantic) + .expect("invalid user defined value definition") + } +} + +impl VoidType {} diff --git a/crates/solidity-v2/outputs/cargo/ast/src/ast/visitor.generated.rs b/crates/solidity-v2/outputs/cargo/ast/src/ast/visitor.generated.rs new file mode 100644 index 0000000000..97a1010bdd --- /dev/null +++ b/crates/solidity-v2/outputs/cargo/ast/src/ast/visitor.generated.rs @@ -0,0 +1,2921 @@ +// This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +use slang_solidity_v2_ir::ir; + +#[allow(clippy::wildcard_imports)] +use super::nodes::*; + +pub trait Visitor { + fn enter_abicoder_pragma(&mut self, _node: &AbicoderPragma) -> bool { + true + } + fn leave_abicoder_pragma(&mut self, _node: &AbicoderPragma) {} + + fn enter_additive_expression(&mut self, _node: &AdditiveExpression) -> bool { + true + } + fn leave_additive_expression(&mut self, _node: &AdditiveExpression) {} + + fn enter_address_type(&mut self, _node: &AddressType) -> bool { + true + } + fn leave_address_type(&mut self, _node: &AddressType) {} + + fn enter_and_expression(&mut self, _node: &AndExpression) -> bool { + true + } + fn leave_and_expression(&mut self, _node: &AndExpression) {} + + fn enter_array_expression(&mut self, _node: &ArrayExpression) -> bool { + true + } + fn leave_array_expression(&mut self, _node: &ArrayExpression) {} + + fn enter_array_type_name(&mut self, _node: &ArrayTypeName) -> bool { + true + } + fn leave_array_type_name(&mut self, _node: &ArrayTypeName) {} + + fn enter_assembly_statement(&mut self, _node: &AssemblyStatement) -> bool { + true + } + fn leave_assembly_statement(&mut self, _node: &AssemblyStatement) {} + + fn enter_assignment_expression(&mut self, _node: &AssignmentExpression) -> bool { + true + } + fn leave_assignment_expression(&mut self, _node: &AssignmentExpression) {} + + fn enter_bitwise_and_expression(&mut self, _node: &BitwiseAndExpression) -> bool { + true + } + fn leave_bitwise_and_expression(&mut self, _node: &BitwiseAndExpression) {} + + fn enter_bitwise_or_expression(&mut self, _node: &BitwiseOrExpression) -> bool { + true + } + fn leave_bitwise_or_expression(&mut self, _node: &BitwiseOrExpression) {} + + fn enter_bitwise_xor_expression(&mut self, _node: &BitwiseXorExpression) -> bool { + true + } + fn leave_bitwise_xor_expression(&mut self, _node: &BitwiseXorExpression) {} + + fn enter_block(&mut self, _node: &Block) -> bool { + true + } + fn leave_block(&mut self, _node: &Block) {} + + fn enter_break_statement(&mut self, _node: &BreakStatement) -> bool { + true + } + fn leave_break_statement(&mut self, _node: &BreakStatement) {} + + fn enter_call_options_expression(&mut self, _node: &CallOptionsExpression) -> bool { + true + } + fn leave_call_options_expression(&mut self, _node: &CallOptionsExpression) {} + + fn enter_catch_clause(&mut self, _node: &CatchClause) -> bool { + true + } + fn leave_catch_clause(&mut self, _node: &CatchClause) {} + + fn enter_catch_clause_error(&mut self, _node: &CatchClauseError) -> bool { + true + } + fn leave_catch_clause_error(&mut self, _node: &CatchClauseError) {} + + fn enter_conditional_expression(&mut self, _node: &ConditionalExpression) -> bool { + true + } + fn leave_conditional_expression(&mut self, _node: &ConditionalExpression) {} + + fn enter_constant_definition(&mut self, _node: &ConstantDefinition) -> bool { + true + } + fn leave_constant_definition(&mut self, _node: &ConstantDefinition) {} + + fn enter_continue_statement(&mut self, _node: &ContinueStatement) -> bool { + true + } + fn leave_continue_statement(&mut self, _node: &ContinueStatement) {} + + fn enter_contract_definition(&mut self, _node: &ContractDefinition) -> bool { + true + } + fn leave_contract_definition(&mut self, _node: &ContractDefinition) {} + + fn enter_decimal_number_expression(&mut self, _node: &DecimalNumberExpression) -> bool { + true + } + fn leave_decimal_number_expression(&mut self, _node: &DecimalNumberExpression) {} + + fn enter_do_while_statement(&mut self, _node: &DoWhileStatement) -> bool { + true + } + fn leave_do_while_statement(&mut self, _node: &DoWhileStatement) {} + + fn enter_emit_statement(&mut self, _node: &EmitStatement) -> bool { + true + } + fn leave_emit_statement(&mut self, _node: &EmitStatement) {} + + fn enter_enum_definition(&mut self, _node: &EnumDefinition) -> bool { + true + } + fn leave_enum_definition(&mut self, _node: &EnumDefinition) {} + + fn enter_equality_expression(&mut self, _node: &EqualityExpression) -> bool { + true + } + fn leave_equality_expression(&mut self, _node: &EqualityExpression) {} + + fn enter_error_definition(&mut self, _node: &ErrorDefinition) -> bool { + true + } + fn leave_error_definition(&mut self, _node: &ErrorDefinition) {} + + fn enter_event_definition(&mut self, _node: &EventDefinition) -> bool { + true + } + fn leave_event_definition(&mut self, _node: &EventDefinition) {} + + fn enter_experimental_pragma(&mut self, _node: &ExperimentalPragma) -> bool { + true + } + fn leave_experimental_pragma(&mut self, _node: &ExperimentalPragma) {} + + fn enter_exponentiation_expression(&mut self, _node: &ExponentiationExpression) -> bool { + true + } + fn leave_exponentiation_expression(&mut self, _node: &ExponentiationExpression) {} + + fn enter_expression_statement(&mut self, _node: &ExpressionStatement) -> bool { + true + } + fn leave_expression_statement(&mut self, _node: &ExpressionStatement) {} + + fn enter_for_statement(&mut self, _node: &ForStatement) -> bool { + true + } + fn leave_for_statement(&mut self, _node: &ForStatement) {} + + fn enter_function_call_expression(&mut self, _node: &FunctionCallExpression) -> bool { + true + } + fn leave_function_call_expression(&mut self, _node: &FunctionCallExpression) {} + + fn enter_function_definition(&mut self, _node: &FunctionDefinition) -> bool { + true + } + fn leave_function_definition(&mut self, _node: &FunctionDefinition) {} + + fn enter_function_type(&mut self, _node: &FunctionType) -> bool { + true + } + fn leave_function_type(&mut self, _node: &FunctionType) {} + + fn enter_hex_number_expression(&mut self, _node: &HexNumberExpression) -> bool { + true + } + fn leave_hex_number_expression(&mut self, _node: &HexNumberExpression) {} + + fn enter_if_statement(&mut self, _node: &IfStatement) -> bool { + true + } + fn leave_if_statement(&mut self, _node: &IfStatement) {} + + fn enter_import_deconstruction(&mut self, _node: &ImportDeconstruction) -> bool { + true + } + fn leave_import_deconstruction(&mut self, _node: &ImportDeconstruction) {} + + fn enter_import_deconstruction_symbol(&mut self, _node: &ImportDeconstructionSymbol) -> bool { + true + } + fn leave_import_deconstruction_symbol(&mut self, _node: &ImportDeconstructionSymbol) {} + + fn enter_index_access_expression(&mut self, _node: &IndexAccessExpression) -> bool { + true + } + fn leave_index_access_expression(&mut self, _node: &IndexAccessExpression) {} + + fn enter_inequality_expression(&mut self, _node: &InequalityExpression) -> bool { + true + } + fn leave_inequality_expression(&mut self, _node: &InequalityExpression) {} + + fn enter_inheritance_type(&mut self, _node: &InheritanceType) -> bool { + true + } + fn leave_inheritance_type(&mut self, _node: &InheritanceType) {} + + fn enter_interface_definition(&mut self, _node: &InterfaceDefinition) -> bool { + true + } + fn leave_interface_definition(&mut self, _node: &InterfaceDefinition) {} + + fn enter_library_definition(&mut self, _node: &LibraryDefinition) -> bool { + true + } + fn leave_library_definition(&mut self, _node: &LibraryDefinition) {} + + fn enter_mapping_type(&mut self, _node: &MappingType) -> bool { + true + } + fn leave_mapping_type(&mut self, _node: &MappingType) {} + + fn enter_member_access_expression(&mut self, _node: &MemberAccessExpression) -> bool { + true + } + fn leave_member_access_expression(&mut self, _node: &MemberAccessExpression) {} + + fn enter_modifier_invocation(&mut self, _node: &ModifierInvocation) -> bool { + true + } + fn leave_modifier_invocation(&mut self, _node: &ModifierInvocation) {} + + fn enter_multi_typed_declaration(&mut self, _node: &MultiTypedDeclaration) -> bool { + true + } + fn leave_multi_typed_declaration(&mut self, _node: &MultiTypedDeclaration) {} + + fn enter_multi_typed_declaration_element( + &mut self, + _node: &MultiTypedDeclarationElement, + ) -> bool { + true + } + fn leave_multi_typed_declaration_element(&mut self, _node: &MultiTypedDeclarationElement) {} + + fn enter_multiplicative_expression(&mut self, _node: &MultiplicativeExpression) -> bool { + true + } + fn leave_multiplicative_expression(&mut self, _node: &MultiplicativeExpression) {} + + fn enter_named_argument(&mut self, _node: &NamedArgument) -> bool { + true + } + fn leave_named_argument(&mut self, _node: &NamedArgument) {} + + fn enter_new_expression(&mut self, _node: &NewExpression) -> bool { + true + } + fn leave_new_expression(&mut self, _node: &NewExpression) {} + + fn enter_or_expression(&mut self, _node: &OrExpression) -> bool { + true + } + fn leave_or_expression(&mut self, _node: &OrExpression) {} + + fn enter_parameter(&mut self, _node: &Parameter) -> bool { + true + } + fn leave_parameter(&mut self, _node: &Parameter) {} + + fn enter_path_import(&mut self, _node: &PathImport) -> bool { + true + } + fn leave_path_import(&mut self, _node: &PathImport) {} + + fn enter_postfix_expression(&mut self, _node: &PostfixExpression) -> bool { + true + } + fn leave_postfix_expression(&mut self, _node: &PostfixExpression) {} + + fn enter_pragma_directive(&mut self, _node: &PragmaDirective) -> bool { + true + } + fn leave_pragma_directive(&mut self, _node: &PragmaDirective) {} + + fn enter_prefix_expression(&mut self, _node: &PrefixExpression) -> bool { + true + } + fn leave_prefix_expression(&mut self, _node: &PrefixExpression) {} + + fn enter_return_statement(&mut self, _node: &ReturnStatement) -> bool { + true + } + fn leave_return_statement(&mut self, _node: &ReturnStatement) {} + + fn enter_revert_statement(&mut self, _node: &RevertStatement) -> bool { + true + } + fn leave_revert_statement(&mut self, _node: &RevertStatement) {} + + fn enter_shift_expression(&mut self, _node: &ShiftExpression) -> bool { + true + } + fn leave_shift_expression(&mut self, _node: &ShiftExpression) {} + + fn enter_single_typed_declaration(&mut self, _node: &SingleTypedDeclaration) -> bool { + true + } + fn leave_single_typed_declaration(&mut self, _node: &SingleTypedDeclaration) {} + + fn enter_source_unit(&mut self, _node: &SourceUnit) -> bool { + true + } + fn leave_source_unit(&mut self, _node: &SourceUnit) {} + + fn enter_state_variable_definition(&mut self, _node: &StateVariableDefinition) -> bool { + true + } + fn leave_state_variable_definition(&mut self, _node: &StateVariableDefinition) {} + + fn enter_struct_definition(&mut self, _node: &StructDefinition) -> bool { + true + } + fn leave_struct_definition(&mut self, _node: &StructDefinition) {} + + fn enter_struct_member(&mut self, _node: &StructMember) -> bool { + true + } + fn leave_struct_member(&mut self, _node: &StructMember) {} + + fn enter_try_statement(&mut self, _node: &TryStatement) -> bool { + true + } + fn leave_try_statement(&mut self, _node: &TryStatement) {} + + fn enter_tuple_expression(&mut self, _node: &TupleExpression) -> bool { + true + } + fn leave_tuple_expression(&mut self, _node: &TupleExpression) {} + + fn enter_tuple_value(&mut self, _node: &TupleValue) -> bool { + true + } + fn leave_tuple_value(&mut self, _node: &TupleValue) {} + + fn enter_type_expression(&mut self, _node: &TypeExpression) -> bool { + true + } + fn leave_type_expression(&mut self, _node: &TypeExpression) {} + + fn enter_unchecked_block(&mut self, _node: &UncheckedBlock) -> bool { + true + } + fn leave_unchecked_block(&mut self, _node: &UncheckedBlock) {} + + fn enter_user_defined_value_type_definition( + &mut self, + _node: &UserDefinedValueTypeDefinition, + ) -> bool { + true + } + fn leave_user_defined_value_type_definition(&mut self, _node: &UserDefinedValueTypeDefinition) { + } + + fn enter_using_deconstruction(&mut self, _node: &UsingDeconstruction) -> bool { + true + } + fn leave_using_deconstruction(&mut self, _node: &UsingDeconstruction) {} + + fn enter_using_deconstruction_symbol(&mut self, _node: &UsingDeconstructionSymbol) -> bool { + true + } + fn leave_using_deconstruction_symbol(&mut self, _node: &UsingDeconstructionSymbol) {} + + fn enter_using_directive(&mut self, _node: &UsingDirective) -> bool { + true + } + fn leave_using_directive(&mut self, _node: &UsingDirective) {} + + fn enter_variable_declaration(&mut self, _node: &VariableDeclaration) -> bool { + true + } + fn leave_variable_declaration(&mut self, _node: &VariableDeclaration) {} + + fn enter_variable_declaration_statement( + &mut self, + _node: &VariableDeclarationStatement, + ) -> bool { + true + } + fn leave_variable_declaration_statement(&mut self, _node: &VariableDeclarationStatement) {} + + fn enter_version_pragma(&mut self, _node: &VersionPragma) -> bool { + true + } + fn leave_version_pragma(&mut self, _node: &VersionPragma) {} + + fn enter_version_range(&mut self, _node: &VersionRange) -> bool { + true + } + fn leave_version_range(&mut self, _node: &VersionRange) {} + + fn enter_version_term(&mut self, _node: &VersionTerm) -> bool { + true + } + fn leave_version_term(&mut self, _node: &VersionTerm) {} + + fn enter_while_statement(&mut self, _node: &WhileStatement) -> bool { + true + } + fn leave_while_statement(&mut self, _node: &WhileStatement) {} + + fn enter_yul_block(&mut self, _node: &YulBlock) -> bool { + true + } + fn leave_yul_block(&mut self, _node: &YulBlock) {} + + fn enter_yul_break_statement(&mut self, _node: &YulBreakStatement) -> bool { + true + } + fn leave_yul_break_statement(&mut self, _node: &YulBreakStatement) {} + + fn enter_yul_continue_statement(&mut self, _node: &YulContinueStatement) -> bool { + true + } + fn leave_yul_continue_statement(&mut self, _node: &YulContinueStatement) {} + + fn enter_yul_default_case(&mut self, _node: &YulDefaultCase) -> bool { + true + } + fn leave_yul_default_case(&mut self, _node: &YulDefaultCase) {} + + fn enter_yul_for_statement(&mut self, _node: &YulForStatement) -> bool { + true + } + fn leave_yul_for_statement(&mut self, _node: &YulForStatement) {} + + fn enter_yul_function_call_expression(&mut self, _node: &YulFunctionCallExpression) -> bool { + true + } + fn leave_yul_function_call_expression(&mut self, _node: &YulFunctionCallExpression) {} + + fn enter_yul_function_definition(&mut self, _node: &YulFunctionDefinition) -> bool { + true + } + fn leave_yul_function_definition(&mut self, _node: &YulFunctionDefinition) {} + + fn enter_yul_if_statement(&mut self, _node: &YulIfStatement) -> bool { + true + } + fn leave_yul_if_statement(&mut self, _node: &YulIfStatement) {} + + fn enter_yul_leave_statement(&mut self, _node: &YulLeaveStatement) -> bool { + true + } + fn leave_yul_leave_statement(&mut self, _node: &YulLeaveStatement) {} + + fn enter_yul_switch_statement(&mut self, _node: &YulSwitchStatement) -> bool { + true + } + fn leave_yul_switch_statement(&mut self, _node: &YulSwitchStatement) {} + + fn enter_yul_value_case(&mut self, _node: &YulValueCase) -> bool { + true + } + fn leave_yul_value_case(&mut self, _node: &YulValueCase) {} + + fn enter_yul_variable_assignment_statement( + &mut self, + _node: &YulVariableAssignmentStatement, + ) -> bool { + true + } + fn leave_yul_variable_assignment_statement(&mut self, _node: &YulVariableAssignmentStatement) {} + + fn enter_yul_variable_declaration_statement( + &mut self, + _node: &YulVariableDeclarationStatement, + ) -> bool { + true + } + fn leave_yul_variable_declaration_statement( + &mut self, + _node: &YulVariableDeclarationStatement, + ) { + } + + fn enter_yul_variable_declaration_value( + &mut self, + _node: &YulVariableDeclarationValue, + ) -> bool { + true + } + fn leave_yul_variable_declaration_value(&mut self, _node: &YulVariableDeclarationValue) {} + + fn enter_abicoder_version(&mut self, _node: &AbicoderVersion) -> bool { + true + } + fn leave_abicoder_version(&mut self, _node: &AbicoderVersion) {} + + fn enter_arguments_declaration(&mut self, _node: &ArgumentsDeclaration) -> bool { + true + } + fn leave_arguments_declaration(&mut self, _node: &ArgumentsDeclaration) {} + + fn enter_contract_member(&mut self, _node: &ContractMember) -> bool { + true + } + fn leave_contract_member(&mut self, _node: &ContractMember) {} + + fn enter_elementary_type(&mut self, _node: &ElementaryType) -> bool { + true + } + fn leave_elementary_type(&mut self, _node: &ElementaryType) {} + + fn enter_experimental_feature(&mut self, _node: &ExperimentalFeature) -> bool { + true + } + fn leave_experimental_feature(&mut self, _node: &ExperimentalFeature) {} + + fn enter_expression(&mut self, _node: &Expression) -> bool { + true + } + fn leave_expression(&mut self, _node: &Expression) {} + + fn enter_expression_additive_expression_operator( + &mut self, + _node: &Expression_AdditiveExpression_Operator, + ) -> bool { + true + } + fn leave_expression_additive_expression_operator( + &mut self, + _node: &Expression_AdditiveExpression_Operator, + ) { + } + + fn enter_expression_assignment_expression_operator( + &mut self, + _node: &Expression_AssignmentExpression_Operator, + ) -> bool { + true + } + fn leave_expression_assignment_expression_operator( + &mut self, + _node: &Expression_AssignmentExpression_Operator, + ) { + } + + fn enter_expression_equality_expression_operator( + &mut self, + _node: &Expression_EqualityExpression_Operator, + ) -> bool { + true + } + fn leave_expression_equality_expression_operator( + &mut self, + _node: &Expression_EqualityExpression_Operator, + ) { + } + + fn enter_expression_inequality_expression_operator( + &mut self, + _node: &Expression_InequalityExpression_Operator, + ) -> bool { + true + } + fn leave_expression_inequality_expression_operator( + &mut self, + _node: &Expression_InequalityExpression_Operator, + ) { + } + + fn enter_expression_multiplicative_expression_operator( + &mut self, + _node: &Expression_MultiplicativeExpression_Operator, + ) -> bool { + true + } + fn leave_expression_multiplicative_expression_operator( + &mut self, + _node: &Expression_MultiplicativeExpression_Operator, + ) { + } + + fn enter_expression_postfix_expression_operator( + &mut self, + _node: &Expression_PostfixExpression_Operator, + ) -> bool { + true + } + fn leave_expression_postfix_expression_operator( + &mut self, + _node: &Expression_PostfixExpression_Operator, + ) { + } + + fn enter_expression_prefix_expression_operator( + &mut self, + _node: &Expression_PrefixExpression_Operator, + ) -> bool { + true + } + fn leave_expression_prefix_expression_operator( + &mut self, + _node: &Expression_PrefixExpression_Operator, + ) { + } + + fn enter_expression_shift_expression_operator( + &mut self, + _node: &Expression_ShiftExpression_Operator, + ) -> bool { + true + } + fn leave_expression_shift_expression_operator( + &mut self, + _node: &Expression_ShiftExpression_Operator, + ) { + } + + fn enter_for_statement_condition(&mut self, _node: &ForStatementCondition) -> bool { + true + } + fn leave_for_statement_condition(&mut self, _node: &ForStatementCondition) {} + + fn enter_for_statement_initialization(&mut self, _node: &ForStatementInitialization) -> bool { + true + } + fn leave_for_statement_initialization(&mut self, _node: &ForStatementInitialization) {} + + fn enter_function_kind(&mut self, _node: &FunctionKind) -> bool { + true + } + fn leave_function_kind(&mut self, _node: &FunctionKind) {} + + fn enter_function_mutability(&mut self, _node: &FunctionMutability) -> bool { + true + } + fn leave_function_mutability(&mut self, _node: &FunctionMutability) {} + + fn enter_function_visibility(&mut self, _node: &FunctionVisibility) -> bool { + true + } + fn leave_function_visibility(&mut self, _node: &FunctionVisibility) {} + + fn enter_import_clause(&mut self, _node: &ImportClause) -> bool { + true + } + fn leave_import_clause(&mut self, _node: &ImportClause) {} + + fn enter_number_unit(&mut self, _node: &NumberUnit) -> bool { + true + } + fn leave_number_unit(&mut self, _node: &NumberUnit) {} + + fn enter_pragma(&mut self, _node: &Pragma) -> bool { + true + } + fn leave_pragma(&mut self, _node: &Pragma) {} + + fn enter_source_unit_member(&mut self, _node: &SourceUnitMember) -> bool { + true + } + fn leave_source_unit_member(&mut self, _node: &SourceUnitMember) {} + + fn enter_state_variable_mutability(&mut self, _node: &StateVariableMutability) -> bool { + true + } + fn leave_state_variable_mutability(&mut self, _node: &StateVariableMutability) {} + + fn enter_state_variable_visibility(&mut self, _node: &StateVariableVisibility) -> bool { + true + } + fn leave_state_variable_visibility(&mut self, _node: &StateVariableVisibility) {} + + fn enter_statement(&mut self, _node: &Statement) -> bool { + true + } + fn leave_statement(&mut self, _node: &Statement) {} + + fn enter_storage_location(&mut self, _node: &StorageLocation) -> bool { + true + } + fn leave_storage_location(&mut self, _node: &StorageLocation) {} + + fn enter_string_expression(&mut self, _node: &StringExpression) -> bool { + true + } + fn leave_string_expression(&mut self, _node: &StringExpression) {} + + fn enter_type_name(&mut self, _node: &TypeName) -> bool { + true + } + fn leave_type_name(&mut self, _node: &TypeName) {} + + fn enter_using_clause(&mut self, _node: &UsingClause) -> bool { + true + } + fn leave_using_clause(&mut self, _node: &UsingClause) {} + + fn enter_using_operator(&mut self, _node: &UsingOperator) -> bool { + true + } + fn leave_using_operator(&mut self, _node: &UsingOperator) {} + + fn enter_using_target(&mut self, _node: &UsingTarget) -> bool { + true + } + fn leave_using_target(&mut self, _node: &UsingTarget) {} + + fn enter_variable_declaration_target(&mut self, _node: &VariableDeclarationTarget) -> bool { + true + } + fn leave_variable_declaration_target(&mut self, _node: &VariableDeclarationTarget) {} + + fn enter_version_expression(&mut self, _node: &VersionExpression) -> bool { + true + } + fn leave_version_expression(&mut self, _node: &VersionExpression) {} + + fn enter_version_literal(&mut self, _node: &VersionLiteral) -> bool { + true + } + fn leave_version_literal(&mut self, _node: &VersionLiteral) {} + + fn enter_version_operator(&mut self, _node: &VersionOperator) -> bool { + true + } + fn leave_version_operator(&mut self, _node: &VersionOperator) {} + + fn enter_yul_expression(&mut self, _node: &YulExpression) -> bool { + true + } + fn leave_yul_expression(&mut self, _node: &YulExpression) {} + + fn enter_yul_literal(&mut self, _node: &YulLiteral) -> bool { + true + } + fn leave_yul_literal(&mut self, _node: &YulLiteral) {} + + fn enter_yul_statement(&mut self, _node: &YulStatement) -> bool { + true + } + fn leave_yul_statement(&mut self, _node: &YulStatement) {} + + fn enter_yul_switch_case(&mut self, _node: &YulSwitchCase) -> bool { + true + } + fn leave_yul_switch_case(&mut self, _node: &YulSwitchCase) {} + + fn enter_array_values(&mut self, _items: &ArrayValues) -> bool { + true + } + fn leave_array_values(&mut self, _items: &ArrayValues) {} + + fn enter_call_options(&mut self, _items: &CallOptions) -> bool { + true + } + fn leave_call_options(&mut self, _items: &CallOptions) {} + + fn enter_catch_clauses(&mut self, _items: &CatchClauses) -> bool { + true + } + fn leave_catch_clauses(&mut self, _items: &CatchClauses) {} + + fn enter_contract_members(&mut self, _items: &ContractMembers) -> bool { + true + } + fn leave_contract_members(&mut self, _items: &ContractMembers) {} + + fn enter_enum_members(&mut self, _items: &EnumMembers) -> bool { + true + } + fn leave_enum_members(&mut self, _items: &EnumMembers) {} + + fn enter_hex_string_literals(&mut self, _items: &[ir::HexStringLiteral]) -> bool { + true + } + fn leave_hex_string_literals(&mut self, _items: &[ir::HexStringLiteral]) {} + + fn enter_identifier_path(&mut self, _items: &IdentifierPath) -> bool { + true + } + fn leave_identifier_path(&mut self, _items: &IdentifierPath) {} + + fn enter_import_deconstruction_symbols( + &mut self, + _items: &ImportDeconstructionSymbols, + ) -> bool { + true + } + fn leave_import_deconstruction_symbols(&mut self, _items: &ImportDeconstructionSymbols) {} + + fn enter_inheritance_types(&mut self, _items: &InheritanceTypes) -> bool { + true + } + fn leave_inheritance_types(&mut self, _items: &InheritanceTypes) {} + + fn enter_interface_members(&mut self, _items: &InterfaceMembers) -> bool { + true + } + fn leave_interface_members(&mut self, _items: &InterfaceMembers) {} + + fn enter_library_members(&mut self, _items: &LibraryMembers) -> bool { + true + } + fn leave_library_members(&mut self, _items: &LibraryMembers) {} + + fn enter_modifier_invocations(&mut self, _items: &ModifierInvocations) -> bool { + true + } + fn leave_modifier_invocations(&mut self, _items: &ModifierInvocations) {} + + fn enter_multi_typed_declaration_elements( + &mut self, + _items: &MultiTypedDeclarationElements, + ) -> bool { + true + } + fn leave_multi_typed_declaration_elements(&mut self, _items: &MultiTypedDeclarationElements) {} + + fn enter_named_arguments(&mut self, _items: &NamedArguments) -> bool { + true + } + fn leave_named_arguments(&mut self, _items: &NamedArguments) {} + + fn enter_override_paths(&mut self, _items: &OverridePaths) -> bool { + true + } + fn leave_override_paths(&mut self, _items: &OverridePaths) {} + + fn enter_parameters(&mut self, _items: &Parameters) -> bool { + true + } + fn leave_parameters(&mut self, _items: &Parameters) {} + + fn enter_positional_arguments(&mut self, _items: &PositionalArguments) -> bool { + true + } + fn leave_positional_arguments(&mut self, _items: &PositionalArguments) {} + + fn enter_simple_version_literal(&mut self, _items: &[ir::VersionSpecifier]) -> bool { + true + } + fn leave_simple_version_literal(&mut self, _items: &[ir::VersionSpecifier]) {} + + fn enter_source_unit_members(&mut self, _items: &SourceUnitMembers) -> bool { + true + } + fn leave_source_unit_members(&mut self, _items: &SourceUnitMembers) {} + + fn enter_statements(&mut self, _items: &Statements) -> bool { + true + } + fn leave_statements(&mut self, _items: &Statements) {} + + fn enter_string_literals(&mut self, _items: &[ir::StringLiteral]) -> bool { + true + } + fn leave_string_literals(&mut self, _items: &[ir::StringLiteral]) {} + + fn enter_struct_members(&mut self, _items: &StructMembers) -> bool { + true + } + fn leave_struct_members(&mut self, _items: &StructMembers) {} + + fn enter_tuple_values(&mut self, _items: &TupleValues) -> bool { + true + } + fn leave_tuple_values(&mut self, _items: &TupleValues) {} + + fn enter_unicode_string_literals(&mut self, _items: &[ir::UnicodeStringLiteral]) -> bool { + true + } + fn leave_unicode_string_literals(&mut self, _items: &[ir::UnicodeStringLiteral]) {} + + fn enter_using_deconstruction_symbols(&mut self, _items: &UsingDeconstructionSymbols) -> bool { + true + } + fn leave_using_deconstruction_symbols(&mut self, _items: &UsingDeconstructionSymbols) {} + + fn enter_version_expression_set(&mut self, _items: &VersionExpressionSet) -> bool { + true + } + fn leave_version_expression_set(&mut self, _items: &VersionExpressionSet) {} + + fn enter_version_expression_sets(&mut self, _items: &VersionExpressionSets) -> bool { + true + } + fn leave_version_expression_sets(&mut self, _items: &VersionExpressionSets) {} + + fn enter_yul_arguments(&mut self, _items: &YulArguments) -> bool { + true + } + fn leave_yul_arguments(&mut self, _items: &YulArguments) {} + + fn enter_yul_flags(&mut self, _items: &[ir::StringLiteral]) -> bool { + true + } + fn leave_yul_flags(&mut self, _items: &[ir::StringLiteral]) {} + + fn enter_yul_parameters(&mut self, _items: &YulParameters) -> bool { + true + } + fn leave_yul_parameters(&mut self, _items: &YulParameters) {} + + fn enter_yul_path(&mut self, _items: &YulPath) -> bool { + true + } + fn leave_yul_path(&mut self, _items: &YulPath) {} + + fn enter_yul_paths(&mut self, _items: &YulPaths) -> bool { + true + } + fn leave_yul_paths(&mut self, _items: &YulPaths) {} + + fn enter_yul_statements(&mut self, _items: &YulStatements) -> bool { + true + } + fn leave_yul_statements(&mut self, _items: &YulStatements) {} + + fn enter_yul_switch_cases(&mut self, _items: &YulSwitchCases) -> bool { + true + } + fn leave_yul_switch_cases(&mut self, _items: &YulSwitchCases) {} + + fn enter_yul_variable_names(&mut self, _items: &YulVariableNames) -> bool { + true + } + fn leave_yul_variable_names(&mut self, _items: &YulVariableNames) {} + + fn visit_identifier(&mut self, _node: &Identifier) {} +} + +// +// Sequences +// + +pub fn accept_abicoder_pragma(node: &AbicoderPragma, visitor: &mut impl Visitor) { + if !visitor.enter_abicoder_pragma(node) { + return; + } + accept_abicoder_version(&node.version(), visitor); + visitor.leave_abicoder_pragma(node); +} + +pub fn accept_additive_expression(node: &AdditiveExpression, visitor: &mut impl Visitor) { + if !visitor.enter_additive_expression(node) { + return; + } + accept_expression(&node.left_operand(), visitor); + accept_expression_additive_expression_operator( + &node.expression_additive_expression_operator(), + visitor, + ); + accept_expression(&node.right_operand(), visitor); + visitor.leave_additive_expression(node); +} + +pub fn accept_address_type(node: &AddressType, visitor: &mut impl Visitor) { + if !visitor.enter_address_type(node) { + return; + } + visitor.leave_address_type(node); +} + +pub fn accept_and_expression(node: &AndExpression, visitor: &mut impl Visitor) { + if !visitor.enter_and_expression(node) { + return; + } + accept_expression(&node.left_operand(), visitor); + accept_expression(&node.right_operand(), visitor); + visitor.leave_and_expression(node); +} + +pub fn accept_array_expression(node: &ArrayExpression, visitor: &mut impl Visitor) { + if !visitor.enter_array_expression(node) { + return; + } + accept_array_values(&node.items(), visitor); + visitor.leave_array_expression(node); +} + +pub fn accept_array_type_name(node: &ArrayTypeName, visitor: &mut impl Visitor) { + if !visitor.enter_array_type_name(node) { + return; + } + accept_type_name(&node.operand(), visitor); + if let Some(ref index) = node.index() { + accept_expression(index, visitor); + } + visitor.leave_array_type_name(node); +} + +pub fn accept_assembly_statement(node: &AssemblyStatement, visitor: &mut impl Visitor) { + if !visitor.enter_assembly_statement(node) { + return; + } + if let Some(ref flags) = node.flags() { + accept_yul_flags(flags, visitor); + } + accept_yul_block(&node.body(), visitor); + visitor.leave_assembly_statement(node); +} + +pub fn accept_assignment_expression(node: &AssignmentExpression, visitor: &mut impl Visitor) { + if !visitor.enter_assignment_expression(node) { + return; + } + accept_expression(&node.left_operand(), visitor); + accept_expression_assignment_expression_operator( + &node.expression_assignment_expression_operator(), + visitor, + ); + accept_expression(&node.right_operand(), visitor); + visitor.leave_assignment_expression(node); +} + +pub fn accept_bitwise_and_expression(node: &BitwiseAndExpression, visitor: &mut impl Visitor) { + if !visitor.enter_bitwise_and_expression(node) { + return; + } + accept_expression(&node.left_operand(), visitor); + accept_expression(&node.right_operand(), visitor); + visitor.leave_bitwise_and_expression(node); +} + +pub fn accept_bitwise_or_expression(node: &BitwiseOrExpression, visitor: &mut impl Visitor) { + if !visitor.enter_bitwise_or_expression(node) { + return; + } + accept_expression(&node.left_operand(), visitor); + accept_expression(&node.right_operand(), visitor); + visitor.leave_bitwise_or_expression(node); +} + +pub fn accept_bitwise_xor_expression(node: &BitwiseXorExpression, visitor: &mut impl Visitor) { + if !visitor.enter_bitwise_xor_expression(node) { + return; + } + accept_expression(&node.left_operand(), visitor); + accept_expression(&node.right_operand(), visitor); + visitor.leave_bitwise_xor_expression(node); +} + +pub fn accept_block(node: &Block, visitor: &mut impl Visitor) { + if !visitor.enter_block(node) { + return; + } + accept_statements(&node.statements(), visitor); + visitor.leave_block(node); +} + +pub fn accept_break_statement(node: &BreakStatement, visitor: &mut impl Visitor) { + if !visitor.enter_break_statement(node) { + return; + } + visitor.leave_break_statement(node); +} + +pub fn accept_call_options_expression(node: &CallOptionsExpression, visitor: &mut impl Visitor) { + if !visitor.enter_call_options_expression(node) { + return; + } + accept_expression(&node.operand(), visitor); + accept_call_options(&node.options(), visitor); + visitor.leave_call_options_expression(node); +} + +pub fn accept_catch_clause(node: &CatchClause, visitor: &mut impl Visitor) { + if !visitor.enter_catch_clause(node) { + return; + } + if let Some(ref error) = node.error() { + accept_catch_clause_error(error, visitor); + } + accept_block(&node.body(), visitor); + visitor.leave_catch_clause(node); +} + +pub fn accept_catch_clause_error(node: &CatchClauseError, visitor: &mut impl Visitor) { + if !visitor.enter_catch_clause_error(node) { + return; + } + if let Some(ref name) = node.name() { + visitor.visit_identifier(name); + } + accept_parameters(&node.parameters(), visitor); + visitor.leave_catch_clause_error(node); +} + +pub fn accept_conditional_expression(node: &ConditionalExpression, visitor: &mut impl Visitor) { + if !visitor.enter_conditional_expression(node) { + return; + } + accept_expression(&node.operand(), visitor); + accept_expression(&node.true_expression(), visitor); + accept_expression(&node.false_expression(), visitor); + visitor.leave_conditional_expression(node); +} + +pub fn accept_constant_definition(node: &ConstantDefinition, visitor: &mut impl Visitor) { + if !visitor.enter_constant_definition(node) { + return; + } + accept_type_name(&node.type_name(), visitor); + visitor.visit_identifier(&node.name()); + if let Some(ref visibility) = node.visibility() { + accept_state_variable_visibility(visibility, visitor); + } + if let Some(ref value) = node.value() { + accept_expression(value, visitor); + } + visitor.leave_constant_definition(node); +} + +pub fn accept_continue_statement(node: &ContinueStatement, visitor: &mut impl Visitor) { + if !visitor.enter_continue_statement(node) { + return; + } + visitor.leave_continue_statement(node); +} + +pub fn accept_contract_definition(node: &ContractDefinition, visitor: &mut impl Visitor) { + if !visitor.enter_contract_definition(node) { + return; + } + visitor.visit_identifier(&node.name()); + accept_inheritance_types(&node.inheritance_types(), visitor); + if let Some(ref storage_layout) = node.storage_layout() { + accept_expression(storage_layout, visitor); + } + accept_contract_members(&node.members(), visitor); + visitor.leave_contract_definition(node); +} + +pub fn accept_decimal_number_expression( + node: &DecimalNumberExpression, + visitor: &mut impl Visitor, +) { + if !visitor.enter_decimal_number_expression(node) { + return; + } + if let Some(ref unit) = node.unit() { + accept_number_unit(unit, visitor); + } + visitor.leave_decimal_number_expression(node); +} + +pub fn accept_do_while_statement(node: &DoWhileStatement, visitor: &mut impl Visitor) { + if !visitor.enter_do_while_statement(node) { + return; + } + accept_statement(&node.body(), visitor); + accept_expression(&node.condition(), visitor); + visitor.leave_do_while_statement(node); +} + +pub fn accept_emit_statement(node: &EmitStatement, visitor: &mut impl Visitor) { + if !visitor.enter_emit_statement(node) { + return; + } + accept_identifier_path(&node.event(), visitor); + accept_arguments_declaration(&node.arguments(), visitor); + visitor.leave_emit_statement(node); +} + +pub fn accept_enum_definition(node: &EnumDefinition, visitor: &mut impl Visitor) { + if !visitor.enter_enum_definition(node) { + return; + } + visitor.visit_identifier(&node.name()); + accept_enum_members(&node.members(), visitor); + visitor.leave_enum_definition(node); +} + +pub fn accept_equality_expression(node: &EqualityExpression, visitor: &mut impl Visitor) { + if !visitor.enter_equality_expression(node) { + return; + } + accept_expression(&node.left_operand(), visitor); + accept_expression_equality_expression_operator( + &node.expression_equality_expression_operator(), + visitor, + ); + accept_expression(&node.right_operand(), visitor); + visitor.leave_equality_expression(node); +} + +pub fn accept_error_definition(node: &ErrorDefinition, visitor: &mut impl Visitor) { + if !visitor.enter_error_definition(node) { + return; + } + visitor.visit_identifier(&node.name()); + accept_parameters(&node.parameters(), visitor); + visitor.leave_error_definition(node); +} + +pub fn accept_event_definition(node: &EventDefinition, visitor: &mut impl Visitor) { + if !visitor.enter_event_definition(node) { + return; + } + visitor.visit_identifier(&node.name()); + accept_parameters(&node.parameters(), visitor); + visitor.leave_event_definition(node); +} + +pub fn accept_experimental_pragma(node: &ExperimentalPragma, visitor: &mut impl Visitor) { + if !visitor.enter_experimental_pragma(node) { + return; + } + accept_experimental_feature(&node.feature(), visitor); + visitor.leave_experimental_pragma(node); +} + +pub fn accept_exponentiation_expression( + node: &ExponentiationExpression, + visitor: &mut impl Visitor, +) { + if !visitor.enter_exponentiation_expression(node) { + return; + } + accept_expression(&node.left_operand(), visitor); + accept_expression(&node.right_operand(), visitor); + visitor.leave_exponentiation_expression(node); +} + +pub fn accept_expression_statement(node: &ExpressionStatement, visitor: &mut impl Visitor) { + if !visitor.enter_expression_statement(node) { + return; + } + accept_expression(&node.expression(), visitor); + visitor.leave_expression_statement(node); +} + +pub fn accept_for_statement(node: &ForStatement, visitor: &mut impl Visitor) { + if !visitor.enter_for_statement(node) { + return; + } + accept_for_statement_initialization(&node.initialization(), visitor); + accept_for_statement_condition(&node.condition(), visitor); + if let Some(ref iterator) = node.iterator() { + accept_expression(iterator, visitor); + } + accept_statement(&node.body(), visitor); + visitor.leave_for_statement(node); +} + +pub fn accept_function_call_expression(node: &FunctionCallExpression, visitor: &mut impl Visitor) { + if !visitor.enter_function_call_expression(node) { + return; + } + accept_expression(&node.operand(), visitor); + accept_arguments_declaration(&node.arguments(), visitor); + visitor.leave_function_call_expression(node); +} + +pub fn accept_function_definition(node: &FunctionDefinition, visitor: &mut impl Visitor) { + if !visitor.enter_function_definition(node) { + return; + } + accept_function_kind(&node.kind(), visitor); + if let Some(ref name) = node.name() { + visitor.visit_identifier(name); + } + accept_parameters(&node.parameters(), visitor); + accept_function_visibility(&node.visibility(), visitor); + accept_function_mutability(&node.mutability(), visitor); + if let Some(ref override_specifier) = node.override_specifier() { + accept_override_paths(override_specifier, visitor); + } + accept_modifier_invocations(&node.modifier_invocations(), visitor); + if let Some(ref returns) = node.returns() { + accept_parameters(returns, visitor); + } + if let Some(ref body) = node.body() { + accept_block(body, visitor); + } + visitor.leave_function_definition(node); +} + +pub fn accept_function_type(node: &FunctionType, visitor: &mut impl Visitor) { + if !visitor.enter_function_type(node) { + return; + } + accept_parameters(&node.parameters(), visitor); + accept_function_visibility(&node.visibility(), visitor); + accept_function_mutability(&node.mutability(), visitor); + if let Some(ref returns) = node.returns() { + accept_parameters(returns, visitor); + } + visitor.leave_function_type(node); +} + +pub fn accept_hex_number_expression(node: &HexNumberExpression, visitor: &mut impl Visitor) { + if !visitor.enter_hex_number_expression(node) { + return; + } + visitor.leave_hex_number_expression(node); +} + +pub fn accept_if_statement(node: &IfStatement, visitor: &mut impl Visitor) { + if !visitor.enter_if_statement(node) { + return; + } + accept_expression(&node.condition(), visitor); + accept_statement(&node.body(), visitor); + if let Some(ref else_branch) = node.else_branch() { + accept_statement(else_branch, visitor); + } + visitor.leave_if_statement(node); +} + +pub fn accept_import_deconstruction(node: &ImportDeconstruction, visitor: &mut impl Visitor) { + if !visitor.enter_import_deconstruction(node) { + return; + } + accept_import_deconstruction_symbols(&node.symbols(), visitor); + visitor.leave_import_deconstruction(node); +} + +pub fn accept_import_deconstruction_symbol( + node: &ImportDeconstructionSymbol, + visitor: &mut impl Visitor, +) { + if !visitor.enter_import_deconstruction_symbol(node) { + return; + } + visitor.visit_identifier(&node.name()); + if let Some(ref alias) = node.alias() { + visitor.visit_identifier(alias); + } + visitor.leave_import_deconstruction_symbol(node); +} + +pub fn accept_index_access_expression(node: &IndexAccessExpression, visitor: &mut impl Visitor) { + if !visitor.enter_index_access_expression(node) { + return; + } + accept_expression(&node.operand(), visitor); + if let Some(ref start) = node.start() { + accept_expression(start, visitor); + } + if let Some(ref end) = node.end() { + accept_expression(end, visitor); + } + visitor.leave_index_access_expression(node); +} + +pub fn accept_inequality_expression(node: &InequalityExpression, visitor: &mut impl Visitor) { + if !visitor.enter_inequality_expression(node) { + return; + } + accept_expression(&node.left_operand(), visitor); + accept_expression_inequality_expression_operator( + &node.expression_inequality_expression_operator(), + visitor, + ); + accept_expression(&node.right_operand(), visitor); + visitor.leave_inequality_expression(node); +} + +pub fn accept_inheritance_type(node: &InheritanceType, visitor: &mut impl Visitor) { + if !visitor.enter_inheritance_type(node) { + return; + } + accept_identifier_path(&node.type_name(), visitor); + if let Some(ref arguments) = node.arguments() { + accept_arguments_declaration(arguments, visitor); + } + visitor.leave_inheritance_type(node); +} + +pub fn accept_interface_definition(node: &InterfaceDefinition, visitor: &mut impl Visitor) { + if !visitor.enter_interface_definition(node) { + return; + } + visitor.visit_identifier(&node.name()); + if let Some(ref inheritance) = node.inheritance() { + accept_inheritance_types(inheritance, visitor); + } + accept_interface_members(&node.members(), visitor); + visitor.leave_interface_definition(node); +} + +pub fn accept_library_definition(node: &LibraryDefinition, visitor: &mut impl Visitor) { + if !visitor.enter_library_definition(node) { + return; + } + visitor.visit_identifier(&node.name()); + accept_library_members(&node.members(), visitor); + visitor.leave_library_definition(node); +} + +pub fn accept_mapping_type(node: &MappingType, visitor: &mut impl Visitor) { + if !visitor.enter_mapping_type(node) { + return; + } + accept_parameter(&node.key_type(), visitor); + accept_parameter(&node.value_type(), visitor); + visitor.leave_mapping_type(node); +} + +pub fn accept_member_access_expression(node: &MemberAccessExpression, visitor: &mut impl Visitor) { + if !visitor.enter_member_access_expression(node) { + return; + } + accept_expression(&node.operand(), visitor); + visitor.visit_identifier(&node.member()); + visitor.leave_member_access_expression(node); +} + +pub fn accept_modifier_invocation(node: &ModifierInvocation, visitor: &mut impl Visitor) { + if !visitor.enter_modifier_invocation(node) { + return; + } + accept_identifier_path(&node.name(), visitor); + if let Some(ref arguments) = node.arguments() { + accept_arguments_declaration(arguments, visitor); + } + visitor.leave_modifier_invocation(node); +} + +pub fn accept_multi_typed_declaration(node: &MultiTypedDeclaration, visitor: &mut impl Visitor) { + if !visitor.enter_multi_typed_declaration(node) { + return; + } + accept_multi_typed_declaration_elements(&node.elements(), visitor); + accept_expression(&node.value(), visitor); + visitor.leave_multi_typed_declaration(node); +} + +pub fn accept_multi_typed_declaration_element( + node: &MultiTypedDeclarationElement, + visitor: &mut impl Visitor, +) { + if !visitor.enter_multi_typed_declaration_element(node) { + return; + } + if let Some(ref member) = node.member() { + accept_variable_declaration(member, visitor); + } + visitor.leave_multi_typed_declaration_element(node); +} + +pub fn accept_multiplicative_expression( + node: &MultiplicativeExpression, + visitor: &mut impl Visitor, +) { + if !visitor.enter_multiplicative_expression(node) { + return; + } + accept_expression(&node.left_operand(), visitor); + accept_expression_multiplicative_expression_operator( + &node.expression_multiplicative_expression_operator(), + visitor, + ); + accept_expression(&node.right_operand(), visitor); + visitor.leave_multiplicative_expression(node); +} + +pub fn accept_named_argument(node: &NamedArgument, visitor: &mut impl Visitor) { + if !visitor.enter_named_argument(node) { + return; + } + visitor.visit_identifier(&node.name()); + accept_expression(&node.value(), visitor); + visitor.leave_named_argument(node); +} + +pub fn accept_new_expression(node: &NewExpression, visitor: &mut impl Visitor) { + if !visitor.enter_new_expression(node) { + return; + } + accept_type_name(&node.type_name(), visitor); + visitor.leave_new_expression(node); +} + +pub fn accept_or_expression(node: &OrExpression, visitor: &mut impl Visitor) { + if !visitor.enter_or_expression(node) { + return; + } + accept_expression(&node.left_operand(), visitor); + accept_expression(&node.right_operand(), visitor); + visitor.leave_or_expression(node); +} + +pub fn accept_parameter(node: &Parameter, visitor: &mut impl Visitor) { + if !visitor.enter_parameter(node) { + return; + } + accept_type_name(&node.type_name(), visitor); + if let Some(ref storage_location) = node.storage_location() { + accept_storage_location(storage_location, visitor); + } + if let Some(ref name) = node.name() { + visitor.visit_identifier(name); + } + visitor.leave_parameter(node); +} + +pub fn accept_path_import(node: &PathImport, visitor: &mut impl Visitor) { + if !visitor.enter_path_import(node) { + return; + } + if let Some(ref alias) = node.alias() { + visitor.visit_identifier(alias); + } + visitor.leave_path_import(node); +} + +pub fn accept_postfix_expression(node: &PostfixExpression, visitor: &mut impl Visitor) { + if !visitor.enter_postfix_expression(node) { + return; + } + accept_expression(&node.operand(), visitor); + accept_expression_postfix_expression_operator( + &node.expression_postfix_expression_operator(), + visitor, + ); + visitor.leave_postfix_expression(node); +} + +pub fn accept_pragma_directive(node: &PragmaDirective, visitor: &mut impl Visitor) { + if !visitor.enter_pragma_directive(node) { + return; + } + accept_pragma(&node.pragma(), visitor); + visitor.leave_pragma_directive(node); +} + +pub fn accept_prefix_expression(node: &PrefixExpression, visitor: &mut impl Visitor) { + if !visitor.enter_prefix_expression(node) { + return; + } + accept_expression_prefix_expression_operator( + &node.expression_prefix_expression_operator(), + visitor, + ); + accept_expression(&node.operand(), visitor); + visitor.leave_prefix_expression(node); +} + +pub fn accept_return_statement(node: &ReturnStatement, visitor: &mut impl Visitor) { + if !visitor.enter_return_statement(node) { + return; + } + if let Some(ref expression) = node.expression() { + accept_expression(expression, visitor); + } + visitor.leave_return_statement(node); +} + +pub fn accept_revert_statement(node: &RevertStatement, visitor: &mut impl Visitor) { + if !visitor.enter_revert_statement(node) { + return; + } + accept_identifier_path(&node.error(), visitor); + accept_arguments_declaration(&node.arguments(), visitor); + visitor.leave_revert_statement(node); +} + +pub fn accept_shift_expression(node: &ShiftExpression, visitor: &mut impl Visitor) { + if !visitor.enter_shift_expression(node) { + return; + } + accept_expression(&node.left_operand(), visitor); + accept_expression_shift_expression_operator( + &node.expression_shift_expression_operator(), + visitor, + ); + accept_expression(&node.right_operand(), visitor); + visitor.leave_shift_expression(node); +} + +pub fn accept_single_typed_declaration(node: &SingleTypedDeclaration, visitor: &mut impl Visitor) { + if !visitor.enter_single_typed_declaration(node) { + return; + } + accept_variable_declaration(&node.declaration(), visitor); + if let Some(ref value) = node.value() { + accept_expression(value, visitor); + } + visitor.leave_single_typed_declaration(node); +} + +pub fn accept_source_unit(node: &SourceUnit, visitor: &mut impl Visitor) { + if !visitor.enter_source_unit(node) { + return; + } + accept_source_unit_members(&node.members(), visitor); + visitor.leave_source_unit(node); +} + +pub fn accept_state_variable_definition( + node: &StateVariableDefinition, + visitor: &mut impl Visitor, +) { + if !visitor.enter_state_variable_definition(node) { + return; + } + accept_type_name(&node.type_name(), visitor); + visitor.visit_identifier(&node.name()); + if let Some(ref value) = node.value() { + accept_expression(value, visitor); + } + accept_state_variable_visibility(&node.visibility(), visitor); + accept_state_variable_mutability(&node.mutability(), visitor); + if let Some(ref override_specifier) = node.override_specifier() { + accept_override_paths(override_specifier, visitor); + } + visitor.leave_state_variable_definition(node); +} + +pub fn accept_struct_definition(node: &StructDefinition, visitor: &mut impl Visitor) { + if !visitor.enter_struct_definition(node) { + return; + } + visitor.visit_identifier(&node.name()); + accept_struct_members(&node.members(), visitor); + visitor.leave_struct_definition(node); +} + +pub fn accept_struct_member(node: &StructMember, visitor: &mut impl Visitor) { + if !visitor.enter_struct_member(node) { + return; + } + accept_type_name(&node.type_name(), visitor); + visitor.visit_identifier(&node.name()); + visitor.leave_struct_member(node); +} + +pub fn accept_try_statement(node: &TryStatement, visitor: &mut impl Visitor) { + if !visitor.enter_try_statement(node) { + return; + } + accept_expression(&node.expression(), visitor); + if let Some(ref returns) = node.returns() { + accept_parameters(returns, visitor); + } + accept_block(&node.body(), visitor); + accept_catch_clauses(&node.catch_clauses(), visitor); + visitor.leave_try_statement(node); +} + +pub fn accept_tuple_expression(node: &TupleExpression, visitor: &mut impl Visitor) { + if !visitor.enter_tuple_expression(node) { + return; + } + accept_tuple_values(&node.items(), visitor); + visitor.leave_tuple_expression(node); +} + +pub fn accept_tuple_value(node: &TupleValue, visitor: &mut impl Visitor) { + if !visitor.enter_tuple_value(node) { + return; + } + if let Some(ref expression) = node.expression() { + accept_expression(expression, visitor); + } + visitor.leave_tuple_value(node); +} + +pub fn accept_type_expression(node: &TypeExpression, visitor: &mut impl Visitor) { + if !visitor.enter_type_expression(node) { + return; + } + accept_type_name(&node.type_name(), visitor); + visitor.leave_type_expression(node); +} + +pub fn accept_unchecked_block(node: &UncheckedBlock, visitor: &mut impl Visitor) { + if !visitor.enter_unchecked_block(node) { + return; + } + accept_block(&node.block(), visitor); + visitor.leave_unchecked_block(node); +} + +pub fn accept_user_defined_value_type_definition( + node: &UserDefinedValueTypeDefinition, + visitor: &mut impl Visitor, +) { + if !visitor.enter_user_defined_value_type_definition(node) { + return; + } + visitor.visit_identifier(&node.name()); + accept_elementary_type(&node.value_type(), visitor); + visitor.leave_user_defined_value_type_definition(node); +} + +pub fn accept_using_deconstruction(node: &UsingDeconstruction, visitor: &mut impl Visitor) { + if !visitor.enter_using_deconstruction(node) { + return; + } + accept_using_deconstruction_symbols(&node.symbols(), visitor); + visitor.leave_using_deconstruction(node); +} + +pub fn accept_using_deconstruction_symbol( + node: &UsingDeconstructionSymbol, + visitor: &mut impl Visitor, +) { + if !visitor.enter_using_deconstruction_symbol(node) { + return; + } + accept_identifier_path(&node.name(), visitor); + if let Some(ref alias) = node.alias() { + accept_using_operator(alias, visitor); + } + visitor.leave_using_deconstruction_symbol(node); +} + +pub fn accept_using_directive(node: &UsingDirective, visitor: &mut impl Visitor) { + if !visitor.enter_using_directive(node) { + return; + } + accept_using_clause(&node.clause(), visitor); + accept_using_target(&node.target(), visitor); + visitor.leave_using_directive(node); +} + +pub fn accept_variable_declaration(node: &VariableDeclaration, visitor: &mut impl Visitor) { + if !visitor.enter_variable_declaration(node) { + return; + } + accept_type_name(&node.type_name(), visitor); + if let Some(ref storage_location) = node.storage_location() { + accept_storage_location(storage_location, visitor); + } + visitor.visit_identifier(&node.name()); + visitor.leave_variable_declaration(node); +} + +pub fn accept_variable_declaration_statement( + node: &VariableDeclarationStatement, + visitor: &mut impl Visitor, +) { + if !visitor.enter_variable_declaration_statement(node) { + return; + } + accept_variable_declaration_target(&node.target(), visitor); + visitor.leave_variable_declaration_statement(node); +} + +pub fn accept_version_pragma(node: &VersionPragma, visitor: &mut impl Visitor) { + if !visitor.enter_version_pragma(node) { + return; + } + accept_version_expression_sets(&node.sets(), visitor); + visitor.leave_version_pragma(node); +} + +pub fn accept_version_range(node: &VersionRange, visitor: &mut impl Visitor) { + if !visitor.enter_version_range(node) { + return; + } + accept_version_literal(&node.start(), visitor); + accept_version_literal(&node.end(), visitor); + visitor.leave_version_range(node); +} + +pub fn accept_version_term(node: &VersionTerm, visitor: &mut impl Visitor) { + if !visitor.enter_version_term(node) { + return; + } + if let Some(ref operator) = node.operator() { + accept_version_operator(operator, visitor); + } + accept_version_literal(&node.literal(), visitor); + visitor.leave_version_term(node); +} + +pub fn accept_while_statement(node: &WhileStatement, visitor: &mut impl Visitor) { + if !visitor.enter_while_statement(node) { + return; + } + accept_expression(&node.condition(), visitor); + accept_statement(&node.body(), visitor); + visitor.leave_while_statement(node); +} + +pub fn accept_yul_block(node: &YulBlock, visitor: &mut impl Visitor) { + if !visitor.enter_yul_block(node) { + return; + } + accept_yul_statements(&node.statements(), visitor); + visitor.leave_yul_block(node); +} + +pub fn accept_yul_break_statement(node: &YulBreakStatement, visitor: &mut impl Visitor) { + if !visitor.enter_yul_break_statement(node) { + return; + } + visitor.leave_yul_break_statement(node); +} + +pub fn accept_yul_continue_statement(node: &YulContinueStatement, visitor: &mut impl Visitor) { + if !visitor.enter_yul_continue_statement(node) { + return; + } + visitor.leave_yul_continue_statement(node); +} + +pub fn accept_yul_default_case(node: &YulDefaultCase, visitor: &mut impl Visitor) { + if !visitor.enter_yul_default_case(node) { + return; + } + accept_yul_block(&node.body(), visitor); + visitor.leave_yul_default_case(node); +} + +pub fn accept_yul_for_statement(node: &YulForStatement, visitor: &mut impl Visitor) { + if !visitor.enter_yul_for_statement(node) { + return; + } + accept_yul_block(&node.initialization(), visitor); + accept_yul_expression(&node.condition(), visitor); + accept_yul_block(&node.iterator(), visitor); + accept_yul_block(&node.body(), visitor); + visitor.leave_yul_for_statement(node); +} + +pub fn accept_yul_function_call_expression( + node: &YulFunctionCallExpression, + visitor: &mut impl Visitor, +) { + if !visitor.enter_yul_function_call_expression(node) { + return; + } + accept_yul_expression(&node.operand(), visitor); + accept_yul_arguments(&node.arguments(), visitor); + visitor.leave_yul_function_call_expression(node); +} + +pub fn accept_yul_function_definition(node: &YulFunctionDefinition, visitor: &mut impl Visitor) { + if !visitor.enter_yul_function_definition(node) { + return; + } + visitor.visit_identifier(&node.name()); + accept_yul_parameters(&node.parameters(), visitor); + if let Some(ref returns) = node.returns() { + accept_yul_variable_names(returns, visitor); + } + accept_yul_block(&node.body(), visitor); + visitor.leave_yul_function_definition(node); +} + +pub fn accept_yul_if_statement(node: &YulIfStatement, visitor: &mut impl Visitor) { + if !visitor.enter_yul_if_statement(node) { + return; + } + accept_yul_expression(&node.condition(), visitor); + accept_yul_block(&node.body(), visitor); + visitor.leave_yul_if_statement(node); +} + +pub fn accept_yul_leave_statement(node: &YulLeaveStatement, visitor: &mut impl Visitor) { + if !visitor.enter_yul_leave_statement(node) { + return; + } + visitor.leave_yul_leave_statement(node); +} + +pub fn accept_yul_switch_statement(node: &YulSwitchStatement, visitor: &mut impl Visitor) { + if !visitor.enter_yul_switch_statement(node) { + return; + } + accept_yul_expression(&node.expression(), visitor); + accept_yul_switch_cases(&node.cases(), visitor); + visitor.leave_yul_switch_statement(node); +} + +pub fn accept_yul_value_case(node: &YulValueCase, visitor: &mut impl Visitor) { + if !visitor.enter_yul_value_case(node) { + return; + } + accept_yul_literal(&node.value(), visitor); + accept_yul_block(&node.body(), visitor); + visitor.leave_yul_value_case(node); +} + +pub fn accept_yul_variable_assignment_statement( + node: &YulVariableAssignmentStatement, + visitor: &mut impl Visitor, +) { + if !visitor.enter_yul_variable_assignment_statement(node) { + return; + } + accept_yul_paths(&node.variables(), visitor); + accept_yul_expression(&node.expression(), visitor); + visitor.leave_yul_variable_assignment_statement(node); +} + +pub fn accept_yul_variable_declaration_statement( + node: &YulVariableDeclarationStatement, + visitor: &mut impl Visitor, +) { + if !visitor.enter_yul_variable_declaration_statement(node) { + return; + } + accept_yul_variable_names(&node.variables(), visitor); + if let Some(ref value) = node.value() { + accept_yul_variable_declaration_value(value, visitor); + } + visitor.leave_yul_variable_declaration_statement(node); +} + +pub fn accept_yul_variable_declaration_value( + node: &YulVariableDeclarationValue, + visitor: &mut impl Visitor, +) { + if !visitor.enter_yul_variable_declaration_value(node) { + return; + } + accept_yul_expression(&node.expression(), visitor); + visitor.leave_yul_variable_declaration_value(node); +} + +// +// Choices +// + +pub fn accept_abicoder_version(_node: &AbicoderVersion, _visitor: &mut impl Visitor) {} + +pub fn accept_arguments_declaration(node: &ArgumentsDeclaration, visitor: &mut impl Visitor) { + if !visitor.enter_arguments_declaration(node) { + return; + } + match node { + ArgumentsDeclaration::PositionalArguments(ref positional_arguments) => { + accept_positional_arguments(positional_arguments, visitor); + } + ArgumentsDeclaration::NamedArguments(ref named_arguments) => { + accept_named_arguments(named_arguments, visitor); + } + } + visitor.leave_arguments_declaration(node); +} + +pub fn accept_contract_member(node: &ContractMember, visitor: &mut impl Visitor) { + if !visitor.enter_contract_member(node) { + return; + } + match node { + ContractMember::UsingDirective(ref using_directive) => { + accept_using_directive(using_directive, visitor); + } + ContractMember::FunctionDefinition(ref function_definition) => { + accept_function_definition(function_definition, visitor); + } + ContractMember::StructDefinition(ref struct_definition) => { + accept_struct_definition(struct_definition, visitor); + } + ContractMember::EnumDefinition(ref enum_definition) => { + accept_enum_definition(enum_definition, visitor); + } + ContractMember::EventDefinition(ref event_definition) => { + accept_event_definition(event_definition, visitor); + } + ContractMember::ErrorDefinition(ref error_definition) => { + accept_error_definition(error_definition, visitor); + } + ContractMember::UserDefinedValueTypeDefinition(ref user_defined_value_type_definition) => { + accept_user_defined_value_type_definition(user_defined_value_type_definition, visitor); + } + ContractMember::StateVariableDefinition(ref state_variable_definition) => { + accept_state_variable_definition(state_variable_definition, visitor); + } + ContractMember::ConstantDefinition(ref constant_definition) => { + accept_constant_definition(constant_definition, visitor); + } + } + visitor.leave_contract_member(node); +} + +pub fn accept_elementary_type(node: &ElementaryType, visitor: &mut impl Visitor) { + if !visitor.enter_elementary_type(node) { + return; + } + match node { + ElementaryType::AddressType(ref address_type) => { + accept_address_type(address_type, visitor); + } + ElementaryType::BytesKeyword(_) => {} + ElementaryType::IntKeyword(_) => {} + ElementaryType::UintKeyword(_) => {} + ElementaryType::FixedKeyword(_) => {} + ElementaryType::UfixedKeyword(_) => {} + ElementaryType::BoolKeyword | ElementaryType::StringKeyword => {} + } + visitor.leave_elementary_type(node); +} + +pub fn accept_experimental_feature(_node: &ExperimentalFeature, _visitor: &mut impl Visitor) {} + +pub fn accept_expression(node: &Expression, visitor: &mut impl Visitor) { + if !visitor.enter_expression(node) { + return; + } + match node { + Expression::AssignmentExpression(ref assignment_expression) => { + accept_assignment_expression(assignment_expression, visitor); + } + Expression::ConditionalExpression(ref conditional_expression) => { + accept_conditional_expression(conditional_expression, visitor); + } + Expression::OrExpression(ref or_expression) => { + accept_or_expression(or_expression, visitor); + } + Expression::AndExpression(ref and_expression) => { + accept_and_expression(and_expression, visitor); + } + Expression::EqualityExpression(ref equality_expression) => { + accept_equality_expression(equality_expression, visitor); + } + Expression::InequalityExpression(ref inequality_expression) => { + accept_inequality_expression(inequality_expression, visitor); + } + Expression::BitwiseOrExpression(ref bitwise_or_expression) => { + accept_bitwise_or_expression(bitwise_or_expression, visitor); + } + Expression::BitwiseXorExpression(ref bitwise_xor_expression) => { + accept_bitwise_xor_expression(bitwise_xor_expression, visitor); + } + Expression::BitwiseAndExpression(ref bitwise_and_expression) => { + accept_bitwise_and_expression(bitwise_and_expression, visitor); + } + Expression::ShiftExpression(ref shift_expression) => { + accept_shift_expression(shift_expression, visitor); + } + Expression::AdditiveExpression(ref additive_expression) => { + accept_additive_expression(additive_expression, visitor); + } + Expression::MultiplicativeExpression(ref multiplicative_expression) => { + accept_multiplicative_expression(multiplicative_expression, visitor); + } + Expression::ExponentiationExpression(ref exponentiation_expression) => { + accept_exponentiation_expression(exponentiation_expression, visitor); + } + Expression::PostfixExpression(ref postfix_expression) => { + accept_postfix_expression(postfix_expression, visitor); + } + Expression::PrefixExpression(ref prefix_expression) => { + accept_prefix_expression(prefix_expression, visitor); + } + Expression::FunctionCallExpression(ref function_call_expression) => { + accept_function_call_expression(function_call_expression, visitor); + } + Expression::CallOptionsExpression(ref call_options_expression) => { + accept_call_options_expression(call_options_expression, visitor); + } + Expression::MemberAccessExpression(ref member_access_expression) => { + accept_member_access_expression(member_access_expression, visitor); + } + Expression::IndexAccessExpression(ref index_access_expression) => { + accept_index_access_expression(index_access_expression, visitor); + } + Expression::NewExpression(ref new_expression) => { + accept_new_expression(new_expression, visitor); + } + Expression::TupleExpression(ref tuple_expression) => { + accept_tuple_expression(tuple_expression, visitor); + } + Expression::TypeExpression(ref type_expression) => { + accept_type_expression(type_expression, visitor); + } + Expression::ArrayExpression(ref array_expression) => { + accept_array_expression(array_expression, visitor); + } + Expression::HexNumberExpression(ref hex_number_expression) => { + accept_hex_number_expression(hex_number_expression, visitor); + } + Expression::DecimalNumberExpression(ref decimal_number_expression) => { + accept_decimal_number_expression(decimal_number_expression, visitor); + } + Expression::StringExpression(ref string_expression) => { + accept_string_expression(string_expression, visitor); + } + Expression::ElementaryType(ref elementary_type) => { + accept_elementary_type(elementary_type, visitor); + } + Expression::Identifier(ref identifier) => { + visitor.visit_identifier(identifier); + } + Expression::PayableKeyword + | Expression::ThisKeyword + | Expression::SuperKeyword + | Expression::TrueKeyword + | Expression::FalseKeyword => {} + } + visitor.leave_expression(node); +} + +pub fn accept_expression_additive_expression_operator( + _node: &Expression_AdditiveExpression_Operator, + _visitor: &mut impl Visitor, +) { +} + +pub fn accept_expression_assignment_expression_operator( + _node: &Expression_AssignmentExpression_Operator, + _visitor: &mut impl Visitor, +) { +} + +pub fn accept_expression_equality_expression_operator( + _node: &Expression_EqualityExpression_Operator, + _visitor: &mut impl Visitor, +) { +} + +pub fn accept_expression_inequality_expression_operator( + _node: &Expression_InequalityExpression_Operator, + _visitor: &mut impl Visitor, +) { +} + +pub fn accept_expression_multiplicative_expression_operator( + _node: &Expression_MultiplicativeExpression_Operator, + _visitor: &mut impl Visitor, +) { +} + +pub fn accept_expression_postfix_expression_operator( + _node: &Expression_PostfixExpression_Operator, + _visitor: &mut impl Visitor, +) { +} + +pub fn accept_expression_prefix_expression_operator( + _node: &Expression_PrefixExpression_Operator, + _visitor: &mut impl Visitor, +) { +} + +pub fn accept_expression_shift_expression_operator( + _node: &Expression_ShiftExpression_Operator, + _visitor: &mut impl Visitor, +) { +} + +pub fn accept_for_statement_condition(node: &ForStatementCondition, visitor: &mut impl Visitor) { + if !visitor.enter_for_statement_condition(node) { + return; + } + match node { + ForStatementCondition::ExpressionStatement(ref expression_statement) => { + accept_expression_statement(expression_statement, visitor); + } + ForStatementCondition::Semicolon => {} + } + visitor.leave_for_statement_condition(node); +} + +pub fn accept_for_statement_initialization( + node: &ForStatementInitialization, + visitor: &mut impl Visitor, +) { + if !visitor.enter_for_statement_initialization(node) { + return; + } + match node { + ForStatementInitialization::VariableDeclarationStatement( + ref variable_declaration_statement, + ) => { + accept_variable_declaration_statement(variable_declaration_statement, visitor); + } + ForStatementInitialization::ExpressionStatement(ref expression_statement) => { + accept_expression_statement(expression_statement, visitor); + } + ForStatementInitialization::Semicolon => {} + } + visitor.leave_for_statement_initialization(node); +} + +pub fn accept_function_kind(_node: &FunctionKind, _visitor: &mut impl Visitor) {} + +pub fn accept_function_mutability(_node: &FunctionMutability, _visitor: &mut impl Visitor) {} + +pub fn accept_function_visibility(_node: &FunctionVisibility, _visitor: &mut impl Visitor) {} + +pub fn accept_import_clause(node: &ImportClause, visitor: &mut impl Visitor) { + if !visitor.enter_import_clause(node) { + return; + } + match node { + ImportClause::PathImport(ref path_import) => { + accept_path_import(path_import, visitor); + } + ImportClause::ImportDeconstruction(ref import_deconstruction) => { + accept_import_deconstruction(import_deconstruction, visitor); + } + } + visitor.leave_import_clause(node); +} + +pub fn accept_number_unit(_node: &NumberUnit, _visitor: &mut impl Visitor) {} + +pub fn accept_pragma(node: &Pragma, visitor: &mut impl Visitor) { + if !visitor.enter_pragma(node) { + return; + } + match node { + Pragma::VersionPragma(ref version_pragma) => { + accept_version_pragma(version_pragma, visitor); + } + Pragma::AbicoderPragma(ref abicoder_pragma) => { + accept_abicoder_pragma(abicoder_pragma, visitor); + } + Pragma::ExperimentalPragma(ref experimental_pragma) => { + accept_experimental_pragma(experimental_pragma, visitor); + } + } + visitor.leave_pragma(node); +} + +pub fn accept_source_unit_member(node: &SourceUnitMember, visitor: &mut impl Visitor) { + if !visitor.enter_source_unit_member(node) { + return; + } + match node { + SourceUnitMember::PragmaDirective(ref pragma_directive) => { + accept_pragma_directive(pragma_directive, visitor); + } + SourceUnitMember::ImportClause(ref import_clause) => { + accept_import_clause(import_clause, visitor); + } + SourceUnitMember::ContractDefinition(ref contract_definition) => { + accept_contract_definition(contract_definition, visitor); + } + SourceUnitMember::InterfaceDefinition(ref interface_definition) => { + accept_interface_definition(interface_definition, visitor); + } + SourceUnitMember::LibraryDefinition(ref library_definition) => { + accept_library_definition(library_definition, visitor); + } + SourceUnitMember::StructDefinition(ref struct_definition) => { + accept_struct_definition(struct_definition, visitor); + } + SourceUnitMember::EnumDefinition(ref enum_definition) => { + accept_enum_definition(enum_definition, visitor); + } + SourceUnitMember::FunctionDefinition(ref function_definition) => { + accept_function_definition(function_definition, visitor); + } + SourceUnitMember::ErrorDefinition(ref error_definition) => { + accept_error_definition(error_definition, visitor); + } + SourceUnitMember::UserDefinedValueTypeDefinition( + ref user_defined_value_type_definition, + ) => { + accept_user_defined_value_type_definition(user_defined_value_type_definition, visitor); + } + SourceUnitMember::UsingDirective(ref using_directive) => { + accept_using_directive(using_directive, visitor); + } + SourceUnitMember::EventDefinition(ref event_definition) => { + accept_event_definition(event_definition, visitor); + } + SourceUnitMember::ConstantDefinition(ref constant_definition) => { + accept_constant_definition(constant_definition, visitor); + } + } + visitor.leave_source_unit_member(node); +} + +pub fn accept_state_variable_mutability( + _node: &StateVariableMutability, + _visitor: &mut impl Visitor, +) { +} + +pub fn accept_state_variable_visibility( + _node: &StateVariableVisibility, + _visitor: &mut impl Visitor, +) { +} + +pub fn accept_statement(node: &Statement, visitor: &mut impl Visitor) { + if !visitor.enter_statement(node) { + return; + } + match node { + Statement::IfStatement(ref if_statement) => { + accept_if_statement(if_statement, visitor); + } + Statement::ForStatement(ref for_statement) => { + accept_for_statement(for_statement, visitor); + } + Statement::WhileStatement(ref while_statement) => { + accept_while_statement(while_statement, visitor); + } + Statement::DoWhileStatement(ref do_while_statement) => { + accept_do_while_statement(do_while_statement, visitor); + } + Statement::ContinueStatement(ref continue_statement) => { + accept_continue_statement(continue_statement, visitor); + } + Statement::BreakStatement(ref break_statement) => { + accept_break_statement(break_statement, visitor); + } + Statement::ReturnStatement(ref return_statement) => { + accept_return_statement(return_statement, visitor); + } + Statement::EmitStatement(ref emit_statement) => { + accept_emit_statement(emit_statement, visitor); + } + Statement::TryStatement(ref try_statement) => { + accept_try_statement(try_statement, visitor); + } + Statement::RevertStatement(ref revert_statement) => { + accept_revert_statement(revert_statement, visitor); + } + Statement::AssemblyStatement(ref assembly_statement) => { + accept_assembly_statement(assembly_statement, visitor); + } + Statement::Block(ref block) => { + accept_block(block, visitor); + } + Statement::UncheckedBlock(ref unchecked_block) => { + accept_unchecked_block(unchecked_block, visitor); + } + Statement::VariableDeclarationStatement(ref variable_declaration_statement) => { + accept_variable_declaration_statement(variable_declaration_statement, visitor); + } + Statement::ExpressionStatement(ref expression_statement) => { + accept_expression_statement(expression_statement, visitor); + } + } + visitor.leave_statement(node); +} + +pub fn accept_storage_location(_node: &StorageLocation, _visitor: &mut impl Visitor) {} + +pub fn accept_string_expression(node: &StringExpression, visitor: &mut impl Visitor) { + if !visitor.enter_string_expression(node) { + return; + } + match node { + StringExpression::StringLiterals(ref string_literals) => { + accept_string_literals(string_literals, visitor); + } + StringExpression::HexStringLiterals(ref hex_string_literals) => { + accept_hex_string_literals(hex_string_literals, visitor); + } + StringExpression::UnicodeStringLiterals(ref unicode_string_literals) => { + accept_unicode_string_literals(unicode_string_literals, visitor); + } + } + visitor.leave_string_expression(node); +} + +pub fn accept_type_name(node: &TypeName, visitor: &mut impl Visitor) { + if !visitor.enter_type_name(node) { + return; + } + match node { + TypeName::ArrayTypeName(ref array_type_name) => { + accept_array_type_name(array_type_name, visitor); + } + TypeName::FunctionType(ref function_type) => { + accept_function_type(function_type, visitor); + } + TypeName::MappingType(ref mapping_type) => { + accept_mapping_type(mapping_type, visitor); + } + TypeName::ElementaryType(ref elementary_type) => { + accept_elementary_type(elementary_type, visitor); + } + TypeName::IdentifierPath(ref identifier_path) => { + accept_identifier_path(identifier_path, visitor); + } + } + visitor.leave_type_name(node); +} + +pub fn accept_using_clause(node: &UsingClause, visitor: &mut impl Visitor) { + if !visitor.enter_using_clause(node) { + return; + } + match node { + UsingClause::IdentifierPath(ref identifier_path) => { + accept_identifier_path(identifier_path, visitor); + } + UsingClause::UsingDeconstruction(ref using_deconstruction) => { + accept_using_deconstruction(using_deconstruction, visitor); + } + } + visitor.leave_using_clause(node); +} + +pub fn accept_using_operator(_node: &UsingOperator, _visitor: &mut impl Visitor) {} + +pub fn accept_using_target(node: &UsingTarget, visitor: &mut impl Visitor) { + if !visitor.enter_using_target(node) { + return; + } + match node { + UsingTarget::TypeName(ref type_name) => { + accept_type_name(type_name, visitor); + } + UsingTarget::Asterisk => {} + } + visitor.leave_using_target(node); +} + +pub fn accept_variable_declaration_target( + node: &VariableDeclarationTarget, + visitor: &mut impl Visitor, +) { + if !visitor.enter_variable_declaration_target(node) { + return; + } + match node { + VariableDeclarationTarget::SingleTypedDeclaration(ref single_typed_declaration) => { + accept_single_typed_declaration(single_typed_declaration, visitor); + } + VariableDeclarationTarget::MultiTypedDeclaration(ref multi_typed_declaration) => { + accept_multi_typed_declaration(multi_typed_declaration, visitor); + } + } + visitor.leave_variable_declaration_target(node); +} + +pub fn accept_version_expression(node: &VersionExpression, visitor: &mut impl Visitor) { + if !visitor.enter_version_expression(node) { + return; + } + match node { + VersionExpression::VersionRange(ref version_range) => { + accept_version_range(version_range, visitor); + } + VersionExpression::VersionTerm(ref version_term) => { + accept_version_term(version_term, visitor); + } + } + visitor.leave_version_expression(node); +} + +pub fn accept_version_literal(node: &VersionLiteral, visitor: &mut impl Visitor) { + if !visitor.enter_version_literal(node) { + return; + } + match node { + VersionLiteral::SimpleVersionLiteral(ref simple_version_literal) => { + accept_simple_version_literal(simple_version_literal, visitor); + } + VersionLiteral::StringLiteral(_) => {} + } + visitor.leave_version_literal(node); +} + +pub fn accept_version_operator(_node: &VersionOperator, _visitor: &mut impl Visitor) {} + +pub fn accept_yul_expression(node: &YulExpression, visitor: &mut impl Visitor) { + if !visitor.enter_yul_expression(node) { + return; + } + match node { + YulExpression::YulFunctionCallExpression(ref yul_function_call_expression) => { + accept_yul_function_call_expression(yul_function_call_expression, visitor); + } + YulExpression::YulLiteral(ref yul_literal) => { + accept_yul_literal(yul_literal, visitor); + } + YulExpression::YulPath(ref yul_path) => { + accept_yul_path(yul_path, visitor); + } + } + visitor.leave_yul_expression(node); +} + +pub fn accept_yul_literal(_node: &YulLiteral, _visitor: &mut impl Visitor) {} + +pub fn accept_yul_statement(node: &YulStatement, visitor: &mut impl Visitor) { + if !visitor.enter_yul_statement(node) { + return; + } + match node { + YulStatement::YulBlock(ref yul_block) => { + accept_yul_block(yul_block, visitor); + } + YulStatement::YulFunctionDefinition(ref yul_function_definition) => { + accept_yul_function_definition(yul_function_definition, visitor); + } + YulStatement::YulIfStatement(ref yul_if_statement) => { + accept_yul_if_statement(yul_if_statement, visitor); + } + YulStatement::YulForStatement(ref yul_for_statement) => { + accept_yul_for_statement(yul_for_statement, visitor); + } + YulStatement::YulSwitchStatement(ref yul_switch_statement) => { + accept_yul_switch_statement(yul_switch_statement, visitor); + } + YulStatement::YulLeaveStatement(ref yul_leave_statement) => { + accept_yul_leave_statement(yul_leave_statement, visitor); + } + YulStatement::YulBreakStatement(ref yul_break_statement) => { + accept_yul_break_statement(yul_break_statement, visitor); + } + YulStatement::YulContinueStatement(ref yul_continue_statement) => { + accept_yul_continue_statement(yul_continue_statement, visitor); + } + YulStatement::YulVariableAssignmentStatement(ref yul_variable_assignment_statement) => { + accept_yul_variable_assignment_statement(yul_variable_assignment_statement, visitor); + } + YulStatement::YulVariableDeclarationStatement(ref yul_variable_declaration_statement) => { + accept_yul_variable_declaration_statement(yul_variable_declaration_statement, visitor); + } + YulStatement::YulExpression(ref yul_expression) => { + accept_yul_expression(yul_expression, visitor); + } + } + visitor.leave_yul_statement(node); +} + +pub fn accept_yul_switch_case(node: &YulSwitchCase, visitor: &mut impl Visitor) { + if !visitor.enter_yul_switch_case(node) { + return; + } + match node { + YulSwitchCase::YulDefaultCase(ref yul_default_case) => { + accept_yul_default_case(yul_default_case, visitor); + } + YulSwitchCase::YulValueCase(ref yul_value_case) => { + accept_yul_value_case(yul_value_case, visitor); + } + } + visitor.leave_yul_switch_case(node); +} + +// +// Repeated & Separated +// + +#[inline] +fn accept_array_values(items: &ArrayValues, visitor: &mut impl Visitor) { + if !visitor.enter_array_values(items) { + return; + } + for item in items.iter() { + accept_expression(&item, visitor); + } + visitor.leave_array_values(items); +} + +#[inline] +fn accept_call_options(items: &CallOptions, visitor: &mut impl Visitor) { + if !visitor.enter_call_options(items) { + return; + } + for item in items.iter() { + accept_named_argument(&item, visitor); + } + visitor.leave_call_options(items); +} + +#[inline] +fn accept_catch_clauses(items: &CatchClauses, visitor: &mut impl Visitor) { + if !visitor.enter_catch_clauses(items) { + return; + } + for item in items.iter() { + accept_catch_clause(&item, visitor); + } + visitor.leave_catch_clauses(items); +} + +#[inline] +fn accept_contract_members(items: &ContractMembers, visitor: &mut impl Visitor) { + if !visitor.enter_contract_members(items) { + return; + } + for item in items.iter() { + accept_contract_member(&item, visitor); + } + visitor.leave_contract_members(items); +} + +#[inline] +fn accept_enum_members(items: &EnumMembers, visitor: &mut impl Visitor) { + if !visitor.enter_enum_members(items) { + return; + } + for item in items.iter() { + visitor.visit_identifier(&item); + } + visitor.leave_enum_members(items); +} + +#[inline] +fn accept_hex_string_literals(items: &[ir::HexStringLiteral], visitor: &mut impl Visitor) { + if !visitor.enter_hex_string_literals(items) { + return; + } + visitor.leave_hex_string_literals(items); +} + +#[inline] +fn accept_identifier_path(items: &IdentifierPath, visitor: &mut impl Visitor) { + if !visitor.enter_identifier_path(items) { + return; + } + for item in items.iter() { + visitor.visit_identifier(&item); + } + visitor.leave_identifier_path(items); +} + +#[inline] +fn accept_import_deconstruction_symbols( + items: &ImportDeconstructionSymbols, + visitor: &mut impl Visitor, +) { + if !visitor.enter_import_deconstruction_symbols(items) { + return; + } + for item in items.iter() { + accept_import_deconstruction_symbol(&item, visitor); + } + visitor.leave_import_deconstruction_symbols(items); +} + +#[inline] +fn accept_inheritance_types(items: &InheritanceTypes, visitor: &mut impl Visitor) { + if !visitor.enter_inheritance_types(items) { + return; + } + for item in items.iter() { + accept_inheritance_type(&item, visitor); + } + visitor.leave_inheritance_types(items); +} + +#[inline] +fn accept_interface_members(items: &InterfaceMembers, visitor: &mut impl Visitor) { + if !visitor.enter_interface_members(items) { + return; + } + for item in items.iter() { + accept_contract_member(&item, visitor); + } + visitor.leave_interface_members(items); +} + +#[inline] +fn accept_library_members(items: &LibraryMembers, visitor: &mut impl Visitor) { + if !visitor.enter_library_members(items) { + return; + } + for item in items.iter() { + accept_contract_member(&item, visitor); + } + visitor.leave_library_members(items); +} + +#[inline] +fn accept_modifier_invocations(items: &ModifierInvocations, visitor: &mut impl Visitor) { + if !visitor.enter_modifier_invocations(items) { + return; + } + for item in items.iter() { + accept_modifier_invocation(&item, visitor); + } + visitor.leave_modifier_invocations(items); +} + +#[inline] +fn accept_multi_typed_declaration_elements( + items: &MultiTypedDeclarationElements, + visitor: &mut impl Visitor, +) { + if !visitor.enter_multi_typed_declaration_elements(items) { + return; + } + for item in items.iter() { + accept_multi_typed_declaration_element(&item, visitor); + } + visitor.leave_multi_typed_declaration_elements(items); +} + +#[inline] +fn accept_named_arguments(items: &NamedArguments, visitor: &mut impl Visitor) { + if !visitor.enter_named_arguments(items) { + return; + } + for item in items.iter() { + accept_named_argument(&item, visitor); + } + visitor.leave_named_arguments(items); +} + +#[inline] +fn accept_override_paths(items: &OverridePaths, visitor: &mut impl Visitor) { + if !visitor.enter_override_paths(items) { + return; + } + for item in items.iter() { + accept_identifier_path(&item, visitor); + } + visitor.leave_override_paths(items); +} + +#[inline] +fn accept_parameters(items: &Parameters, visitor: &mut impl Visitor) { + if !visitor.enter_parameters(items) { + return; + } + for item in items.iter() { + accept_parameter(&item, visitor); + } + visitor.leave_parameters(items); +} + +#[inline] +fn accept_positional_arguments(items: &PositionalArguments, visitor: &mut impl Visitor) { + if !visitor.enter_positional_arguments(items) { + return; + } + for item in items.iter() { + accept_expression(&item, visitor); + } + visitor.leave_positional_arguments(items); +} + +#[inline] +fn accept_simple_version_literal(items: &[ir::VersionSpecifier], visitor: &mut impl Visitor) { + if !visitor.enter_simple_version_literal(items) { + return; + } + visitor.leave_simple_version_literal(items); +} + +#[inline] +fn accept_source_unit_members(items: &SourceUnitMembers, visitor: &mut impl Visitor) { + if !visitor.enter_source_unit_members(items) { + return; + } + for item in items.iter() { + accept_source_unit_member(&item, visitor); + } + visitor.leave_source_unit_members(items); +} + +#[inline] +fn accept_statements(items: &Statements, visitor: &mut impl Visitor) { + if !visitor.enter_statements(items) { + return; + } + for item in items.iter() { + accept_statement(&item, visitor); + } + visitor.leave_statements(items); +} + +#[inline] +fn accept_string_literals(items: &[ir::StringLiteral], visitor: &mut impl Visitor) { + if !visitor.enter_string_literals(items) { + return; + } + visitor.leave_string_literals(items); +} + +#[inline] +fn accept_struct_members(items: &StructMembers, visitor: &mut impl Visitor) { + if !visitor.enter_struct_members(items) { + return; + } + for item in items.iter() { + accept_struct_member(&item, visitor); + } + visitor.leave_struct_members(items); +} + +#[inline] +fn accept_tuple_values(items: &TupleValues, visitor: &mut impl Visitor) { + if !visitor.enter_tuple_values(items) { + return; + } + for item in items.iter() { + accept_tuple_value(&item, visitor); + } + visitor.leave_tuple_values(items); +} + +#[inline] +fn accept_unicode_string_literals(items: &[ir::UnicodeStringLiteral], visitor: &mut impl Visitor) { + if !visitor.enter_unicode_string_literals(items) { + return; + } + visitor.leave_unicode_string_literals(items); +} + +#[inline] +fn accept_using_deconstruction_symbols( + items: &UsingDeconstructionSymbols, + visitor: &mut impl Visitor, +) { + if !visitor.enter_using_deconstruction_symbols(items) { + return; + } + for item in items.iter() { + accept_using_deconstruction_symbol(&item, visitor); + } + visitor.leave_using_deconstruction_symbols(items); +} + +#[inline] +fn accept_version_expression_set(items: &VersionExpressionSet, visitor: &mut impl Visitor) { + if !visitor.enter_version_expression_set(items) { + return; + } + for item in items.iter() { + accept_version_expression(&item, visitor); + } + visitor.leave_version_expression_set(items); +} + +#[inline] +fn accept_version_expression_sets(items: &VersionExpressionSets, visitor: &mut impl Visitor) { + if !visitor.enter_version_expression_sets(items) { + return; + } + for item in items.iter() { + accept_version_expression_set(&item, visitor); + } + visitor.leave_version_expression_sets(items); +} + +#[inline] +fn accept_yul_arguments(items: &YulArguments, visitor: &mut impl Visitor) { + if !visitor.enter_yul_arguments(items) { + return; + } + for item in items.iter() { + accept_yul_expression(&item, visitor); + } + visitor.leave_yul_arguments(items); +} + +#[inline] +fn accept_yul_flags(items: &[ir::StringLiteral], visitor: &mut impl Visitor) { + if !visitor.enter_yul_flags(items) { + return; + } + visitor.leave_yul_flags(items); +} + +#[inline] +fn accept_yul_parameters(items: &YulParameters, visitor: &mut impl Visitor) { + if !visitor.enter_yul_parameters(items) { + return; + } + for item in items.iter() { + visitor.visit_identifier(&item); + } + visitor.leave_yul_parameters(items); +} + +#[inline] +fn accept_yul_path(items: &YulPath, visitor: &mut impl Visitor) { + if !visitor.enter_yul_path(items) { + return; + } + for item in items.iter() { + visitor.visit_identifier(&item); + } + visitor.leave_yul_path(items); +} + +#[inline] +fn accept_yul_paths(items: &YulPaths, visitor: &mut impl Visitor) { + if !visitor.enter_yul_paths(items) { + return; + } + for item in items.iter() { + accept_yul_path(&item, visitor); + } + visitor.leave_yul_paths(items); +} + +#[inline] +fn accept_yul_statements(items: &YulStatements, visitor: &mut impl Visitor) { + if !visitor.enter_yul_statements(items) { + return; + } + for item in items.iter() { + accept_yul_statement(&item, visitor); + } + visitor.leave_yul_statements(items); +} + +#[inline] +fn accept_yul_switch_cases(items: &YulSwitchCases, visitor: &mut impl Visitor) { + if !visitor.enter_yul_switch_cases(items) { + return; + } + for item in items.iter() { + accept_yul_switch_case(&item, visitor); + } + visitor.leave_yul_switch_cases(items); +} + +#[inline] +fn accept_yul_variable_names(items: &YulVariableNames, visitor: &mut impl Visitor) { + if !visitor.enter_yul_variable_names(items) { + return; + } + for item in items.iter() { + visitor.visit_identifier(&item); + } + visitor.leave_yul_variable_names(items); +} diff --git a/crates/solidity-v2/outputs/cargo/ast/src/ast/visitor.rs.jinja2 b/crates/solidity-v2/outputs/cargo/ast/src/ast/visitor.rs.jinja2 new file mode 100644 index 0000000000..98a1f5a667 --- /dev/null +++ b/crates/solidity-v2/outputs/cargo/ast/src/ast/visitor.rs.jinja2 @@ -0,0 +1,145 @@ +{%- set target = model.ir_language_model.target -%} +#[allow(clippy::wildcard_imports)] +use super::nodes::*; +use slang_solidity_v2_ir::ir; + +pub trait Visitor { + {%- for parent_type, sequence in target.sequences %} + fn enter_{{ parent_type | snake_case }}(&mut self, _node: &{{ parent_type }}) -> bool { true } + fn leave_{{ parent_type | snake_case }}(&mut self, _node: &{{ parent_type }}) {} + {% endfor -%} + {%- for parent_type, choice in target.choices %} + fn enter_{{ parent_type | snake_case }}(&mut self, _node: &{{ parent_type }}) -> bool { true } + fn leave_{{ parent_type | snake_case }}(&mut self, _node: &{{ parent_type }}) {} + {% endfor -%} + {%- for parent_type, collection in target.collections %} + {% if collection.item_type.is_terminal and + not target.terminals[collection.item_type.name].is_identifier %} + fn enter_{{ parent_type | snake_case }}( + &mut self, _items: &[ir::{{ collection.item_type.name }}], + ) -> bool { true } + fn leave_{{ parent_type | snake_case }}( + &mut self, _items: &[ir::{{ collection.item_type.name }}], + ) {} + {% else %} + fn enter_{{ parent_type | snake_case }}(&mut self, _items: &{{ parent_type }}) -> bool { true } + fn leave_{{ parent_type | snake_case }}(&mut self, _items: &{{ parent_type }}) {} + {% endif %} + {% endfor -%} + {%- for terminal_type, terminal in target.terminals %} + {%- if terminal.is_identifier %} + fn visit_{{ terminal_type | snake_case }}(&mut self, _node: &{{ terminal_type }}) {} + {% endif -%} + {% endfor -%} +} + +// +// Sequences +// + +{% for parent_type, sequence in target.sequences %} + pub fn accept_{{ parent_type | snake_case }}(node: &{{ parent_type }}, visitor: &mut impl Visitor) { + if !visitor.enter_{{ parent_type | snake_case }}(node) { + return; + } + {% for field in sequence.fields -%} + {%- if field.is_optional -%} + {%- if not field.type.is_terminal -%} + if let Some(ref {{ field.label | snake_case }}) = node.{{ field.label | snake_case }}() { + accept_{{ field.type.name | snake_case }}({{ field.label | snake_case }}, visitor); + } + {%- elif target.terminals[field.type.name].is_identifier -%} + if let Some(ref {{ field.label | snake_case }}) = node.{{ field.label | snake_case }}() { + visitor.visit_{{ field.type.name | snake_case }}({{ field.label | snake_case }}); + } + {%- endif -%} + {%- else -%} + {%- if not field.type.is_terminal -%} + accept_{{ field.type.name | snake_case }}(&node.{{ field.label | snake_case }}(), visitor); + {%- elif target.terminals[field.type.name].is_identifier -%} + visitor.visit_{{ field.type.name | snake_case }}(&node.{{ field.label | snake_case }}()); + {%- endif -%} + {%- endif -%} + {%- endfor -%} + visitor.leave_{{ parent_type | snake_case }}(node); + } + +{% endfor %} + +// +// Choices +// + +{% for parent_type, choice in target.choices %} + {%- set nonterminals = choice.variants | filter(attribute="kind", value="Nonterminal") -%} + {%- set unique_terminals = choice.variants | filter(attribute="kind", value="UniqueTerminal") -%} + {%- set non_unique_terminals = choice.variants | filter(attribute="kind", value="Terminal") -%} + {% if nonterminals | length == 0 %} + pub fn accept_{{ parent_type | snake_case }}(_node: &{{ parent_type }}, _visitor: &mut impl Visitor) {} + {% else %} + pub fn accept_{{ parent_type | snake_case }}(node: &{{ parent_type }}, visitor: &mut impl Visitor) { + if !visitor.enter_{{ parent_type | snake_case }}(node) { + return; + } + match node { + {% for nonterminal in nonterminals -%} + {{ parent_type }}::{{ nonterminal.name }}(ref {{ nonterminal.name | snake_case }}) => { + accept_{{ nonterminal.name | snake_case }}({{ nonterminal.name | snake_case }}, visitor); + } + {%- endfor %} + {%- if non_unique_terminals | length > 0 %} + {%- for terminal in non_unique_terminals -%} + {%- if target.terminals[terminal.name].is_identifier -%} + {{ parent_type }}::{{ terminal.name }}(ref {{ terminal.name | snake_case }}) => { + visitor.visit_{{ terminal.name | snake_case }}({{ terminal.name | snake_case }}); + } + {%- else -%} + {{ parent_type }}::{{ terminal.name }}(_) => {} + {%- endif -%} + {%- endfor -%} + {% endif -%} + {%- if unique_terminals | length > 0 %} + {%- for terminal in unique_terminals -%} + {%- if not loop.first -%} | {%- endif -%} + {{ parent_type }}::{{ terminal.name }} + {%- endfor -%} + => {} + {% endif -%} + } + visitor.leave_{{ parent_type | snake_case }}(node); + } + {% endif %} +{% endfor %} + +// +// Repeated & Separated +// + +{% for parent_type, collection in target.collections -%} + {% if collection.item_type.is_terminal and + not target.terminals[collection.item_type.name].is_identifier %} + {# non-identifier terminals #} + {% set collection_type = "[ir::" ~ collection.item_type.name ~ "]" %} + {% else %} + {% set collection_type = parent_type %} + {% endif %} + #[inline] + fn accept_{{ parent_type | snake_case }}(items: &{{ collection_type }}, visitor: &mut impl Visitor) { + if !visitor.enter_{{ parent_type | snake_case }}(items) { + return; + } + {%- if not collection.item_type.is_terminal %} + for item in items.iter() { + accept_{{ collection.item_type.name | snake_case }}(&item, visitor); + } + {% elif target.terminals[collection.item_type.name].is_identifier %} + for item in items.iter() { + visitor.visit_{{ collection.item_type.name | snake_case }}(&item); + } + {% else -%} + {# non-identifier terminal items are not visited #} + {% endif -%} + visitor.leave_{{ parent_type | snake_case }}(items); + } + +{% endfor %} diff --git a/crates/solidity-v2/outputs/cargo/ast/src/lib.rs b/crates/solidity-v2/outputs/cargo/ast/src/lib.rs new file mode 100644 index 0000000000..2fcc324bfb --- /dev/null +++ b/crates/solidity-v2/outputs/cargo/ast/src/lib.rs @@ -0,0 +1,2 @@ +pub mod abi; +pub mod ast; diff --git a/crates/solidity-v2/outputs/cargo/ir/Cargo.toml b/crates/solidity-v2/outputs/cargo/ir/Cargo.toml index 6ec90afb19..c449ff9c6f 100644 --- a/crates/solidity-v2/outputs/cargo/ir/Cargo.toml +++ b/crates/solidity-v2/outputs/cargo/ir/Cargo.toml @@ -19,6 +19,7 @@ keywords = ["utilities"] categories = ["compilers", "utilities"] [dependencies] +indexmap = { workspace = true } slang_solidity_v2_cst = { workspace = true } [dev-dependencies] diff --git a/crates/solidity-v2/outputs/cargo/ir/src/interner.rs b/crates/solidity-v2/outputs/cargo/ir/src/interner.rs new file mode 100644 index 0000000000..f88705862c --- /dev/null +++ b/crates/solidity-v2/outputs/cargo/ir/src/interner.rs @@ -0,0 +1,25 @@ +use indexmap::IndexSet; + +#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)] +#[repr(transparent)] +pub struct StringId(usize); + +#[derive(Debug, Default)] +pub struct Interner { + strings: IndexSet, +} + +impl Interner { + pub fn new() -> Self { + Self::default() + } + + pub fn intern(&mut self, text: &str) -> StringId { + let (index, _) = self.strings.insert_full(text.to_owned()); + StringId(index) + } + + pub fn resolve(&self, id: StringId) -> &str { + &self.strings[id.0] + } +} diff --git a/crates/solidity-v2/outputs/cargo/ir/src/ir/builder/default.generated.rs b/crates/solidity-v2/outputs/cargo/ir/src/ir/builder/default.generated.rs index 1df50f84dc..7d392c3c41 100644 --- a/crates/solidity-v2/outputs/cargo/ir/src/ir/builder/default.generated.rs +++ b/crates/solidity-v2/outputs/cargo/ir/src/ir/builder/default.generated.rs @@ -8,10 +8,11 @@ use std::rc::Rc; use slang_solidity_v2_cst::structured_cst::nodes as input; +use crate::interner::StringId; use crate::ir::nodes as output; pub trait Builder { - fn unparse_range(&self, range: std::ops::Range) -> String; + fn intern_string(&mut self, range: std::ops::Range) -> StringId; // // Sequences @@ -2225,17 +2226,17 @@ pub trait Builder { ) -> output::Identifier { match source { input::IdentifierPathElement::Identifier(terminal) => { - let text = self.unparse_range(terminal.range.clone()); + let string_id = self.intern_string(terminal.range.clone()); Rc::new(output::IdentifierStruct { range: terminal.range.clone(), - text, + string_id, }) } input::IdentifierPathElement::AddressKeyword(terminal) => { - let text = self.unparse_range(terminal.range.clone()); + let string_id = self.intern_string(terminal.range.clone()); Rc::new(output::IdentifierStruct { range: terminal.range.clone(), - text, + string_id, }) } } @@ -2564,34 +2565,34 @@ pub trait Builder { // fn build_bytes_keyword(&mut self, source: &input::BytesKeyword) -> output::BytesKeyword { - let text = self.unparse_range(source.range.clone()); + let string_id = self.intern_string(source.range.clone()); Rc::new(output::BytesKeywordStruct { range: source.range.clone(), - text, + string_id, }) } fn build_decimal_literal(&mut self, source: &input::DecimalLiteral) -> output::DecimalLiteral { - let text = self.unparse_range(source.range.clone()); + let string_id = self.intern_string(source.range.clone()); Rc::new(output::DecimalLiteralStruct { range: source.range.clone(), - text, + string_id, }) } fn build_fixed_keyword(&mut self, source: &input::FixedKeyword) -> output::FixedKeyword { - let text = self.unparse_range(source.range.clone()); + let string_id = self.intern_string(source.range.clone()); Rc::new(output::FixedKeywordStruct { range: source.range.clone(), - text, + string_id, }) } fn build_hex_literal(&mut self, source: &input::HexLiteral) -> output::HexLiteral { - let text = self.unparse_range(source.range.clone()); + let string_id = self.intern_string(source.range.clone()); Rc::new(output::HexLiteralStruct { range: source.range.clone(), - text, + string_id, }) } @@ -2599,50 +2600,50 @@ pub trait Builder { &mut self, source: &input::HexStringLiteral, ) -> output::HexStringLiteral { - let text = self.unparse_range(source.range.clone()); + let string_id = self.intern_string(source.range.clone()); Rc::new(output::HexStringLiteralStruct { range: source.range.clone(), - text, + string_id, }) } fn build_identifier(&mut self, source: &input::Identifier) -> output::Identifier { - let text = self.unparse_range(source.range.clone()); + let string_id = self.intern_string(source.range.clone()); Rc::new(output::IdentifierStruct { range: source.range.clone(), - text, + string_id, }) } fn build_int_keyword(&mut self, source: &input::IntKeyword) -> output::IntKeyword { - let text = self.unparse_range(source.range.clone()); + let string_id = self.intern_string(source.range.clone()); Rc::new(output::IntKeywordStruct { range: source.range.clone(), - text, + string_id, }) } fn build_string_literal(&mut self, source: &input::StringLiteral) -> output::StringLiteral { - let text = self.unparse_range(source.range.clone()); + let string_id = self.intern_string(source.range.clone()); Rc::new(output::StringLiteralStruct { range: source.range.clone(), - text, + string_id, }) } fn build_ufixed_keyword(&mut self, source: &input::UfixedKeyword) -> output::UfixedKeyword { - let text = self.unparse_range(source.range.clone()); + let string_id = self.intern_string(source.range.clone()); Rc::new(output::UfixedKeywordStruct { range: source.range.clone(), - text, + string_id, }) } fn build_uint_keyword(&mut self, source: &input::UintKeyword) -> output::UintKeyword { - let text = self.unparse_range(source.range.clone()); + let string_id = self.intern_string(source.range.clone()); Rc::new(output::UintKeywordStruct { range: source.range.clone(), - text, + string_id, }) } @@ -2650,10 +2651,10 @@ pub trait Builder { &mut self, source: &input::UnicodeStringLiteral, ) -> output::UnicodeStringLiteral { - let text = self.unparse_range(source.range.clone()); + let string_id = self.intern_string(source.range.clone()); Rc::new(output::UnicodeStringLiteralStruct { range: source.range.clone(), - text, + string_id, }) } @@ -2661,10 +2662,10 @@ pub trait Builder { &mut self, source: &input::VersionSpecifier, ) -> output::VersionSpecifier { - let text = self.unparse_range(source.range.clone()); + let string_id = self.intern_string(source.range.clone()); Rc::new(output::VersionSpecifierStruct { range: source.range.clone(), - text, + string_id, }) } @@ -2676,10 +2677,10 @@ pub trait Builder { &mut self, source: &input::PragmaStringLiteral, ) -> output::StringLiteral { - let text = self.unparse_range(source.range.clone()); + let string_id = self.intern_string(source.range.clone()); Rc::new(output::StringLiteralStruct { range: source.range.clone(), - text, + string_id, }) } @@ -2687,18 +2688,18 @@ pub trait Builder { &mut self, source: &input::YulDecimalLiteral, ) -> output::DecimalLiteral { - let text = self.unparse_range(source.range.clone()); + let string_id = self.intern_string(source.range.clone()); Rc::new(output::DecimalLiteralStruct { range: source.range.clone(), - text, + string_id, }) } fn build_yul_hex_literal(&mut self, source: &input::YulHexLiteral) -> output::HexLiteral { - let text = self.unparse_range(source.range.clone()); + let string_id = self.intern_string(source.range.clone()); Rc::new(output::HexLiteralStruct { range: source.range.clone(), - text, + string_id, }) } @@ -2706,18 +2707,18 @@ pub trait Builder { &mut self, source: &input::YulHexStringLiteral, ) -> output::HexStringLiteral { - let text = self.unparse_range(source.range.clone()); + let string_id = self.intern_string(source.range.clone()); Rc::new(output::HexStringLiteralStruct { range: source.range.clone(), - text, + string_id, }) } fn build_yul_identifier(&mut self, source: &input::YulIdentifier) -> output::Identifier { - let text = self.unparse_range(source.range.clone()); + let string_id = self.intern_string(source.range.clone()); Rc::new(output::IdentifierStruct { range: source.range.clone(), - text, + string_id, }) } @@ -2725,10 +2726,10 @@ pub trait Builder { &mut self, source: &input::YulStringLiteral, ) -> output::StringLiteral { - let text = self.unparse_range(source.range.clone()); + let string_id = self.intern_string(source.range.clone()); Rc::new(output::StringLiteralStruct { range: source.range.clone(), - text, + string_id, }) } } diff --git a/crates/solidity-v2/outputs/cargo/ir/src/ir/builder/default.rs.jinja2 b/crates/solidity-v2/outputs/cargo/ir/src/ir/builder/default.rs.jinja2 index 986fafbe13..71369f6634 100644 --- a/crates/solidity-v2/outputs/cargo/ir/src/ir/builder/default.rs.jinja2 +++ b/crates/solidity-v2/outputs/cargo/ir/src/ir/builder/default.rs.jinja2 @@ -5,11 +5,12 @@ #![allow(unused_variables)] use std::rc::Rc; +use crate::interner::StringId; use crate::ir::nodes as output; use slang_solidity_v2_cst::structured_cst::nodes as input; pub trait Builder { - fn unparse_range(&self, range: std::ops::Range) -> String; + fn intern_string(&mut self, range: std::ops::Range) -> StringId; // // Sequences @@ -104,10 +105,10 @@ pub trait Builder { match source { {% for variant in collapsed.variants -%} input::{{ parent_type }}::{{ variant.source.name }}(terminal) => { - let text = self.unparse_range(terminal.range.clone()); + let string_id = self.intern_string(terminal.range.clone()); Rc::new(output::{{ collapsed.target.name }}Struct { range: terminal.range.clone(), - text, + string_id, }) } {% endfor -%} @@ -138,10 +139,10 @@ pub trait Builder { {# and new terminals cannot be automatically built #} {% if not terminal.is_new and not terminal.is_unique %} fn build_{{ terminal_type | snake_case }}(&mut self, source: &input::{{ terminal_type }}) -> output::{{ terminal_type }} { - let text = self.unparse_range(source.range.clone()); + let string_id = self.intern_string(source.range.clone()); Rc::new(output::{{ terminal_type }}Struct { range: source.range.clone(), - text, + string_id, }) } {% endif %} @@ -153,10 +154,10 @@ pub trait Builder { {% for source_type, normalized in builder.normalized_terminals %} {% if not normalized.is_unique %} fn build_{{ source_type | snake_case }}(&mut self, source: &input::{{ source_type }}) -> output::{{ normalized.target }} { - let text = self.unparse_range(source.range.clone()); + let string_id = self.intern_string(source.range.clone()); Rc::new(output::{{ normalized.target }}Struct { range: source.range.clone(), - text, + string_id, }) } {% endif %} diff --git a/crates/solidity-v2/outputs/cargo/ir/src/ir/builder/mod.rs b/crates/solidity-v2/outputs/cargo/ir/src/ir/builder/mod.rs index 78716acc27..0c05a98de5 100644 --- a/crates/solidity-v2/outputs/cargo/ir/src/ir/builder/mod.rs +++ b/crates/solidity-v2/outputs/cargo/ir/src/ir/builder/mod.rs @@ -7,23 +7,27 @@ mod default; use default::Builder; use super::Source; +use crate::interner::{Interner, StringId}; use crate::ir::nodes as output; pub fn build_source_unit( source_unit: &input::SourceUnit, source: &impl Source, + interner: &mut Interner, ) -> output::SourceUnit { - let mut builder = CstToIrBuilder { source }; + let mut builder = CstToIrBuilder { source, interner }; builder.build_source_unit(source_unit) } struct CstToIrBuilder<'a, S: Source> { pub source: &'a S, + pub interner: &'a mut Interner, } impl Builder for CstToIrBuilder<'_, S> { - fn unparse_range(&self, range: std::ops::Range) -> String { - self.source.text(range).to_owned() + fn intern_string(&mut self, range: std::ops::Range) -> StringId { + let text = self.source.text(range); + self.interner.intern(text) } // diff --git a/crates/solidity-v2/outputs/cargo/ir/src/ir/nodes.generated.rs b/crates/solidity-v2/outputs/cargo/ir/src/ir/nodes.generated.rs index 21a9742454..2d76709c6d 100644 --- a/crates/solidity-v2/outputs/cargo/ir/src/ir/nodes.generated.rs +++ b/crates/solidity-v2/outputs/cargo/ir/src/ir/nodes.generated.rs @@ -6,6 +6,8 @@ use std::ops::Range; use std::rc::Rc; use std::vec::Vec; +use crate::interner::{Interner, StringId}; + #[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)] #[repr(transparent)] pub struct NodeId(usize); @@ -1805,7 +1807,7 @@ pub type BytesKeyword = Rc; #[derive(Clone, Debug, Eq, PartialEq)] pub struct BytesKeywordStruct { pub range: Range, - pub text: String, + pub string_id: StringId, } impl BytesKeywordStruct { @@ -1813,8 +1815,8 @@ impl BytesKeywordStruct { NodeId(Rc::as_ptr(self) as usize) } - pub fn unparse(&self) -> &str { - &self.text + pub fn unparse<'a>(&self, interner: &'a Interner) -> &'a str { + interner.resolve(self.string_id) } } @@ -1823,7 +1825,7 @@ pub type DecimalLiteral = Rc; #[derive(Clone, Debug, Eq, PartialEq)] pub struct DecimalLiteralStruct { pub range: Range, - pub text: String, + pub string_id: StringId, } impl DecimalLiteralStruct { @@ -1831,8 +1833,8 @@ impl DecimalLiteralStruct { NodeId(Rc::as_ptr(self) as usize) } - pub fn unparse(&self) -> &str { - &self.text + pub fn unparse<'a>(&self, interner: &'a Interner) -> &'a str { + interner.resolve(self.string_id) } } @@ -1841,7 +1843,7 @@ pub type FixedKeyword = Rc; #[derive(Clone, Debug, Eq, PartialEq)] pub struct FixedKeywordStruct { pub range: Range, - pub text: String, + pub string_id: StringId, } impl FixedKeywordStruct { @@ -1849,8 +1851,8 @@ impl FixedKeywordStruct { NodeId(Rc::as_ptr(self) as usize) } - pub fn unparse(&self) -> &str { - &self.text + pub fn unparse<'a>(&self, interner: &'a Interner) -> &'a str { + interner.resolve(self.string_id) } } @@ -1859,7 +1861,7 @@ pub type HexLiteral = Rc; #[derive(Clone, Debug, Eq, PartialEq)] pub struct HexLiteralStruct { pub range: Range, - pub text: String, + pub string_id: StringId, } impl HexLiteralStruct { @@ -1867,8 +1869,8 @@ impl HexLiteralStruct { NodeId(Rc::as_ptr(self) as usize) } - pub fn unparse(&self) -> &str { - &self.text + pub fn unparse<'a>(&self, interner: &'a Interner) -> &'a str { + interner.resolve(self.string_id) } } @@ -1877,7 +1879,7 @@ pub type HexStringLiteral = Rc; #[derive(Clone, Debug, Eq, PartialEq)] pub struct HexStringLiteralStruct { pub range: Range, - pub text: String, + pub string_id: StringId, } impl HexStringLiteralStruct { @@ -1885,8 +1887,8 @@ impl HexStringLiteralStruct { NodeId(Rc::as_ptr(self) as usize) } - pub fn unparse(&self) -> &str { - &self.text + pub fn unparse<'a>(&self, interner: &'a Interner) -> &'a str { + interner.resolve(self.string_id) } } @@ -1895,7 +1897,7 @@ pub type Identifier = Rc; #[derive(Clone, Debug, Eq, PartialEq)] pub struct IdentifierStruct { pub range: Range, - pub text: String, + pub string_id: StringId, } impl IdentifierStruct { @@ -1903,8 +1905,8 @@ impl IdentifierStruct { NodeId(Rc::as_ptr(self) as usize) } - pub fn unparse(&self) -> &str { - &self.text + pub fn unparse<'a>(&self, interner: &'a Interner) -> &'a str { + interner.resolve(self.string_id) } } @@ -1913,7 +1915,7 @@ pub type IntKeyword = Rc; #[derive(Clone, Debug, Eq, PartialEq)] pub struct IntKeywordStruct { pub range: Range, - pub text: String, + pub string_id: StringId, } impl IntKeywordStruct { @@ -1921,8 +1923,8 @@ impl IntKeywordStruct { NodeId(Rc::as_ptr(self) as usize) } - pub fn unparse(&self) -> &str { - &self.text + pub fn unparse<'a>(&self, interner: &'a Interner) -> &'a str { + interner.resolve(self.string_id) } } @@ -1931,7 +1933,7 @@ pub type StringLiteral = Rc; #[derive(Clone, Debug, Eq, PartialEq)] pub struct StringLiteralStruct { pub range: Range, - pub text: String, + pub string_id: StringId, } impl StringLiteralStruct { @@ -1939,8 +1941,8 @@ impl StringLiteralStruct { NodeId(Rc::as_ptr(self) as usize) } - pub fn unparse(&self) -> &str { - &self.text + pub fn unparse<'a>(&self, interner: &'a Interner) -> &'a str { + interner.resolve(self.string_id) } } @@ -1949,7 +1951,7 @@ pub type UfixedKeyword = Rc; #[derive(Clone, Debug, Eq, PartialEq)] pub struct UfixedKeywordStruct { pub range: Range, - pub text: String, + pub string_id: StringId, } impl UfixedKeywordStruct { @@ -1957,8 +1959,8 @@ impl UfixedKeywordStruct { NodeId(Rc::as_ptr(self) as usize) } - pub fn unparse(&self) -> &str { - &self.text + pub fn unparse<'a>(&self, interner: &'a Interner) -> &'a str { + interner.resolve(self.string_id) } } @@ -1967,7 +1969,7 @@ pub type UintKeyword = Rc; #[derive(Clone, Debug, Eq, PartialEq)] pub struct UintKeywordStruct { pub range: Range, - pub text: String, + pub string_id: StringId, } impl UintKeywordStruct { @@ -1975,8 +1977,8 @@ impl UintKeywordStruct { NodeId(Rc::as_ptr(self) as usize) } - pub fn unparse(&self) -> &str { - &self.text + pub fn unparse<'a>(&self, interner: &'a Interner) -> &'a str { + interner.resolve(self.string_id) } } @@ -1985,7 +1987,7 @@ pub type UnicodeStringLiteral = Rc; #[derive(Clone, Debug, Eq, PartialEq)] pub struct UnicodeStringLiteralStruct { pub range: Range, - pub text: String, + pub string_id: StringId, } impl UnicodeStringLiteralStruct { @@ -1993,8 +1995,8 @@ impl UnicodeStringLiteralStruct { NodeId(Rc::as_ptr(self) as usize) } - pub fn unparse(&self) -> &str { - &self.text + pub fn unparse<'a>(&self, interner: &'a Interner) -> &'a str { + interner.resolve(self.string_id) } } @@ -2003,7 +2005,7 @@ pub type VersionSpecifier = Rc; #[derive(Clone, Debug, Eq, PartialEq)] pub struct VersionSpecifierStruct { pub range: Range, - pub text: String, + pub string_id: StringId, } impl VersionSpecifierStruct { @@ -2011,7 +2013,7 @@ impl VersionSpecifierStruct { NodeId(Rc::as_ptr(self) as usize) } - pub fn unparse(&self) -> &str { - &self.text + pub fn unparse<'a>(&self, interner: &'a Interner) -> &'a str { + interner.resolve(self.string_id) } } diff --git a/crates/solidity-v2/outputs/cargo/ir/src/ir/nodes.rs.jinja2 b/crates/solidity-v2/outputs/cargo/ir/src/ir/nodes.rs.jinja2 index 49186bb46a..f6f74c8503 100644 --- a/crates/solidity-v2/outputs/cargo/ir/src/ir/nodes.rs.jinja2 +++ b/crates/solidity-v2/outputs/cargo/ir/src/ir/nodes.rs.jinja2 @@ -5,6 +5,8 @@ use std::rc::Rc; use std::ops::Range; use std::vec::Vec; +use crate::interner::{Interner, StringId}; + #[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)] #[repr(transparent)] pub struct NodeId(usize); @@ -94,7 +96,7 @@ pub struct NodeId(usize); #[derive(Clone, Debug, Eq, PartialEq)] pub struct {{ terminal_type }}Struct { pub range: Range, - pub text: String, + pub string_id: StringId, } impl {{ terminal_type }}Struct { @@ -102,8 +104,8 @@ pub struct NodeId(usize); NodeId(Rc::as_ptr(self) as usize) } - pub fn unparse(&self) -> &str { - &self.text + pub fn unparse<'a>(&self, interner: &'a Interner) -> &'a str { + interner.resolve(self.string_id) } } {% endif %} diff --git a/crates/solidity-v2/outputs/cargo/ir/src/lib.rs b/crates/solidity-v2/outputs/cargo/ir/src/lib.rs index 76a9f963df..d9fbc295e3 100644 --- a/crates/solidity-v2/outputs/cargo/ir/src/lib.rs +++ b/crates/solidity-v2/outputs/cargo/ir/src/lib.rs @@ -1,3 +1,4 @@ +pub mod interner; pub mod ir; #[cfg(test)] diff --git a/crates/solidity-v2/outputs/cargo/ir/src/tests/builder.rs b/crates/solidity-v2/outputs/cargo/ir/src/tests/builder.rs new file mode 100644 index 0000000000..dcc4078dd0 --- /dev/null +++ b/crates/solidity-v2/outputs/cargo/ir/src/tests/builder.rs @@ -0,0 +1,121 @@ +use anyhow::{anyhow, Result}; +use slang_solidity_v2_common::versions::LanguageVersion; +use slang_solidity_v2_parser::Parser; + +use crate::interner::Interner; +use crate::ir; + +#[test] +fn test_build_ir_tree() -> Result<()> { + const CONTENTS: &str = r###" +// SPDX-License-Identifier: UNLICENSED +pragma solidity >= 0.8.17; + +contract MyContract { + address owner; + constructor() { + owner = msg.sender; + } + function test() view public returns (bool) { + return owner == msg.sender; + } +} + "###; + + let version = LanguageVersion::V0_8_30; + let source_unit_cst = + Parser::parse(CONTENTS, version).map_err(|message| anyhow!(format!("{message:?}")))?; + let mut interner = Interner::new(); + let source_unit = ir::build(&source_unit_cst, &CONTENTS, &mut interner); + + assert_eq!(2, source_unit.members.len()); + assert!(matches!( + source_unit.members[0], + ir::SourceUnitMember::PragmaDirective(_) + )); + assert!(matches!( + source_unit.members[1], + ir::SourceUnitMember::ContractDefinition(_) + )); + + // MyContract contract + let ir::SourceUnitMember::ContractDefinition(ref contract) = source_unit.members[1] else { + panic!("Expected ContractDefinition"); + }; + assert_eq!("MyContract", contract.name.unparse(&interner)); + assert_eq!(3, contract.members.len()); + + // MyContract.owner state variable + let ir::ContractMember::StateVariableDefinition(ref state_var) = contract.members[0] else { + panic!("Expected StateVariableDefinition"); + }; + assert_eq!("owner", state_var.name.unparse(&interner)); + + // MyContract constructor + let ir::ContractMember::FunctionDefinition(ref constructor) = contract.members[1] else { + panic!("Expected FunctionDefinition for constructor"); + }; + assert_eq!(ir::FunctionKind::Constructor, constructor.kind); + assert!(constructor.body.is_some()); + let constructor_body = constructor.body.as_ref().unwrap(); + assert_eq!(1, constructor_body.statements.len()); + + // MyContract.test() function + let ir::ContractMember::FunctionDefinition(ref function) = contract.members[2] else { + panic!("Expected FunctionDefinition"); + }; + assert_eq!(ir::FunctionKind::Regular, function.kind); + let function_name = function.name.as_ref().expect("function has a name"); + assert_eq!("test", function_name.unparse(&interner)); + assert_eq!(ir::FunctionVisibility::Public, function.visibility); + assert_eq!(ir::FunctionMutability::View, function.mutability); + assert_eq!(0, function.parameters.len()); + assert!(function.returns.is_some()); + assert_eq!(1, function.returns.as_ref().unwrap().len()); + assert!(function.body.is_some()); + let function_body = function.body.as_ref().unwrap(); + assert_eq!(1, function_body.statements.len()); + + Ok(()) +} + +#[test] +fn test_build_ir_contract_inheritance_and_storage_layout() -> Result<()> { + const CONTENTS: &str = r###" +contract Base {} +contract Test is Base layout at 0 {} + "###; + + let version = LanguageVersion::V0_8_30; + let source_unit_cst = + Parser::parse(CONTENTS, version).map_err(|message| anyhow!(format!("{message:?}")))?; + let mut interner = Interner::new(); + let source_unit = ir::build(&source_unit_cst, &CONTENTS, &mut interner); + + assert_eq!(2, source_unit.members.len()); + + let ir::SourceUnitMember::ContractDefinition(base_contract) = &source_unit.members[0] else { + panic!("Expected ContractDefinition"); + }; + assert_eq!("Base", base_contract.name.unparse(&interner)); + assert!(base_contract.inheritance_types.is_empty()); + assert!(base_contract.storage_layout.is_none()); + + let ir::SourceUnitMember::ContractDefinition(test_contract) = &source_unit.members[1] else { + panic!("Expected ContractDefinition"); + }; + assert_eq!("Test", test_contract.name.unparse(&interner)); + assert_eq!(1, test_contract.inheritance_types.len()); + assert_eq!( + "Base", + test_contract.inheritance_types[0] + .type_name + .iter() + .map(|node| node.unparse(&interner)) + .collect::>() + .join(".") + ); + assert!(test_contract.storage_layout.is_some()); + + Ok(()) +} diff --git a/crates/solidity-v2/outputs/cargo/ir/src/tests/mod.rs b/crates/solidity-v2/outputs/cargo/ir/src/tests/mod.rs index 6520b880b4..bed7f6b223 100644 --- a/crates/solidity-v2/outputs/cargo/ir/src/tests/mod.rs +++ b/crates/solidity-v2/outputs/cargo/ir/src/tests/mod.rs @@ -1,45 +1,2 @@ -use anyhow::{anyhow, Result}; -use slang_solidity_v2_common::versions::LanguageVersion; -use slang_solidity_v2_parser::Parser; - -use crate::ir; - -#[test] -fn test_build_ir_tree() -> Result<()> { - const CONTENTS: &str = r###" -contract Base {} -contract Test is Base layout at 0 {} - "###; - - let version = LanguageVersion::V0_8_30; - let source_unit_cst = - Parser::parse(CONTENTS, version).map_err(|message| anyhow!(format!("{message:?}")))?; - let source_unit = ir::build(&source_unit_cst, &CONTENTS); - - assert_eq!(2, source_unit.members.len()); - - let ir::SourceUnitMember::ContractDefinition(base_contract) = &source_unit.members[0] else { - panic!("Expected ContractDefinition"); - }; - assert_eq!("Base", base_contract.name.unparse()); - assert!(base_contract.inheritance_types.is_empty()); - assert!(base_contract.storage_layout.is_none()); - - let ir::SourceUnitMember::ContractDefinition(test_contract) = &source_unit.members[1] else { - panic!("Expected ContractDefinition"); - }; - assert_eq!("Test", test_contract.name.unparse()); - assert_eq!(1, test_contract.inheritance_types.len()); - assert_eq!( - "Base", - test_contract.inheritance_types[0] - .type_name - .iter() - .map(|node| node.unparse()) - .collect::>() - .join(".") - ); - assert!(test_contract.storage_layout.is_some()); - - Ok(()) -} +mod builder; +mod visitor; diff --git a/crates/solidity-v2/outputs/cargo/ir/src/tests/visitor.rs b/crates/solidity-v2/outputs/cargo/ir/src/tests/visitor.rs new file mode 100644 index 0000000000..3a0e006f3c --- /dev/null +++ b/crates/solidity-v2/outputs/cargo/ir/src/tests/visitor.rs @@ -0,0 +1,106 @@ +use anyhow::{anyhow, Result}; +use slang_solidity_v2_common::versions::LanguageVersion; +use slang_solidity_v2_parser::Parser; + +use crate::interner::Interner; +use crate::ir; + +#[derive(Default)] +struct CounterVisitor { + contracts: usize, + constructors: usize, + functions: usize, + modifiers: usize, + state_vars: usize, + + enter_contracts: bool, +} + +impl CounterVisitor { + fn new(enter_contracts: bool) -> Self { + Self { + enter_contracts, + ..Self::default() + } + } +} + +impl ir::visitor::Visitor for CounterVisitor { + fn enter_contract_definition(&mut self, _node: &ir::ContractDefinition) -> bool { + self.contracts += 1; + self.enter_contracts + } + fn leave_function_definition(&mut self, node: &ir::FunctionDefinition) { + match node.kind { + ir::FunctionKind::Constructor => self.constructors += 1, + ir::FunctionKind::Modifier => self.modifiers += 1, + _ => self.functions += 1, + } + } + fn leave_state_variable_definition(&mut self, _node: &ir::StateVariableDefinition) { + self.state_vars += 1; + } +} + +#[test] +fn test_ast_visitor() -> Result<()> { + const CONTENTS: &str = r###" +// SPDX-License-Identifier: UNLICENSED +pragma solidity >= 0.8.17; + +function add(uint a, uint b) pure returns (uint) { + return a + b; +} + +abstract contract Ownable { + address _owner; + constructor() { + _owner = msg.sender; + } + modifier onlyOwner() { + require(_owner == msg.sender); + _; + } +} + +contract Counter is Ownable { + uint _count; + constructor(uint initial_value) { + _count = initial_value; + } + function count() view public returns (uint) { + return _count; + } + function increment(uint delta) public onlyOwner returns (uint) { + _count = add(_count, delta); + return _count; + } +} + "###; + + let version = LanguageVersion::V0_8_30; + let source_unit_cst = + Parser::parse(CONTENTS, version).map_err(|message| anyhow!(format!("{message:?}")))?; + let mut interner = Interner::new(); + let source_unit = ir::build(&source_unit_cst, &CONTENTS, &mut interner); + + let mut visitor = CounterVisitor::new(true); + ir::visitor::accept_source_unit(&source_unit, &mut visitor); + + assert_eq!(2, visitor.contracts); + assert_eq!(2, visitor.constructors); + assert_eq!(1, visitor.modifiers); + assert_eq!(2, visitor.state_vars); + assert_eq!(3, visitor.functions); + + let mut shallow_visitor = CounterVisitor::new(false); + ir::visitor::accept_source_unit(&source_unit, &mut shallow_visitor); + + assert_eq!(2, shallow_visitor.contracts); + assert_eq!(0, shallow_visitor.constructors); + assert_eq!(0, shallow_visitor.modifiers); + assert_eq!(0, shallow_visitor.state_vars); + assert_eq!(1, shallow_visitor.functions); + + Ok(()) +} diff --git a/crates/solidity-v2/outputs/cargo/semantic/src/binder/definitions.rs b/crates/solidity-v2/outputs/cargo/semantic/src/binder/definitions.rs index 38008cea11..8118cf3e43 100644 --- a/crates/solidity-v2/outputs/cargo/semantic/src/binder/definitions.rs +++ b/crates/solidity-v2/outputs/cargo/semantic/src/binder/definitions.rs @@ -1,8 +1,10 @@ use std::rc::Rc; +use slang_solidity_v2_ir::interner::StringId; use slang_solidity_v2_ir::ir::{self, NodeId}; use super::ScopeId; +use crate::context::FileId; use crate::types::TypeId; ////////////////////////////////////////////////////////////////////////////// @@ -37,13 +39,13 @@ pub enum Definition { #[derive(Debug)] pub struct ConstantDefinition { - pub(crate) ir_node: ir::ConstantDefinition, + pub ir_node: ir::ConstantDefinition, pub scope_id: ScopeId, } #[derive(Debug)] pub struct ContractDefinition { - pub(crate) ir_node: ir::ContractDefinition, + pub ir_node: ir::ContractDefinition, pub bases: Option>, pub constructor_parameters_scope_id: Option, pub base_slot: Option, @@ -51,113 +53,113 @@ pub struct ContractDefinition { #[derive(Debug)] pub struct EnumDefinition { - pub(crate) ir_node: ir::EnumDefinition, + pub ir_node: ir::EnumDefinition, } #[derive(Debug)] pub struct EnumMemberDefinition { - pub(crate) ir_node: ir::Identifier, + pub ir_node: ir::Identifier, } #[derive(Debug)] pub struct ErrorDefinition { - pub(crate) ir_node: ir::ErrorDefinition, + pub ir_node: ir::ErrorDefinition, pub parameters_scope_id: ScopeId, } #[derive(Debug)] pub struct EventDefinition { - pub(crate) ir_node: ir::EventDefinition, + pub ir_node: ir::EventDefinition, pub parameters_scope_id: ScopeId, } #[derive(Debug)] pub struct FunctionDefinition { - pub(crate) ir_node: ir::FunctionDefinition, + pub ir_node: ir::FunctionDefinition, pub parameters_scope_id: ScopeId, pub visibility: ir::FunctionVisibility, } #[derive(Debug)] pub struct ImportDefinition { - pub(crate) ir_node: ir::PathImport, - pub resolved_file_id: Option, + pub ir_node: ir::PathImport, + pub resolved_file_id: Option, } #[derive(Debug)] pub struct ImportedSymbolDefinition { - pub(crate) ir_node: ir::ImportDeconstructionSymbol, - pub symbol: String, - pub resolved_file_id: Option, + pub ir_node: ir::ImportDeconstructionSymbol, + pub symbol: StringId, + pub resolved_file_id: Option, } #[derive(Debug)] pub struct InterfaceDefinition { - pub(crate) ir_node: ir::InterfaceDefinition, + pub ir_node: ir::InterfaceDefinition, pub bases: Option>, } #[derive(Debug)] pub struct LibraryDefinition { - pub(crate) ir_node: ir::LibraryDefinition, + pub ir_node: ir::LibraryDefinition, } #[derive(Debug)] pub struct ModifierDefinition { - pub(crate) ir_node: ir::FunctionDefinition, + pub ir_node: ir::FunctionDefinition, } #[derive(Debug)] pub struct ParameterDefinition { - pub(crate) ir_node: ir::Parameter, + pub ir_node: ir::Parameter, } #[derive(Debug)] pub struct StateVariableDefinition { - pub(crate) ir_node: ir::StateVariableDefinition, + pub ir_node: ir::StateVariableDefinition, pub getter_type_id: Option, pub visibility: ir::StateVariableVisibility, } #[derive(Debug)] pub struct StructDefinition { - pub(crate) ir_node: ir::StructDefinition, + pub ir_node: ir::StructDefinition, } #[derive(Debug)] pub struct StructMemberDefinition { - pub(crate) ir_node: ir::StructMember, + pub ir_node: ir::StructMember, } #[derive(Debug)] pub struct TypeParameterDefinition { - pub(crate) ir_node: ir::Parameter, + pub ir_node: ir::Parameter, } #[derive(Debug)] pub struct UserDefinedValueTypeDefinition { - pub(crate) ir_node: ir::UserDefinedValueTypeDefinition, + pub ir_node: ir::UserDefinedValueTypeDefinition, pub target_type_id: Option, } #[derive(Debug)] pub struct VariableDefinition { - pub(crate) ir_node: ir::VariableDeclaration, + pub ir_node: ir::VariableDeclaration, } #[derive(Debug)] pub struct YulFunctionDefinition { - pub(crate) ir_node: ir::YulFunctionDefinition, + pub ir_node: ir::YulFunctionDefinition, } #[derive(Debug)] pub struct YulParameterDefinition { - pub(crate) ir_node: ir::Identifier, + pub ir_node: ir::Identifier, } #[derive(Debug)] pub struct YulVariableDefinition { - pub(crate) ir_node: ir::Identifier, + pub ir_node: ir::Identifier, } impl Definition { @@ -342,7 +344,7 @@ impl Definition { }) } - pub(crate) fn new_import(ir_node: &ir::PathImport, resolved_file_id: Option) -> Self { + pub(crate) fn new_import(ir_node: &ir::PathImport, resolved_file_id: Option) -> Self { assert!( ir_node.alias.is_some(), "Definition can only be created for aliased imports" @@ -356,8 +358,8 @@ impl Definition { pub(crate) fn new_imported_symbol( ir_node: &ir::ImportDeconstructionSymbol, - symbol: String, - resolved_file_id: Option, + symbol: StringId, + resolved_file_id: Option, ) -> Self { Self::ImportedSymbol(ImportedSymbolDefinition { ir_node: Rc::clone(ir_node), diff --git a/crates/solidity-v2/outputs/cargo/semantic/src/binder/mod.rs b/crates/solidity-v2/outputs/cargo/semantic/src/binder/mod.rs index 044581ac80..0dfa140d5a 100644 --- a/crates/solidity-v2/outputs/cargo/semantic/src/binder/mod.rs +++ b/crates/solidity-v2/outputs/cargo/semantic/src/binder/mod.rs @@ -1,9 +1,11 @@ use std::collections::{HashMap, HashSet, VecDeque}; +use slang_solidity_v2_ir::interner::StringId; use slang_solidity_v2_ir::ir::NodeId; use super::built_ins::BuiltIn; use super::types::{Type, TypeId}; +use crate::context::FileId; mod definitions; mod references; @@ -73,7 +75,7 @@ pub enum Typing { } impl Typing { - pub(crate) fn as_type_id(&self) -> Option { + pub fn as_type_id(&self) -> Option { match self { Self::Resolved(type_id) => Some(*type_id), _ => None, @@ -91,7 +93,7 @@ pub struct Binder { /// Scopes (set of definitions contained and relationship to other scopes), indexed by `NodeId` scopes_by_node_id: HashMap, /// Index of root `FileScope`s for all files in the `CompilationUnit` - scopes_by_file_id: HashMap, + scopes_by_file_id: HashMap, /// `UsingDirective` objects registered globally (contract level directives /// are stored in the corresponding `ContractScope`) global_using_directives: Vec, @@ -141,21 +143,17 @@ impl Binder { self.scopes_by_node_id.get(&node_id).copied() } - pub(crate) fn scope_id_for_file_id(&self, file_id: &str) -> Option { - self.scopes_by_file_id.get(file_id).copied() + pub(crate) fn scope_id_for_file_id(&self, file_id: FileId) -> Option { + self.scopes_by_file_id.get(&file_id).copied() } pub(crate) fn insert_scope(&mut self, scope: Scope) -> ScopeId { let scope_id = ScopeId(self.scopes.len()); if let Scope::File(file_scope) = &scope { - let file_id = &file_scope.file_id; - if self - .scopes_by_file_id - .insert(file_id.clone(), scope_id) - .is_some() - { - unreachable!("attempt to insert duplicate file scope for {file_id}"); + let file_id = file_scope.file_id; + if self.scopes_by_file_id.insert(file_id, scope_id).is_some() { + unreachable!("attempt to insert duplicate file scope for {file_id:?}"); } } @@ -184,7 +182,7 @@ impl Binder { pub(crate) fn insert_definition_in_scope(&mut self, definition: Definition, scope_id: ScopeId) { let scope = self.get_scope_mut(scope_id); - let symbol = definition.identifier().unparse().to_string(); + let symbol = definition.identifier().string_id; scope.insert_definition(symbol, definition.node_id()); self.insert_definition_no_scope(definition); } @@ -217,7 +215,7 @@ impl Binder { } } - pub(crate) fn get_linearised_bases(&self, node_id: NodeId) -> Option<&Vec> { + pub fn get_linearised_bases(&self, node_id: NodeId) -> Option<&Vec> { self.linearisations.get(&node_id) } @@ -330,9 +328,9 @@ impl Binder { // File scope resolution context - fn get_file_scope(&self, file_id: &str) -> &FileScope { + fn get_file_scope(&self, file_id: FileId) -> &FileScope { self.scopes_by_file_id - .get(file_id) + .get(&file_id) .and_then(|scope_id| self.scopes.get(scope_id.0)) .and_then(|scope| match scope { Scope::File(file_scope) => Some(file_scope), @@ -344,20 +342,20 @@ impl Binder { // Resolving a symbol in a file scope is special because of default imports. // We want to find *all* definitions with the given symbol reachable from // the file. - fn resolve_in_file_scope(&self, file_id: &str, symbol: &str) -> Resolution { + fn resolve_in_file_scope(&self, file_id: FileId, symbol: StringId) -> Resolution { let mut found_definitions = Vec::new(); let mut visited_files = HashSet::new(); let mut files_to_search = VecDeque::new(); - files_to_search.push_back(file_id.to_owned()); + files_to_search.push_back(file_id); while let Some(file_id) = files_to_search.pop_front() { - let file_scope = self.get_file_scope(&file_id); + let file_scope = self.get_file_scope(file_id); if !visited_files.insert(file_id) { continue; } found_definitions.extend(file_scope.lookup_symbol(symbol)); - files_to_search.extend(file_scope.imported_files.iter().cloned()); + files_to_search.extend(file_scope.imported_files.iter().copied()); } Resolution::from(found_definitions) @@ -366,7 +364,7 @@ impl Binder { fn resolve_in_contract_scope_internal( &self, contract_scope: &ContractScope, - symbol: &str, + symbol: StringId, options: ResolveOptions, ) -> Resolution { // Search for the symbol in the linearised bases *in-order*. @@ -399,7 +397,7 @@ impl Binder { else { unreachable!("expected the scope of a base contract to be a ContractScope"); }; - let Some(definitions) = base_contract_scope.definitions.get(symbol) else { + let Some(definitions) = base_contract_scope.definitions.get(&symbol) else { continue; }; for definition_id in definitions { @@ -428,7 +426,7 @@ impl Binder { } } Resolution::from(results) - } else if let Some(definitions) = contract_scope.definitions.get(symbol) { + } else if let Some(definitions) = contract_scope.definitions.get(&symbol) { // This case shouldn't happen for valid Solidity, as all // contracts should have a proper linearisation Resolution::from(definitions.clone()) @@ -440,10 +438,10 @@ impl Binder { // This function attempts to lexically resolve `symbol` starting from the // given scope. Certain scopes can delegate to their "parent" scopes if // the symbol is not found there. - pub(crate) fn resolve_in_scope(&self, scope_id: ScopeId, symbol: &str) -> Resolution { + pub(crate) fn resolve_in_scope(&self, scope_id: ScopeId, symbol: StringId) -> Resolution { let scope = self.get_scope_by_id(scope_id); match scope { - Scope::Block(block_scope) => block_scope.definitions.get(symbol).copied().map_or_else( + Scope::Block(block_scope) => block_scope.definitions.get(&symbol).copied().map_or_else( || self.resolve_in_scope(block_scope.parent_scope_id, symbol), Resolution::Definition, ), @@ -458,35 +456,37 @@ impl Binder { self.resolve_in_scope(contract_scope.file_scope_id, symbol) }) } - Scope::Enum(enum_scope) => enum_scope.definitions.get(symbol).into(), - Scope::File(file_scope) => self.resolve_in_file_scope(&file_scope.file_id, symbol), + Scope::Enum(enum_scope) => enum_scope.definitions.get(&symbol).into(), + Scope::File(file_scope) => self.resolve_in_file_scope(file_scope.file_id, symbol), Scope::Function(function_scope) => function_scope .definitions - .get(symbol) + .get(&symbol) .copied() .map_or_else( || self.resolve_in_scope(function_scope.parameters_scope_id, symbol), Resolution::Definition, ) .or_else(|| self.resolve_in_scope(function_scope.parent_scope_id, symbol)), - Scope::Modifier(modifier_scope) => { - modifier_scope.definitions.get(symbol).copied().map_or_else( + Scope::Modifier(modifier_scope) => modifier_scope + .definitions + .get(&symbol) + .copied() + .map_or_else( || self.resolve_in_scope(modifier_scope.parent_scope_id, symbol), Resolution::Definition, - ) - } + ), Scope::Parameters(parameters_scope) => { parameters_scope.lookup_definition(symbol).into() } - Scope::Struct(struct_scope) => struct_scope.definitions.get(symbol).into(), + Scope::Struct(struct_scope) => struct_scope.definitions.get(&symbol).into(), Scope::Using(using_scope) => using_scope .symbols - .get(symbol) + .get(&symbol) .cloned() .map_or(Resolution::Unresolved, Resolution::from), Scope::YulBlock(yul_block_scope) => yul_block_scope .definitions - .get(symbol) + .get(&symbol) .copied() .map_or_else( || self.resolve_in_scope(yul_block_scope.parent_scope_id, symbol), @@ -497,7 +497,7 @@ impl Binder { // cannot resolve to a Yul variable defined in a parent block yul_function_scope .definitions - .get(symbol) + .get(&symbol) .copied() .map_or_else( || self.resolve_in_scope(yul_function_scope.parent_scope_id, symbol), @@ -540,12 +540,12 @@ impl Binder { let Some(scope_id) = imported_symbol .resolved_file_id .as_ref() - .and_then(|file_id| self.scope_id_for_file_id(file_id)) + .and_then(|file_id| self.scope_id_for_file_id(*file_id)) else { continue; }; working_set.extend( - self.resolve_in_scope(scope_id, &imported_symbol.symbol) + self.resolve_in_scope(scope_id, imported_symbol.symbol) .get_definition_ids(), ); } else { @@ -565,7 +565,7 @@ impl Binder { pub(crate) fn resolve_in_scope_as_namespace( &self, scope_id: ScopeId, - symbol: &str, + symbol: StringId, ) -> Resolution { let scope = self.get_scope_by_id(scope_id); match scope { @@ -574,11 +574,11 @@ impl Binder { symbol, ResolveOptions::Qualified, ), - Scope::Enum(enum_scope) => enum_scope.definitions.get(symbol).into(), - Scope::Struct(struct_scope) => struct_scope.definitions.get(symbol).into(), + Scope::Enum(enum_scope) => enum_scope.definitions.get(&symbol).into(), + Scope::Struct(struct_scope) => struct_scope.definitions.get(&symbol).into(), Scope::Using(using_scope) => using_scope .symbols - .get(symbol) + .get(&symbol) .cloned() .map_or(Resolution::Unresolved, Resolution::from), Scope::Parameters(parameters_scope) => { @@ -597,7 +597,7 @@ impl Binder { pub(crate) fn resolve_in_contract_scope( &self, scope_id: ScopeId, - symbol: &str, + symbol: StringId, options: ResolveOptions, ) -> Resolution { let scope = self.get_scope_by_id(scope_id); diff --git a/crates/solidity-v2/outputs/cargo/semantic/src/binder/scopes.rs b/crates/solidity-v2/outputs/cargo/semantic/src/binder/scopes.rs index 1dc304cdfa..d8bdd52253 100644 --- a/crates/solidity-v2/outputs/cargo/semantic/src/binder/scopes.rs +++ b/crates/solidity-v2/outputs/cargo/semantic/src/binder/scopes.rs @@ -1,8 +1,10 @@ use std::collections::{HashMap, HashSet}; +use slang_solidity_v2_ir::interner::StringId; use slang_solidity_v2_ir::ir::{self, NodeId}; use super::ScopeId; +use crate::context::FileId; use crate::types::TypeId; ////////////////////////////////////////////////////////////////////////////// @@ -25,26 +27,26 @@ pub(crate) enum Scope { pub(crate) struct BlockScope { pub(crate) node_id: NodeId, pub(crate) parent_scope_id: ScopeId, - pub(crate) definitions: HashMap, + pub(crate) definitions: HashMap, } pub(crate) struct ContractScope { pub(crate) node_id: NodeId, pub(crate) file_scope_id: ScopeId, - pub(crate) definitions: HashMap>, + pub(crate) definitions: HashMap>, pub(crate) using_directives: Vec, } pub(crate) struct EnumScope { pub(crate) node_id: NodeId, - pub(crate) definitions: HashMap, + pub(crate) definitions: HashMap, } pub(crate) struct FileScope { pub(crate) node_id: NodeId, - pub(crate) file_id: String, - pub(crate) definitions: HashMap>, - pub(crate) imported_files: HashSet, + pub(crate) file_id: FileId, + pub(crate) definitions: HashMap>, + pub(crate) imported_files: HashSet, pub(crate) using_directives: Vec, } @@ -52,7 +54,7 @@ pub(crate) struct FunctionScope { pub(crate) node_id: NodeId, pub(crate) parent_scope_id: ScopeId, pub(crate) parameters_scope_id: ScopeId, - pub(crate) definitions: HashMap, + pub(crate) definitions: HashMap, } // TODO: this is similar to a function scope, but it doesn't have a separate @@ -64,14 +66,14 @@ pub(crate) struct FunctionScope { pub(crate) struct ModifierScope { pub(crate) node_id: NodeId, pub(crate) parent_scope_id: ScopeId, - pub(crate) definitions: HashMap, + pub(crate) definitions: HashMap, } /// This is stored in a vector in the `ParametersScope` below preserving order /// for positional arguments and used by the binder, both to resolve named /// arguments, and disambiguate overloads of functions and events. pub(crate) struct ParameterDefinition { - pub(crate) name: Option, + pub(crate) name: Option, pub(crate) node_id: NodeId, /// The type of the parameter, or `None` if it's not yet computed or cannot /// be computed. For some parameter containers (eg. errors) it's never @@ -85,24 +87,24 @@ pub(crate) struct ParametersScope { pub(crate) struct StructScope { pub(crate) node_id: NodeId, - pub(crate) definitions: HashMap, + pub(crate) definitions: HashMap, } pub(crate) struct UsingScope { pub(crate) node_id: NodeId, - pub(crate) symbols: HashMap>, + pub(crate) symbols: HashMap>, } pub(crate) struct YulBlockScope { pub(crate) node_id: NodeId, pub(crate) parent_scope_id: ScopeId, - pub(crate) definitions: HashMap, + pub(crate) definitions: HashMap, } pub(crate) struct YulFunctionScope { pub(crate) node_id: NodeId, pub(crate) parent_scope_id: ScopeId, - pub(crate) definitions: HashMap, + pub(crate) definitions: HashMap, } ////////////////////////////////////////////////////////////////////////////// @@ -125,7 +127,7 @@ impl Scope { } } - pub(crate) fn insert_definition(&mut self, symbol: String, node_id: NodeId) { + pub(crate) fn insert_definition(&mut self, symbol: StringId, node_id: NodeId) { match self { Self::Block(block_scope) => block_scope.insert_definition(symbol, node_id), Self::Contract(contract_scope) => contract_scope.insert_definition(symbol, node_id), @@ -165,7 +167,7 @@ impl Scope { Self::Enum(EnumScope::new(node_id)) } - pub(crate) fn new_file(node_id: NodeId, file_id: &str) -> Self { + pub(crate) fn new_file(node_id: NodeId, file_id: FileId) -> Self { Self::File(FileScope::new(node_id, file_id)) } @@ -189,7 +191,7 @@ impl Scope { Self::Struct(StructScope::new(node_id)) } - pub(crate) fn new_using(node_id: NodeId, symbols: HashMap>) -> Self { + pub(crate) fn new_using(node_id: NodeId, symbols: HashMap>) -> Self { Self::Using(UsingScope::new(node_id, symbols)) } @@ -211,7 +213,7 @@ impl BlockScope { } } - pub(crate) fn insert_definition(&mut self, symbol: String, node_id: NodeId) { + pub(crate) fn insert_definition(&mut self, symbol: StringId, node_id: NodeId) { self.definitions.insert(symbol, node_id); } } @@ -226,7 +228,7 @@ impl ContractScope { } } - pub(crate) fn insert_definition(&mut self, symbol: String, node_id: NodeId) { + pub(crate) fn insert_definition(&mut self, symbol: StringId, node_id: NodeId) { if let Some(definitions) = self.definitions.get_mut(&symbol) { definitions.push(node_id); } else { @@ -243,23 +245,23 @@ impl EnumScope { } } - pub(crate) fn insert_definition(&mut self, symbol: String, node_id: NodeId) { + pub(crate) fn insert_definition(&mut self, symbol: StringId, node_id: NodeId) { self.definitions.insert(symbol, node_id); } } impl FileScope { - fn new(node_id: NodeId, file_id: &str) -> Self { + fn new(node_id: NodeId, file_id: FileId) -> Self { Self { node_id, - file_id: file_id.to_string(), + file_id, definitions: HashMap::new(), imported_files: HashSet::new(), using_directives: Vec::new(), } } - pub(crate) fn insert_definition(&mut self, symbol: String, node_id: NodeId) { + pub(crate) fn insert_definition(&mut self, symbol: StringId, node_id: NodeId) { if let Some(definitions) = self.definitions.get_mut(&symbol) { definitions.push(node_id); } else { @@ -267,12 +269,12 @@ impl FileScope { } } - pub(crate) fn add_imported_file(&mut self, file_id: String) { + pub(crate) fn add_imported_file(&mut self, file_id: FileId) { self.imported_files.insert(file_id); } - pub(super) fn lookup_symbol<'a>(&'a self, symbol: &str) -> impl Iterator + 'a { - match self.definitions.get(symbol) { + pub(super) fn lookup_symbol(&self, symbol: StringId) -> impl Iterator + '_ { + match self.definitions.get(&symbol) { Some(defs) => OptionIter::Some(defs.iter().copied()), None => OptionIter::Empty, } @@ -289,7 +291,7 @@ impl FunctionScope { } } - pub(crate) fn insert_definition(&mut self, symbol: String, node_id: NodeId) { + pub(crate) fn insert_definition(&mut self, symbol: StringId, node_id: NodeId) { self.definitions.insert(symbol, node_id); } } @@ -303,7 +305,7 @@ impl ModifierScope { } } - pub(crate) fn insert_definition(&mut self, symbol: String, node_id: NodeId) { + pub(crate) fn insert_definition(&mut self, symbol: StringId, node_id: NodeId) { self.definitions.insert(symbol, node_id); } } @@ -315,9 +317,9 @@ impl ParametersScope { } } - pub(crate) fn add_parameter(&mut self, identifier: Option<&String>, node_id: NodeId) { + pub(crate) fn add_parameter(&mut self, name: Option, node_id: NodeId) { self.parameters.push(ParameterDefinition { - name: identifier.cloned(), + name, node_id, type_id: None, }); @@ -332,10 +334,10 @@ impl ParametersScope { } } - pub(crate) fn lookup_definition(&self, symbol: &str) -> Option { + pub(crate) fn lookup_definition(&self, symbol: StringId) -> Option { self.parameters .iter() - .find(|parameter| parameter.name.as_ref().is_some_and(|name| name == symbol)) + .find(|parameter| parameter.name.is_some_and(|name| name == symbol)) .map(|parameter| parameter.node_id) } } @@ -348,13 +350,13 @@ impl StructScope { } } - pub(crate) fn insert_definition(&mut self, symbol: String, node_id: NodeId) { + pub(crate) fn insert_definition(&mut self, symbol: StringId, node_id: NodeId) { self.definitions.insert(symbol, node_id); } } impl UsingScope { - fn new(node_id: NodeId, symbols: HashMap>) -> Self { + fn new(node_id: NodeId, symbols: HashMap>) -> Self { Self { node_id, symbols } } } @@ -368,7 +370,7 @@ impl YulBlockScope { } } - pub(crate) fn insert_definition(&mut self, symbol: String, node_id: NodeId) { + pub(crate) fn insert_definition(&mut self, symbol: StringId, node_id: NodeId) { self.definitions.insert(symbol, node_id); } } @@ -382,7 +384,7 @@ impl YulFunctionScope { } } - pub(crate) fn insert_definition(&mut self, symbol: String, node_id: NodeId) { + pub(crate) fn insert_definition(&mut self, symbol: StringId, node_id: NodeId) { self.definitions.insert(symbol, node_id); } } @@ -401,7 +403,7 @@ pub(crate) enum UsingDirective { }, SingleTypeOperator { scope_id: ScopeId, - operator_mapping: HashMap, + operator_mapping: HashMap, type_id: TypeId, }, } @@ -418,7 +420,7 @@ impl UsingDirective { pub(crate) fn new_single_type_with_operators( scope_id: ScopeId, type_id: TypeId, - operator_mapping: HashMap, + operator_mapping: HashMap, ) -> Self { Self::SingleTypeOperator { scope_id, diff --git a/crates/solidity-v2/outputs/cargo/semantic/src/context/mod.rs b/crates/solidity-v2/outputs/cargo/semantic/src/context/mod.rs index 90af616c8f..4c2da5fe3a 100644 --- a/crates/solidity-v2/outputs/cargo/semantic/src/context/mod.rs +++ b/crates/solidity-v2/outputs/cargo/semantic/src/context/mod.rs @@ -1,40 +1,58 @@ +use std::rc::Rc; + use slang_solidity_v2_common::versions::LanguageVersion; +use slang_solidity_v2_ir::interner::{Interner, StringId}; use slang_solidity_v2_ir::ir::{self, NodeId}; -use crate::binder::Binder; +use crate::binder::{Binder, Definition, Reference, Scope}; use crate::passes::{ p1_collect_definitions, p2_linearise_contracts, p3_type_definitions, p4_resolve_references, }; -use crate::types::TypeRegistry; +use crate::types::{Type, TypeId, TypeRegistry}; + +pub type FileId = StringId; /// Trait for files that can be used as input to the semantic analysis passes. pub trait SemanticFile { /// Returns the file identifier. - fn id(&self) -> &str; + fn file_id(&self) -> FileId; /// Returns the root IR node of the file. fn ir_root(&self) -> &ir::SourceUnit; /// Returns the resolved import target file ID for the given import node, if resolved. - fn resolved_import_by_node_id(&self, node_id: NodeId) -> Option<&String>; + fn resolved_import_by_node_id(&self, node_id: NodeId) -> Option; } pub struct SemanticContext { + interner: Rc, binder: Binder, types: TypeRegistry, } impl SemanticContext { - pub fn build_from(language_version: LanguageVersion, files: &[impl SemanticFile]) -> Self { + pub fn build_from( + language_version: LanguageVersion, + files: &[impl SemanticFile], + interner: &Rc, + ) -> Self { let mut binder = Binder::default(); let mut types = TypeRegistry::default(); p1_collect_definitions::run(files, &mut binder); p2_linearise_contracts::run(files, &mut binder); - p3_type_definitions::run(files, &mut binder, &mut types); - p4_resolve_references::run(files, &mut binder, &mut types, language_version); + p3_type_definitions::run(files, &mut binder, &mut types, interner); + p4_resolve_references::run(files, &mut binder, &mut types, language_version, interner); - Self { binder, types } + Self { + interner: Rc::clone(interner), + binder, + types, + } + } + + pub fn interner(&self) -> &Interner { + &self.interner } // TODO: this should not be public @@ -46,4 +64,260 @@ impl SemanticContext { pub fn types(&self) -> &TypeRegistry { &self.types } + + pub fn all_definitions(&self) -> impl Iterator + use<'_> { + self.binder.definitions().values() + } + + pub fn all_references(&self) -> impl Iterator + use<'_> { + self.binder.references().values() + } + + pub fn find_contract_by_name(&self, name: &str) -> Option { + self.binder().definitions().values().find_map(|definition| { + let Definition::Contract(contract) = definition else { + return None; + }; + if definition.identifier().unparse(&self.interner) == name { + Some(Rc::clone(&contract.ir_node)) + } else { + None + } + }) + } +} + +impl SemanticContext { + pub fn node_id_to_file_id(&self, node_id: NodeId) -> Option { + let scope_id = self.binder().scope_id_for_node_id(node_id)?; + let Scope::File(file_scope) = self.binder().get_scope_by_id(scope_id) else { + return None; + }; + Some(self.interner.resolve(file_scope.file_id).to_owned()) + } + + pub fn resolve_reference_identifier_to_definition_id(&self, node_id: NodeId) -> Option { + let reference = self + .binder() + .find_reference_by_identifier_node_id(node_id)?; + self.binder() + .follow_symbol_aliases(&reference.resolution) + .as_definition_id() + } + + pub fn resolve_reference_identifier_to_immediate_definition_id( + &self, + node_id: NodeId, + ) -> Option { + let reference = self + .binder() + .find_reference_by_identifier_node_id(node_id)?; + reference.resolution.as_definition_id() + } + + pub fn definition_canonical_name(&self, definition_id: NodeId) -> String { + self.binder + .find_definition_by_id(definition_id) + .unwrap() + .identifier() + .unparse(&self.interner) + .to_string() + } + + pub fn type_internal_name(&self, type_id: TypeId) -> String { + match self.types.get_type_by_id(type_id) { + Type::Address { .. } => "address".to_string(), + Type::Array { element_type, .. } => { + format!( + "{element}[]", + element = self.type_internal_name(*element_type) + ) + } + Type::Boolean => "bool".to_string(), + Type::ByteArray { width } => format!("bytes{width}"), + Type::Bytes { .. } => "bytes".to_string(), + Type::FixedPointNumber { + signed, + bits, + precision_bits, + } => format!( + "{prefix}{bits}x{precision_bits}", + prefix = if *signed { "fixed" } else { "ufixed" }, + ), + Type::FixedSizeArray { + element_type, size, .. + } => { + format!( + "{element}[{size}]", + element = self.type_internal_name(*element_type), + ) + } + Type::Function(_) => "function".to_string(), + Type::Integer { signed, bits } => format!( + "{prefix}{bits}", + prefix = if *signed { "int" } else { "uint" } + ), + Type::Literal(_) => "literal".to_string(), + Type::Mapping { + key_type_id, + value_type_id, + } => format!( + "mapping({key_type} => {value_type})", + key_type = self.type_internal_name(*key_type_id), + value_type = self.type_internal_name(*value_type_id) + ), + Type::String { .. } => "string".to_string(), + Type::Tuple { types } => format!( + "({types})", + types = types + .iter() + .map(|type_id| self.type_internal_name(*type_id)) + .collect::>() + .join(",") + ), + Type::Contract { definition_id } + | Type::Enum { definition_id } + | Type::Interface { definition_id } + | Type::Struct { definition_id, .. } + | Type::UserDefinedValue { definition_id } => { + self.definition_canonical_name(*definition_id) + } + Type::Void => "void".to_string(), + } + } + + pub fn type_canonical_name(&self, type_id: TypeId) -> Option { + match self.types.get_type_by_id(type_id) { + Type::Address { .. } + | Type::Boolean + | Type::ByteArray { .. } + | Type::Bytes { .. } + | Type::FixedPointNumber { .. } + | Type::Function(_) + | Type::Integer { .. } + | Type::String { .. } => Some(self.type_internal_name(type_id)), + + Type::Array { element_type, .. } => self + .type_canonical_name(*element_type) + .map(|element| format!("{element}[]",)), + Type::FixedSizeArray { + element_type, size, .. + } => self + .type_canonical_name(*element_type) + .map(|element| format!("{element}[{size}]",)), + + Type::Contract { .. } | Type::Interface { .. } => Some("address".to_string()), + + Type::Enum { .. } => Some("uint8".to_string()), + + Type::Struct { definition_id, .. } => { + let Definition::Struct(struct_) = self + .binder + .find_definition_by_id(*definition_id) + .expect("definition in type exists") + else { + unreachable!("definition in struct type is not a struct"); + }; + let mut fields = Vec::new(); + for member in &struct_.ir_node.members { + let member_type_id = self.binder.node_typing(member.id()).as_type_id()?; + let field_type = self.type_canonical_name(member_type_id)?; + fields.push(field_type); + } + Some(format!("({fields})", fields = fields.join(","))) + } + + Type::UserDefinedValue { definition_id } => { + let Definition::UserDefinedValueType(udvt) = self + .binder + .find_definition_by_id(*definition_id) + .expect("definition in type exists") + else { + unreachable!("definition in user defined value type is not a UDVT"); + }; + udvt.target_type_id + .and_then(|type_id| self.type_canonical_name(type_id)) + } + + Type::Literal(_) | Type::Mapping { .. } | Type::Tuple { .. } | Type::Void => None, + } + } + + pub const SLOT_SIZE: usize = 32; + pub const ADDRESS_BYTE_SIZE: usize = 20; + pub const SELECTOR_SIZE: usize = 4; + + pub fn storage_size_of_type_id(&self, type_id: TypeId) -> Option { + match self.types.get_type_by_id(type_id) { + Type::Address { .. } | Type::Contract { .. } | Type::Interface { .. } => { + Some(Self::ADDRESS_BYTE_SIZE) + } + Type::Boolean => Some(1), + Type::FixedPointNumber { bits, .. } | Type::Integer { bits, .. } => { + Some((bits.div_ceil(8)).try_into().unwrap()) + } + Type::ByteArray { width } => Some((*width).try_into().unwrap()), + Type::Enum { .. } => Some(1), + Type::Bytes { .. } | Type::String { .. } => Some(Self::SLOT_SIZE), + Type::Mapping { .. } => Some(Self::SLOT_SIZE), + + Type::Array { .. } => Some(Self::SLOT_SIZE), + Type::FixedSizeArray { + element_type, size, .. + } => { + let element_size = self.storage_size_of_type_id(*element_type)?; + if element_size > Self::SLOT_SIZE { + let slots_per_element = element_size.div_ceil(Self::SLOT_SIZE); + Some(slots_per_element * size * Self::SLOT_SIZE) + } else { + let elements_per_slot = Self::SLOT_SIZE / element_size; + let num_slots = size.div_ceil(elements_per_slot); + Some(num_slots * Self::SLOT_SIZE) + } + } + + Type::Function(function_type) => { + if function_type.external { + Some(Self::ADDRESS_BYTE_SIZE + Self::SELECTOR_SIZE) + } else { + // NOTE: an internal function ref type is 8 bytes long, it's + // opaque and its meaning not documented + Some(8) + } + } + Type::Struct { definition_id, .. } => { + let Definition::Struct(struct_definition) = + self.binder.find_definition_by_id(*definition_id)? + else { + return None; + }; + let mut ptr: usize = 0; + for member in &struct_definition.ir_node.members { + let member_type_id = self.binder.node_typing(member.id()).as_type_id()?; + let member_size = self.storage_size_of_type_id(member_type_id)?; + let remaining_bytes = Self::SLOT_SIZE - (ptr % Self::SLOT_SIZE); + if remaining_bytes < Self::SLOT_SIZE && member_size >= remaining_bytes { + ptr += remaining_bytes; + } + ptr += member_size; + } + // round up the final allocation to a full slot, because the + // next variable needs to start at the next slot anyway + ptr = ptr.div_ceil(Self::SLOT_SIZE) * Self::SLOT_SIZE; + Some(ptr) + } + Type::UserDefinedValue { definition_id } => { + let Definition::UserDefinedValueType(user_defined_value) = + self.binder.find_definition_by_id(*definition_id)? + else { + return None; + }; + self.storage_size_of_type_id(user_defined_value.target_type_id?) + } + + Type::Literal(_) => None, + Type::Tuple { .. } => None, + Type::Void => None, + } + } } diff --git a/crates/solidity-v2/outputs/cargo/semantic/src/passes/common.rs b/crates/solidity-v2/outputs/cargo/semantic/src/passes/common.rs index 66fde623df..86c523b5b4 100644 --- a/crates/solidity-v2/outputs/cargo/semantic/src/passes/common.rs +++ b/crates/solidity-v2/outputs/cargo/semantic/src/passes/common.rs @@ -18,7 +18,7 @@ pub(super) fn resolve_identifier_path_in_scope( let mut last_resolution: Resolution = Resolution::Unresolved; for identifier in identifier_path { - let symbol = identifier.unparse(); + let symbol = identifier.string_id; let resolution = if let Some(scope_id) = scope_id { if use_lexical_resolution { binder.resolve_in_scope(scope_id, symbol) @@ -54,7 +54,7 @@ pub(super) fn resolve_identifier_path_in_scope( resolved_file_id, .. }) => resolved_file_id .as_ref() - .and_then(|resolved_file_id| binder.scope_id_for_file_id(resolved_file_id)), + .and_then(|resolved_file_id| binder.scope_id_for_file_id(*resolved_file_id)), Definition::Contract(_) | Definition::Interface(_) | Definition::Library(_) => { use_lexical_resolution = false; binder.scope_id_for_node_id(definition.node_id()) diff --git a/crates/solidity-v2/outputs/cargo/semantic/src/passes/p1_collect_definitions/mod.rs b/crates/solidity-v2/outputs/cargo/semantic/src/passes/p1_collect_definitions/mod.rs index 2c1896251e..d9d0d0f0ad 100644 --- a/crates/solidity-v2/outputs/cargo/semantic/src/passes/p1_collect_definitions/mod.rs +++ b/crates/solidity-v2/outputs/cargo/semantic/src/passes/p1_collect_definitions/mod.rs @@ -2,7 +2,7 @@ use slang_solidity_v2_ir::ir::visitor::Visitor; use slang_solidity_v2_ir::ir::{self, NodeId}; use crate::binder::{Binder, Definition, FileScope, ParametersScope, Scope, ScopeId}; -use crate::context::SemanticFile; +use crate::context::{FileId, SemanticFile}; /// In this pass all definitions are collected with their naming identifiers. /// Also lexical (and other kinds of) scopes are identified and linked together, @@ -116,10 +116,8 @@ impl<'a, F: SemanticFile> Pass<'a, F> { .insert_definition_in_scope(definition, self.current_scope_id()); } - fn resolve_import_path(&self, import_node_id: NodeId) -> Option { - self.current_file - .resolved_import_by_node_id(import_node_id) - .cloned() + fn resolve_import_path(&mut self, import_node_id: NodeId) -> Option { + self.current_file.resolved_import_by_node_id(import_node_id) // TODO(validation): emit an error/warning if the file cannot be resolved } @@ -130,7 +128,10 @@ impl<'a, F: SemanticFile> Pass<'a, F> { fn collect_parameters(&mut self, parameters: &ir::Parameters) -> ScopeId { let mut scope = ParametersScope::new(); for parameter in parameters { - scope.add_parameter(parameter.name.as_ref().map(|id| &id.text), parameter.id()); + scope.add_parameter( + parameter.name.as_ref().map(|id| id.string_id), + parameter.id(), + ); if parameter.name.is_some() { let definition = Definition::new_parameter(parameter); self.binder.insert_definition_no_scope(definition); @@ -170,7 +171,7 @@ impl<'a, F: SemanticFile> Pass<'a, F> { impl Visitor for Pass<'_, F> { fn enter_source_unit(&mut self, node: &ir::SourceUnit) -> bool { - let scope = Scope::new_file(node.id(), self.current_file.id()); + let scope = Scope::new_file(node.id(), self.current_file.file_id()); self.enter_scope(scope); true @@ -240,11 +241,8 @@ impl Visitor for Pass<'_, F> { let imported_file_id = self.resolve_import_path(node.id()); for symbol in &node.symbols { - let definition = Definition::new_imported_symbol( - symbol, - symbol.name.unparse().to_owned(), - imported_file_id.clone(), - ); + let definition = + Definition::new_imported_symbol(symbol, symbol.name.string_id, imported_file_id); self.insert_definition_in_current_scope(definition); } @@ -269,10 +267,10 @@ impl Visitor for Pass<'_, F> { let current_scope_node_id = self.current_scope().node_id(); let enclosing_definition = self.binder.find_definition_by_id(current_scope_node_id); - let enclosing_contract_name = + let enclosing_contract_string_id = if let Some(enclosing_definition) = enclosing_definition { if matches!(enclosing_definition, Definition::Contract(_)) { - Some(enclosing_definition.identifier().unparse()) + Some(enclosing_definition.identifier().string_id) } else { None } @@ -280,8 +278,8 @@ impl Visitor for Pass<'_, F> { None }; - if enclosing_contract_name - .is_some_and(|contract_name| contract_name == name.unparse()) + if enclosing_contract_string_id + .is_some_and(|contract_id| contract_id == name.string_id) { // TODO(validation): there cannot be a function with the // same name as the enclosing contract (since Solidity diff --git a/crates/solidity-v2/outputs/cargo/semantic/src/passes/p3_type_definitions/evaluator.rs b/crates/solidity-v2/outputs/cargo/semantic/src/passes/p3_type_definitions/evaluator.rs index cecd3745a2..ea846e73d7 100644 --- a/crates/solidity-v2/outputs/cargo/semantic/src/passes/p3_type_definitions/evaluator.rs +++ b/crates/solidity-v2/outputs/cargo/semantic/src/passes/p3_type_definitions/evaluator.rs @@ -3,14 +3,16 @@ use std::str::FromStr; use num_bigint::BigInt; use num_traits::cast::ToPrimitive; use num_traits::Num; +use slang_solidity_v2_ir::interner::{Interner, StringId}; use slang_solidity_v2_ir::ir; pub(crate) fn evaluate_compile_time_uint_constant( expression: &ir::Expression, start_scope: Scope, identifier_resolver: &dyn ConstantIdentifierResolver, + interner: &Interner, ) -> Option { - evaluate_compile_time_constant(expression, start_scope, identifier_resolver) + evaluate_compile_time_constant(expression, start_scope, identifier_resolver, interner) .and_then(|value| value.as_usize()) } @@ -18,9 +20,11 @@ fn evaluate_compile_time_constant( expression: &ir::Expression, start_scope: Scope, identifier_resolver: &dyn ConstantIdentifierResolver, + interner: &Interner, ) -> Option { let mut evaluator = CompileConstantEvaluator { identifier_resolver, + interner, scope_stack: Vec::new(), }; evaluator.evaluate_expression_in_scope(expression, start_scope) @@ -45,13 +49,14 @@ pub(crate) trait ConstantIdentifierResolver { /// be resolved to a constant. fn resolve_identifier_in_scope( &self, - identifier: &str, + identifier: StringId, scope: &Scope, ) -> Option<(ir::Expression, Scope)>; } struct CompileConstantEvaluator<'a, Scope> { identifier_resolver: &'a dyn ConstantIdentifierResolver, + interner: &'a Interner, scope_stack: Vec, } @@ -102,10 +107,10 @@ impl CompileConstantEvaluator<'_, Scope> { self.evaluate_prefix_expression(prefix_expression) } ir::Expression::HexNumberExpression(hex_number_expression) => { - Self::evaluate_hex_number_expression(hex_number_expression) + self.evaluate_hex_number_expression(hex_number_expression) } ir::Expression::DecimalNumberExpression(decimal_number_expression) => { - Self::evaluate_decimal_number_expression(decimal_number_expression) + self.evaluate_decimal_number_expression(decimal_number_expression) } ir::Expression::Identifier(identifier) => self.evaluate_identifier(identifier), ir::Expression::TupleExpression(tuple_expression) => { @@ -254,9 +259,10 @@ impl CompileConstantEvaluator<'_, Scope> { } fn evaluate_hex_number_expression( + &self, hex_number_expression: &ir::HexNumberExpression, ) -> Option { - let hex = hex_number_expression.literal.unparse(); + let hex = hex_number_expression.literal.unparse(self.interner); // skip `0x` prefix and parse the hexadecimal number BigInt::from_str_radix(&hex[2..], 16) .ok() @@ -264,11 +270,12 @@ impl CompileConstantEvaluator<'_, Scope> { } fn evaluate_decimal_number_expression( + &self, decimal_number_expression: &ir::DecimalNumberExpression, ) -> Option { // TODO: this only handles integers but not rational numbers // TODO: handle number units - let decimal = decimal_number_expression.literal.unparse(); + let decimal = decimal_number_expression.literal.unparse(self.interner); BigInt::from_str(decimal).ok().map(ConstantValue::Integer) } @@ -276,7 +283,7 @@ impl CompileConstantEvaluator<'_, Scope> { let current_scope = self.scope_stack.last().expect("scope stack is empty"); let (target_expression, target_scope) = self .identifier_resolver - .resolve_identifier_in_scope(identifier.unparse(), current_scope)?; + .resolve_identifier_in_scope(identifier.string_id, current_scope)?; self.evaluate_expression_in_scope(&target_expression, target_scope) } diff --git a/crates/solidity-v2/outputs/cargo/semantic/src/passes/p3_type_definitions/mod.rs b/crates/solidity-v2/outputs/cargo/semantic/src/passes/p3_type_definitions/mod.rs index 5e97fe358a..17947f4879 100644 --- a/crates/solidity-v2/outputs/cargo/semantic/src/passes/p3_type_definitions/mod.rs +++ b/crates/solidity-v2/outputs/cargo/semantic/src/passes/p3_type_definitions/mod.rs @@ -1,3 +1,4 @@ +use slang_solidity_v2_ir::interner::Interner; use slang_solidity_v2_ir::ir::{self, NodeId}; use crate::binder::{Binder, Definition, Scope, ScopeId}; @@ -18,12 +19,17 @@ mod visitor; /// Finally, public state variables will be assigned an equivalent getter /// function type. This happens after the main typing pass to ensure all types /// are already registered. -pub fn run(files: &[impl SemanticFile], binder: &mut Binder, types: &mut TypeRegistry) { +pub fn run( + files: &[impl SemanticFile], + binder: &mut Binder, + types: &mut TypeRegistry, + interner: &Interner, +) { for file in files { - Pass::visit_file(file, binder, types); + Pass::visit_file(file, binder, types, interner); } for file in files { - Pass::visit_file_type_getters(file, binder, types); + Pass::visit_file_type_getters(file, binder, types, interner); } } @@ -31,15 +37,22 @@ struct Pass<'a> { scope_stack: Vec, binder: &'a mut Binder, types: &'a mut TypeRegistry, + interner: &'a Interner, current_receiver_type: Option, } impl<'a> Pass<'a> { - fn visit_file(file: &impl SemanticFile, binder: &'a mut Binder, types: &'a mut TypeRegistry) { + fn visit_file( + file: &impl SemanticFile, + binder: &'a mut Binder, + types: &'a mut TypeRegistry, + interner: &'a Interner, + ) { let mut pass = Self { scope_stack: Vec::new(), binder, types, + interner, current_receiver_type: None, }; ir::visitor::accept_source_unit(file.ir_root(), &mut pass); @@ -56,11 +69,13 @@ impl<'a> Pass<'a> { file: &impl SemanticFile, binder: &'a mut Binder, types: &'a mut TypeRegistry, + interner: &'a Interner, ) { let mut pass = Self { scope_stack: Vec::new(), binder, types, + interner, current_receiver_type: None, }; pass.type_getters_from(file.ir_root()); diff --git a/crates/solidity-v2/outputs/cargo/semantic/src/passes/p3_type_definitions/resolution.rs b/crates/solidity-v2/outputs/cargo/semantic/src/passes/p3_type_definitions/resolution.rs index 39e043af5a..0589916fa4 100644 --- a/crates/solidity-v2/outputs/cargo/semantic/src/passes/p3_type_definitions/resolution.rs +++ b/crates/solidity-v2/outputs/cargo/semantic/src/passes/p3_type_definitions/resolution.rs @@ -1,3 +1,4 @@ +use slang_solidity_v2_ir::interner::StringId; use slang_solidity_v2_ir::ir; use super::evaluator::{evaluate_compile_time_uint_constant, ConstantIdentifierResolver}; @@ -50,6 +51,7 @@ impl Pass<'_> { size_expression, self.current_contract_or_file_scope_id(), self, + self.interner, ) .unwrap_or_default(); self.types.register_type(Type::FixedSizeArray { @@ -144,7 +146,7 @@ impl Pass<'_> { impl ConstantIdentifierResolver for Pass<'_> { fn resolve_identifier_in_scope( &self, - identifier: &str, + identifier: StringId, scope_id: &ScopeId, ) -> Option<(ir::Expression, ScopeId)> { let resolution = self.binder.resolve_in_scope(*scope_id, identifier); diff --git a/crates/solidity-v2/outputs/cargo/semantic/src/passes/p3_type_definitions/typing.rs b/crates/solidity-v2/outputs/cargo/semantic/src/passes/p3_type_definitions/typing.rs index d145a85c9b..652fa5df49 100644 --- a/crates/solidity-v2/outputs/cargo/semantic/src/passes/p3_type_definitions/typing.rs +++ b/crates/solidity-v2/outputs/cargo/semantic/src/passes/p3_type_definitions/typing.rs @@ -90,25 +90,23 @@ impl Pass<'_> { })) } ir::ElementaryType::BytesKeyword(bytes_keyword) => { - Type::from_bytes_keyword(bytes_keyword.unparse(), data_location) + Type::from_bytes_keyword(bytes_keyword.unparse(self.interner), data_location) .map(|type_| self.types.register_type(type_)) } ir::ElementaryType::IntKeyword(int_keyword) => Some( self.types - .register_type(Type::from_int_keyword(int_keyword.unparse())), + .register_type(Type::from_int_keyword(int_keyword.unparse(self.interner))), ), ir::ElementaryType::UintKeyword(uint_keyword) => Some( self.types - .register_type(Type::from_uint_keyword(uint_keyword.unparse())), - ), - ir::ElementaryType::FixedKeyword(fixed_keyword) => Some( - self.types - .register_type(Type::from_fixed_keyword(fixed_keyword.unparse())), - ), - ir::ElementaryType::UfixedKeyword(ufixed_keyword) => Some( - self.types - .register_type(Type::from_ufixed_keyword(ufixed_keyword.unparse())), + .register_type(Type::from_uint_keyword(uint_keyword.unparse(self.interner))), ), + ir::ElementaryType::FixedKeyword(fixed_keyword) => Some(self.types.register_type( + Type::from_fixed_keyword(fixed_keyword.unparse(self.interner)), + )), + ir::ElementaryType::UfixedKeyword(ufixed_keyword) => Some(self.types.register_type( + Type::from_ufixed_keyword(ufixed_keyword.unparse(self.interner)), + )), ir::ElementaryType::BoolKeyword => Some(self.types.boolean()), // No ByteKeyword in v2 (removed since Solidity >= 0.8.0) ir::ElementaryType::StringKeyword => data_location.map(|data_location| { diff --git a/crates/solidity-v2/outputs/cargo/semantic/src/passes/p3_type_definitions/visitor.rs b/crates/solidity-v2/outputs/cargo/semantic/src/passes/p3_type_definitions/visitor.rs index 51fe8b617b..ee9b799418 100644 --- a/crates/solidity-v2/outputs/cargo/semantic/src/passes/p3_type_definitions/visitor.rs +++ b/crates/solidity-v2/outputs/cargo/semantic/src/passes/p3_type_definitions/visitor.rs @@ -51,6 +51,7 @@ impl Visitor for Pass<'_> { base_slot_expression, self.current_contract_or_file_scope_id(), self, + self.interner, ) { let Definition::Contract(contract_definition) = self.binder.get_definition_mut(node.id()) @@ -115,11 +116,11 @@ impl Visitor for Pass<'_> { let scope_id = imported_symbol .resolved_file_id .as_ref() - .and_then(|file_id| self.binder.scope_id_for_file_id(file_id)); + .and_then(|file_id| self.binder.scope_id_for_file_id(*file_id)); let resolution = scope_id.map_or(Resolution::Unresolved, |scope_id| { self.binder - .resolve_in_scope(scope_id, symbol.name.unparse()) + .resolve_in_scope(scope_id, symbol.name.string_id) }); let reference = Reference::new(Rc::clone(&symbol.name), resolution); self.binder.insert_reference(reference); @@ -354,11 +355,10 @@ impl Visitor for Pass<'_> { }); // TODO(validation): *all* definitions should point to functions - symbols.insert(symbol_name.unparse().to_string(), definition_ids); + symbols.insert(symbol_name.string_id, definition_ids); if let Some(operator) = &symbol.alias { - operators - .insert(operator.clone(), symbol_name.unparse().to_string()); + operators.insert(operator.clone(), symbol_name.string_id); } } @@ -422,7 +422,7 @@ impl Visitor for Pass<'_> { fn enter_catch_clause_error(&mut self, node: &ir::CatchClauseError) -> bool { if let Some(name) = &node.name { - let resolution = match name.unparse() { + let resolution = match name.unparse(self.interner) { "Error" | "Panic" => Resolution::BuiltIn(BuiltIn::ErrorOrPanic), _ => Resolution::Unresolved, }; diff --git a/crates/solidity-v2/outputs/cargo/semantic/src/passes/p4_resolve_references/disambiguation.rs b/crates/solidity-v2/outputs/cargo/semantic/src/passes/p4_resolve_references/disambiguation.rs index a9a01bf0b1..79b775abe3 100644 --- a/crates/solidity-v2/outputs/cargo/semantic/src/passes/p4_resolve_references/disambiguation.rs +++ b/crates/solidity-v2/outputs/cargo/semantic/src/passes/p4_resolve_references/disambiguation.rs @@ -1,3 +1,4 @@ +use slang_solidity_v2_ir::interner::StringId; use slang_solidity_v2_ir::ir::NodeId; use super::Pass; @@ -144,7 +145,7 @@ impl Pass<'_> { pub(super) fn lookup_function_matching_named_arguments<'a>( &'a self, type_ids: &[TypeId], - argument_typings: &[(String, Typing)], + argument_typings: &[(StringId, Typing)], receiver_type_id: Option, ) -> Option<&'a FunctionType> { // get types and filter non-function types @@ -202,18 +203,16 @@ impl Pass<'_> { fn parameters_match_named_arguments( &self, parameters: &[ParameterDefinition], - argument_typings: &[(String, Typing)], + argument_typings: &[(StringId, Typing)], external_call: bool, ) -> bool { argument_typings .iter() .all(|(argument_name, argument_typing)| { - let Some(parameter) = parameters.iter().find(|parameter| { - parameter - .name - .as_ref() - .is_some_and(|name| name == argument_name) - }) else { + let Some(parameter) = parameters + .iter() + .find(|parameter| parameter.name.is_some_and(|name| name == *argument_name)) + else { return false; }; parameter.type_id.is_some_and(|type_id| { @@ -267,7 +266,7 @@ impl Pass<'_> { pub(super) fn lookup_event_matching_named_arguments( &self, definition_ids: &[NodeId], - argument_typings: &[(String, Typing)], + argument_typings: &[(StringId, Typing)], ) -> Option { for definition_id in definition_ids { let Some(parameters) = self.get_event_definition_parameters(*definition_id) else { diff --git a/crates/solidity-v2/outputs/cargo/semantic/src/passes/p4_resolve_references/mod.rs b/crates/solidity-v2/outputs/cargo/semantic/src/passes/p4_resolve_references/mod.rs index f3359399e6..09e05c5215 100644 --- a/crates/solidity-v2/outputs/cargo/semantic/src/passes/p4_resolve_references/mod.rs +++ b/crates/solidity-v2/outputs/cargo/semantic/src/passes/p4_resolve_references/mod.rs @@ -1,4 +1,5 @@ use slang_solidity_v2_common::versions::LanguageVersion; +use slang_solidity_v2_ir::interner::Interner; use slang_solidity_v2_ir::ir::{self, NodeId}; use crate::binder::{Binder, Scope, ScopeId}; @@ -21,9 +22,10 @@ pub fn run( binder: &mut Binder, types: &mut TypeRegistry, language_version: LanguageVersion, + interner: &Interner, ) { for file in files { - Pass::visit_file(file, binder, types, language_version); + Pass::visit_file(file, binder, types, language_version, interner); } // update definition->references reverse mapping binder.update_definitions_to_references_index(); @@ -42,6 +44,7 @@ struct Pass<'a> { scope_stack: Vec, binder: &'a mut Binder, types: &'a mut TypeRegistry, + interner: &'a Interner, } impl<'a> Pass<'a> { @@ -50,12 +53,14 @@ impl<'a> Pass<'a> { binder: &'a mut Binder, types: &'a mut TypeRegistry, language_version: LanguageVersion, + interner: &'a Interner, ) { let mut pass = Self { language_version, scope_stack: Vec::new(), binder, types, + interner, }; ir::visitor::accept_source_unit(file.ir_root(), &mut pass); assert!(pass.scope_stack.is_empty()); diff --git a/crates/solidity-v2/outputs/cargo/semantic/src/passes/p4_resolve_references/resolution.rs b/crates/solidity-v2/outputs/cargo/semantic/src/passes/p4_resolve_references/resolution.rs index 4bffb64145..c44f8c805d 100644 --- a/crates/solidity-v2/outputs/cargo/semantic/src/passes/p4_resolve_references/resolution.rs +++ b/crates/solidity-v2/outputs/cargo/semantic/src/passes/p4_resolve_references/resolution.rs @@ -1,6 +1,7 @@ use std::collections::HashSet; use std::rc::Rc; +use slang_solidity_v2_ir::interner::StringId; use slang_solidity_v2_ir::ir::{self, NodeId}; use super::{Pass, ScopeFrame}; @@ -12,10 +13,17 @@ use crate::types::{FunctionType, Type, TypeId}; /// Lexical style resolution of symbols impl Pass<'_> { // This is a "top-level" (ie. not a member access) resolution method - pub(super) fn resolve_symbol_in_scope(&self, scope_id: ScopeId, symbol: &str) -> Resolution { + pub(super) fn resolve_symbol_in_scope( + &self, + scope_id: ScopeId, + symbol: StringId, + ) -> Resolution { let resolution = self.binder.resolve_in_scope(scope_id, symbol); match &resolution { - Resolution::Unresolved => self.built_ins_resolver().lookup_global(symbol).into(), + Resolution::Unresolved => self + .built_ins_resolver() + .lookup_global(self.interner.resolve(symbol)) + .into(), Resolution::Ambiguous(definition_ids) => { // Try to disambiguate known cases let first_id = definition_ids.first().copied().unwrap(); @@ -123,7 +131,7 @@ impl Pass<'_> { Resolution::from(filtered_definitions) } - pub(super) fn resolve_symbol_in_typing(&self, typing: &Typing, symbol: &str) -> Resolution { + pub(super) fn resolve_symbol_in_typing(&self, typing: &Typing, symbol: StringId) -> Resolution { match typing { Typing::Unresolved => Resolution::Unresolved, Typing::Undetermined(type_ids) => { @@ -183,7 +191,7 @@ impl Pass<'_> { Typing::MetaType(type_) => { if let Some(built_in) = self .built_ins_resolver() - .lookup_member_of_meta_type(type_, symbol) + .lookup_member_of_meta_type(type_, self.interner.resolve(symbol)) { Resolution::BuiltIn(built_in) } else { @@ -201,7 +209,7 @@ impl Pass<'_> { if let Some(scope_id) = import_definition .resolved_file_id .as_ref() - .and_then(|file_id| self.binder.scope_id_for_file_id(file_id)) + .and_then(|file_id| self.binder.scope_id_for_file_id(*file_id)) { self.binder.resolve_in_scope(scope_id, symbol) } else { @@ -221,18 +229,18 @@ impl Pass<'_> { } _ => self .built_ins_resolver() - .lookup_member_of_user_definition(definition, symbol) + .lookup_member_of_user_definition(definition, self.interner.resolve(symbol)) .into(), } } Typing::BuiltIn(built_in) => self .built_ins_resolver() - .lookup_member_of(built_in, symbol) + .lookup_member_of(built_in, self.interner.resolve(symbol)) .into(), } } - fn resolve_symbol_in_type(&self, type_id: TypeId, symbol: &str) -> Resolution { + fn resolve_symbol_in_type(&self, type_id: TypeId, symbol: StringId) -> Resolution { let type_ = self.types.get_type_by_id(type_id); // Resolve direct members of the type first @@ -243,7 +251,7 @@ impl Pass<'_> { .resolve_in_contract_scope(scope_id, symbol, ResolveOptions::External) .or_else(|| { self.built_ins_resolver() - .lookup_member_of_type_id(type_id, symbol) + .lookup_member_of_type_id(type_id, self.interner.resolve(symbol)) .into() }) } @@ -261,7 +269,7 @@ impl Pass<'_> { Resolution::from(definition_ids).or_else(|| { // If still unresolved, try with a built-in self.built_ins_resolver() - .lookup_member_of_type_id(type_id, symbol) + .lookup_member_of_type_id(type_id, self.interner.resolve(symbol)) .into() }) } @@ -269,7 +277,7 @@ impl Pass<'_> { fn add_attached_functions_for_type( &self, receiver_type_id: TypeId, - symbol: &str, + symbol: StringId, definition_ids: &mut Vec, ) { let active_directives = self.active_using_directives_for_type(receiver_type_id); @@ -356,7 +364,7 @@ impl Pass<'_> { let mut use_contract_lookup = true; for (index, identifier) in identifier_path.iter().enumerate() { let resolution = if let Some(scope_id) = scope_id { - let symbol = identifier.unparse(); + let symbol = identifier.string_id; if use_contract_lookup { use_contract_lookup = false; self.resolve_symbol_in_scope(scope_id, symbol) @@ -407,7 +415,7 @@ impl Pass<'_> { let resolution = parameters_scope_id.map_or(Resolution::Unresolved, |parameters_scope_id| { self.binder - .resolve_in_scope_as_namespace(parameters_scope_id, identifier.unparse()) + .resolve_in_scope_as_namespace(parameters_scope_id, identifier.string_id) }); let reference = Reference::new(Rc::clone(identifier), resolution); self.binder.insert_reference(reference); @@ -418,12 +426,14 @@ impl Pass<'_> { pub(super) fn resolve_symbol_in_yul_scope( &self, scope_id: ScopeId, - symbol: &str, + symbol: StringId, ) -> Resolution { let resolution = self.filter_overriden_definitions(self.binder.resolve_in_scope(scope_id, symbol)); if resolution == Resolution::Unresolved { - self.built_ins_resolver().lookup_yul_global(symbol).into() + self.built_ins_resolver() + .lookup_yul_global(self.interner.resolve(symbol)) + .into() } else { resolution } @@ -431,14 +441,14 @@ impl Pass<'_> { pub(super) fn resolve_yul_suffix( &self, - symbol: &str, + symbol: StringId, parent_resolution: &Resolution, ) -> Resolution { match parent_resolution { Resolution::Definition(node_id) => { if let Some(definition) = self.binder.find_definition_by_id(*node_id) { self.built_ins_resolver() - .lookup_yul_suffix(definition, symbol) + .lookup_yul_suffix(definition, self.interner.resolve(symbol)) .into() } else { Resolution::Unresolved diff --git a/crates/solidity-v2/outputs/cargo/semantic/src/passes/p4_resolve_references/typing.rs b/crates/solidity-v2/outputs/cargo/semantic/src/passes/p4_resolve_references/typing.rs index 8120f829bf..bebd258607 100644 --- a/crates/solidity-v2/outputs/cargo/semantic/src/passes/p4_resolve_references/typing.rs +++ b/crates/solidity-v2/outputs/cargo/semantic/src/passes/p4_resolve_references/typing.rs @@ -1,3 +1,4 @@ +use slang_solidity_v2_ir::interner::StringId; use slang_solidity_v2_ir::ir::{self, NodeId}; use super::Pass; @@ -81,7 +82,7 @@ impl Pass<'_> { .binder .node_typing(Self::string_expression_node_id(string_expression)), ir::Expression::ElementaryType(elementary_type) => { - Typing::MetaType(Self::type_of_elementary_type(elementary_type)) + Typing::MetaType(self.type_of_elementary_type(elementary_type)) } ir::Expression::Identifier(identifier) => self.typing_of_identifier(identifier), ir::Expression::PayableKeyword => Typing::MetaType(Type::Address { payable: true }), @@ -90,23 +91,27 @@ impl Pass<'_> { } } - fn type_of_elementary_type(elementary_type: &ir::ElementaryType) -> Type { + fn type_of_elementary_type(&self, elementary_type: &ir::ElementaryType) -> Type { match elementary_type { ir::ElementaryType::AddressType(address_type) => Type::Address { payable: address_type.payable_keyword, }, - ir::ElementaryType::BytesKeyword(terminal) => { - Type::from_bytes_keyword(terminal.unparse(), Some(DataLocation::Memory)).unwrap() + ir::ElementaryType::BytesKeyword(terminal) => Type::from_bytes_keyword( + terminal.unparse(self.interner), + Some(DataLocation::Memory), + ) + .unwrap(), + ir::ElementaryType::IntKeyword(terminal) => { + Type::from_int_keyword(terminal.unparse(self.interner)) } - ir::ElementaryType::IntKeyword(terminal) => Type::from_int_keyword(terminal.unparse()), ir::ElementaryType::UintKeyword(terminal) => { - Type::from_uint_keyword(terminal.unparse()) + Type::from_uint_keyword(terminal.unparse(self.interner)) } ir::ElementaryType::FixedKeyword(terminal) => { - Type::from_fixed_keyword(terminal.unparse()) + Type::from_fixed_keyword(terminal.unparse(self.interner)) } ir::ElementaryType::UfixedKeyword(terminal) => { - Type::from_ufixed_keyword(terminal.unparse()) + Type::from_ufixed_keyword(terminal.unparse(self.interner)) } ir::ElementaryType::BoolKeyword => Type::Boolean, ir::ElementaryType::StringKeyword => Type::String { @@ -386,12 +391,12 @@ impl Pass<'_> { pub(super) fn collect_named_argument_typings( &self, arguments: &[ir::NamedArgument], - ) -> Vec<(String, Typing)> { + ) -> Vec<(StringId, Typing)> { arguments .iter() .map(|argument| { ( - argument.name.unparse().to_string(), + argument.name.string_id, self.typing_of_expression(&argument.value), ) }) @@ -516,12 +521,12 @@ impl Pass<'_> { } } - pub(super) fn type_of_string_expression(node: &ir::StringExpression) -> Type { + pub(super) fn type_of_string_expression(&self, node: &ir::StringExpression) -> Type { let kind = match node { ir::StringExpression::StringLiterals(strings) => { let size = strings.iter().fold(0usize, |acc, string| { // TODO: consider escaped characters - acc + string.unparse().len() - 2 + acc + string.unparse(self.interner).len() - 2 }); LiteralKind::String { bytes: u32::try_from(size).unwrap(), @@ -530,7 +535,7 @@ impl Pass<'_> { ir::StringExpression::HexStringLiterals(hex_strings) => { let size = hex_strings.iter().fold(0usize, |acc, hex_string| { // 5 is the length of the `hex` prefix plus the quotes - acc + (hex_string.unparse().len() - 5) / 2 + acc + (hex_string.unparse(self.interner).len() - 5) / 2 }); LiteralKind::String { bytes: u32::try_from(size).unwrap(), @@ -540,7 +545,7 @@ impl Pass<'_> { let size = unicode_strings.iter().fold(0usize, |acc, unicode_string| { // TODO: actually parse the string // 9 is the length of the `unicode` prefix plus quotes - acc + unicode_string.unparse().len() - 9 + acc + unicode_string.unparse(self.interner).len() - 9 }); LiteralKind::String { bytes: u32::try_from(size).unwrap(), @@ -551,9 +556,10 @@ impl Pass<'_> { } pub(super) fn hex_number_literal_kind( + &self, hex_number_expression: &ir::HexNumberExpression, ) -> LiteralKind { - let hex_number = hex_number_expression.literal.unparse(); + let hex_number = hex_number_expression.literal.unparse(self.interner); if hex_number.len() == 42 { // TODO(validation): verify the address is valid (ie. has a valid checksum) // We need at least an implementation of SHA3 to compute the checksum diff --git a/crates/solidity-v2/outputs/cargo/semantic/src/passes/p4_resolve_references/visitor.rs b/crates/solidity-v2/outputs/cargo/semantic/src/passes/p4_resolve_references/visitor.rs index 10f2ffd178..ba4b8de49b 100644 --- a/crates/solidity-v2/outputs/cargo/semantic/src/passes/p4_resolve_references/visitor.rs +++ b/crates/solidity-v2/outputs/cargo/semantic/src/passes/p4_resolve_references/visitor.rs @@ -115,8 +115,9 @@ impl Visitor for Pass<'_> { fn enter_expression(&mut self, node: &ir::Expression) -> bool { if let ir::Expression::Identifier(identifier) = node { - let symbol = identifier.unparse(); - let resolution = if symbol == "_" && self.is_in_modifier_scope() { + let symbol = identifier.string_id; + let resolution = if self.interner.resolve(symbol) == "_" && self.is_in_modifier_scope() + { Resolution::BuiltIn(BuiltIn::ModifierUnderscore) } else { let scope_id = self.current_scope_id(); @@ -129,13 +130,13 @@ impl Visitor for Pass<'_> { } fn leave_hex_number_expression(&mut self, node: &ir::HexNumberExpression) { - let kind = Self::hex_number_literal_kind(node); + let kind = self.hex_number_literal_kind(node); let type_id = self.types.register_type(Type::Literal(kind)); self.binder.set_node_type(node.id(), Some(type_id)); } fn leave_decimal_number_expression(&mut self, node: &ir::DecimalNumberExpression) { - let type_ = if node.unit.is_none() && node.literal.unparse() == "0" { + let type_ = if node.unit.is_none() && node.literal.unparse(self.interner) == "0" { Type::Literal(LiteralKind::Zero) } else { Type::Literal(LiteralKind::DecimalInteger) @@ -147,7 +148,7 @@ impl Visitor for Pass<'_> { fn leave_string_expression(&mut self, node: &ir::StringExpression) { let type_id = self .types - .register_type(Self::type_of_string_expression(node)); + .register_type(self.type_of_string_expression(node)); let node_id = Self::string_expression_node_id(node); self.binder.set_node_type(node_id, Some(type_id)); } @@ -317,7 +318,7 @@ impl Visitor for Pass<'_> { // typing information of the operand expression let operand_typing = self.typing_of_expression(&node.operand); let resolution = self.filter_overriden_definitions( - self.resolve_symbol_in_typing(&operand_typing, node.member.unparse()), + self.resolve_symbol_in_typing(&operand_typing, node.member.string_id), ); // Special case: if the operand is either `this` or a contract/interface @@ -475,8 +476,10 @@ impl Visitor for Pass<'_> { fn enter_call_options_expression(&mut self, node: &ir::CallOptionsExpression) -> bool { for option in &node.options { let identifier = &option.name; - let resolution = - crate::built_ins::BuiltInsResolver::lookup_call_option(identifier.unparse()).into(); + let resolution = crate::built_ins::BuiltInsResolver::lookup_call_option( + self.interner.resolve(identifier.string_id), + ) + .into(); let reference = Reference::new(Rc::clone(identifier), resolution); self.binder.insert_reference(reference); } @@ -495,13 +498,13 @@ impl Visitor for Pass<'_> { let scope_id = self.current_scope_id(); let identifier = &items[0]; - let resolution = self.resolve_symbol_in_yul_scope(scope_id, identifier.unparse()); + let resolution = self.resolve_symbol_in_yul_scope(scope_id, identifier.string_id); let reference = Reference::new(Rc::clone(identifier), resolution.clone()); self.binder.insert_reference(reference); if items.len() > 1 { let suffix = &items[1]; - let resolution = self.resolve_yul_suffix(suffix.unparse(), &resolution); + let resolution = self.resolve_yul_suffix(suffix.string_id, &resolution); let reference = Reference::new(Rc::clone(suffix), resolution); self.binder.insert_reference(reference); } diff --git a/crates/solidity-v2/outputs/cargo/semantic/src/passes/tests.rs b/crates/solidity-v2/outputs/cargo/semantic/src/passes/tests.rs index 94f0d1fa43..a6cab5e271 100644 --- a/crates/solidity-v2/outputs/cargo/semantic/src/passes/tests.rs +++ b/crates/solidity-v2/outputs/cargo/semantic/src/passes/tests.rs @@ -1,41 +1,45 @@ +use std::collections::HashMap; + use anyhow::{anyhow, Result}; use slang_solidity_v2_common::versions::LanguageVersion; +use slang_solidity_v2_ir::interner::Interner; use slang_solidity_v2_ir::ir::{self, NodeId}; use slang_solidity_v2_parser::Parser; use crate::binder::{Binder, Resolution}; -use crate::context::SemanticFile; +use crate::context::{FileId, SemanticFile}; use crate::passes::{ p1_collect_definitions, p2_linearise_contracts, p3_type_definitions, p4_resolve_references, }; use crate::types::TypeRegistry; struct TestFile { - id: String, + file_id: FileId, ir_root: ir::SourceUnit, } impl SemanticFile for TestFile { - fn id(&self) -> &str { - &self.id + fn file_id(&self) -> FileId { + self.file_id } fn ir_root(&self) -> &ir::SourceUnit { &self.ir_root } - fn resolved_import_by_node_id(&self, _node_id: NodeId) -> Option<&String> { + fn resolved_import_by_node_id(&self, _node_id: NodeId) -> Option { None } } -fn build_file(name: &str, contents: &str) -> Result { +fn build_file(name: &str, contents: &str, interner: &mut Interner) -> Result { let version = LanguageVersion::V0_8_30; let source_unit_cst = Parser::parse(contents, version).map_err(|message| anyhow!(format!("{message:?}")))?; - let source_unit = ir::build(&source_unit_cst, &contents); + let source_unit = ir::build(&source_unit_cst, &contents, interner); + let file_id = interner.intern(name); Ok(TestFile { - id: name.to_string(), + file_id, ir_root: source_unit, }) } @@ -47,7 +51,8 @@ contract Base {} contract Test is Base layout at 0 {} "###; - let file = build_file("test.sol", CONTENTS)?; + let mut interner = Interner::new(); + let file = build_file("test.sol", CONTENTS, &mut interner)?; let files = [file]; let mut binder = Binder::default(); @@ -62,6 +67,109 @@ contract Test is Base layout at 0 {} Ok(()) } +fn get_contract_to_bases_map(binder: &Binder, interner: &Interner) -> HashMap> { + let mut contract_to_bases = HashMap::new(); + for (key, values) in binder.linearisations() { + let contract_name = binder + .find_definition_by_id(*key) + .unwrap() + .identifier() + .unparse(interner) + .to_string(); + + let base_names: Vec = values + .iter() + .map(|value| { + binder + .find_definition_by_id(*value) + .unwrap() + .identifier() + .unparse(interner) + .to_string() + }) + .collect(); + + contract_to_bases.insert(contract_name, base_names); + } + contract_to_bases +} + +#[test] +fn test_valid_linearisations() -> Result<()> { + const CONTENTS: &str = r#" +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.8.29; + +contract D is A, B {} +interface C {} +abstract contract B is C {} +interface A is C {} +"#; + + let mut interner = Interner::new(); + let file = build_file("test.sol", CONTENTS, &mut interner)?; + + let files = [file]; + let mut binder = Binder::default(); + p1_collect_definitions::run(&files, &mut binder); + p2_linearise_contracts::run(&files, &mut binder); + + let contract_to_bases = get_contract_to_bases_map(&binder, &interner); + + let mut expected = HashMap::new(); + expected.insert( + "D".to_string(), + vec![ + "D".to_string(), + "B".to_string(), + "A".to_string(), + "C".to_string(), + ], + ); + expected.insert("A".to_string(), vec!["A".to_string(), "C".to_string()]); + expected.insert("B".to_string(), vec!["B".to_string(), "C".to_string()]); + expected.insert("C".to_string(), vec!["C".to_string()]); + + assert_eq!(contract_to_bases, expected); + + Ok(()) +} + +#[test] +fn test_linearise_with_invalid_input() -> Result<()> { + const CONTENTS: &str = r#" +contract Base {} + +library Foo {} + +// Foo is an invalid base, but it shouldn't crash the linearisation pass +contract Test is Base, Foo { // Base should resolve to the contract, not the var + string Base; +} +"#; + + let mut interner = Interner::new(); + let file = build_file("test.sol", CONTENTS, &mut interner)?; + + let files = [file]; + let mut binder = Binder::default(); + p1_collect_definitions::run(&files, &mut binder); + p2_linearise_contracts::run(&files, &mut binder); + + let contract_to_bases = get_contract_to_bases_map(&binder, &interner); + + let mut expected = HashMap::new(); + expected.insert("Base".to_string(), vec!["Base".to_string()]); + expected.insert( + "Test".to_string(), + vec!["Test".to_string(), "Base".to_string()], + ); + + assert_eq!(contract_to_bases, expected); + + Ok(()) +} + #[test] fn test_type_definitions() -> Result<()> { const CONTENTS: &str = r###" @@ -89,7 +197,8 @@ contract Test is Base { } "###; - let file = build_file("test.sol", CONTENTS)?; + let mut interner = Interner::new(); + let file = build_file("test.sol", CONTENTS, &mut interner)?; let files = [file]; let mut binder = Binder::default(); @@ -99,7 +208,7 @@ contract Test is Base { p2_linearise_contracts::run(&files, &mut binder); let types_before = types.iter_types().count(); - p3_type_definitions::run(&files, &mut binder, &mut types); + p3_type_definitions::run(&files, &mut binder, &mut types, &interner); let types_after = types.iter_types().count(); // The pass registers new types for: contracts, mappings, structs, enums, @@ -143,7 +252,8 @@ contract Test is Base { } "###; - let file = build_file("test.sol", CONTENTS)?; + let mut interner = Interner::new(); + let file = build_file("test.sol", CONTENTS, &mut interner)?; let files = [file]; let mut binder = Binder::default(); @@ -152,8 +262,8 @@ contract Test is Base { p1_collect_definitions::run(&files, &mut binder); p2_linearise_contracts::run(&files, &mut binder); - p3_type_definitions::run(&files, &mut binder, &mut types); - p4_resolve_references::run(&files, &mut binder, &mut types, language_version); + p3_type_definitions::run(&files, &mut binder, &mut types, &interner); + p4_resolve_references::run(&files, &mut binder, &mut types, language_version, &interner); // Verify that references were created and most are resolved let references = binder.references(); @@ -163,12 +273,9 @@ contract Test is Base { .values() .filter(|r| matches!(r.resolution, Resolution::Unresolved)) .count(); - - // Some references may be unresolved (e.g. built-in types), but most should resolve - let resolved_count = references.len() - unresolved_count; - assert!( - resolved_count > 0, - "expected at least some resolved references" + assert_eq!( + 0, unresolved_count, + "expected all references to be resolved" ); Ok(()) diff --git a/crates/solidity-v2/outputs/cargo/semantic/src/types/registry.rs b/crates/solidity-v2/outputs/cargo/semantic/src/types/registry.rs index efa60a8a61..89d219f245 100644 --- a/crates/solidity-v2/outputs/cargo/semantic/src/types/registry.rs +++ b/crates/solidity-v2/outputs/cargo/semantic/src/types/registry.rs @@ -577,6 +577,24 @@ impl TypeRegistry { } }) } + + pub fn type_id_is_function_and_overrides( + &self, + type_id: TypeId, + other_type_id: TypeId, + ) -> bool { + if type_id == other_type_id { + return true; + } + let type_ = self.get_type_by_id(type_id); + let other_type = self.get_type_by_id(other_type_id); + match (type_, other_type) { + (Type::Function(ftype), Type::Function(other)) => { + self.function_type_overrides(ftype, other) + } + _ => false, + } + } } // Convenience accessors for pre-defined types diff --git a/crates/solidity-v2/outputs/cargo/slang_solidity/Cargo.toml b/crates/solidity-v2/outputs/cargo/slang_solidity/Cargo.toml index c0723748a6..8cc5c7364a 100644 --- a/crates/solidity-v2/outputs/cargo/slang_solidity/Cargo.toml +++ b/crates/solidity-v2/outputs/cargo/slang_solidity/Cargo.toml @@ -19,11 +19,15 @@ keywords = ["utilities"] categories = ["compilers", "utilities"] [dependencies] +slang_solidity_v2_ast = { workspace = true } slang_solidity_v2_common = { workspace = true } slang_solidity_v2_ir = { workspace = true } slang_solidity_v2_parser = { workspace = true } slang_solidity_v2_semantic = { workspace = true } thiserror = { workspace = true } +[dev-dependencies] +anyhow = { workspace = true } + [lints] workspace = true diff --git a/crates/solidity-v2/outputs/cargo/slang_solidity/src/compilation/builder.rs b/crates/solidity-v2/outputs/cargo/slang_solidity/src/compilation/builder.rs index 62a2035bcf..608dc8af5d 100644 --- a/crates/solidity-v2/outputs/cargo/slang_solidity/src/compilation/builder.rs +++ b/crates/solidity-v2/outputs/cargo/slang_solidity/src/compilation/builder.rs @@ -75,32 +75,35 @@ impl> CompilationBuilder { /// imported or not, to be able to query the definitions there. /// /// Adding a file that has already been added is a no-op. - pub fn add_file(&mut self, file_id: &str) -> Result<(), CompilationBuilderError> { - if !self.seen_files.insert(file_id.into()) { + pub fn add_file(&mut self, id: &str) -> Result<(), CompilationBuilderError> { + if !self.seen_files.insert(id.into()) { return Ok(()); } let source = self .config - .read_file(file_id) + .read_file(id) .map_err(|err| CompilationBuilderError::UserError(err))?; if let Some(source) = source { - let AddFileResponse { import_paths } = self + let AddFileResponse { + file_id, + import_paths, + } = self .internal - .add_file(file_id.into(), &source) + .add_file(id, &source) .map_err(|err| CompilationBuilderError::ParserError(err))?; for (node_id, import_path) in import_paths { let import_id = self .config - .resolve_import(file_id, &import_path) + .resolve_import(id, &import_path) .map_err(|err| CompilationBuilderError::UserError(err))?; if let Some(import_id) = &import_id { self.internal - .resolve_import(file_id, node_id, import_id.clone()) - .unwrap_or_else(|_| panic!("{file_id} should have been added")); + .resolve_import(file_id, node_id, import_id) + .unwrap_or_else(|_| panic!("{id} should have been added")); self.add_file(import_id)?; } } diff --git a/crates/solidity-v2/outputs/cargo/slang_solidity/src/compilation/file.rs b/crates/solidity-v2/outputs/cargo/slang_solidity/src/compilation/file.rs index 12a7db7dc5..5a5038467c 100644 --- a/crates/solidity-v2/outputs/cargo/slang_solidity/src/compilation/file.rs +++ b/crates/solidity-v2/outputs/cargo/slang_solidity/src/compilation/file.rs @@ -1,38 +1,45 @@ use std::collections::HashMap; use slang_solidity_v2_ir::ir::{self, NodeId}; -use slang_solidity_v2_semantic::context::SemanticFile; +use slang_solidity_v2_semantic::context::{FileId, SemanticFile}; +#[allow(clippy::struct_field_names)] pub struct File { id: String, + file_id: FileId, ir_root: ir::SourceUnit, - resolved_imports: HashMap, + resolved_imports: HashMap, } impl File { - pub(crate) fn new(id: String, ir_root: ir::SourceUnit) -> Self { + pub(crate) fn new(id: String, file_id: FileId, ir_root: ir::SourceUnit) -> Self { Self { id, + file_id, ir_root, resolved_imports: HashMap::new(), } } - pub(crate) fn add_resolved_import(&mut self, node_id: NodeId, target_file_id: String) { + pub(crate) fn add_resolved_import(&mut self, node_id: NodeId, target_file_id: FileId) { self.resolved_imports.insert(node_id, target_file_id); } + + pub fn id(&self) -> &str { + &self.id + } } impl SemanticFile for File { - fn id(&self) -> &str { - &self.id + fn file_id(&self) -> FileId { + self.file_id } fn ir_root(&self) -> &ir::SourceUnit { &self.ir_root } - fn resolved_import_by_node_id(&self, node_id: NodeId) -> Option<&String> { - self.resolved_imports.get(&node_id) + fn resolved_import_by_node_id(&self, node_id: NodeId) -> Option { + self.resolved_imports.get(&node_id).copied() } } diff --git a/crates/solidity-v2/outputs/cargo/slang_solidity/src/compilation/internal_builder.rs b/crates/solidity-v2/outputs/cargo/slang_solidity/src/compilation/internal_builder.rs index 6221c163ed..af65f493a4 100644 --- a/crates/solidity-v2/outputs/cargo/slang_solidity/src/compilation/internal_builder.rs +++ b/crates/solidity-v2/outputs/cargo/slang_solidity/src/compilation/internal_builder.rs @@ -2,9 +2,10 @@ use std::collections::BTreeMap; use std::rc::Rc; use slang_solidity_v2_common::versions::LanguageVersion; +use slang_solidity_v2_ir::interner::Interner; use slang_solidity_v2_ir::ir::{self, NodeId}; use slang_solidity_v2_parser::{Parser, ParserError}; -use slang_solidity_v2_semantic::context::SemanticContext; +use slang_solidity_v2_semantic::context::{FileId, SemanticContext}; use super::file::File; use super::unit::CompilationUnit; @@ -12,50 +13,61 @@ use super::unit::CompilationUnit; #[doc(hidden)] pub struct InternalCompilationBuilder { language_version: LanguageVersion, - files: BTreeMap, + interner: Interner, + files: BTreeMap, } impl InternalCompilationBuilder { pub fn create(language_version: LanguageVersion) -> Self { Self { language_version, + interner: Interner::new(), files: BTreeMap::new(), } } - pub fn add_file(&mut self, id: String, contents: &str) -> Result { - if self.files.contains_key(&id) { + pub fn add_file(&mut self, id: &str, contents: &str) -> Result { + let file_id = self.interner.intern(id); + if self.files.contains_key(&file_id) { // Already added. No need to process it again: return Ok(AddFileResponse { + file_id, import_paths: vec![], }); } let source_unit_cst = Parser::parse(contents, self.language_version)?; - let source_unit = ir::build(&source_unit_cst, &contents); - let import_paths = Self::extract_imports_path(&source_unit); + let source_unit = ir::build(&source_unit_cst, &contents, &mut self.interner); + let import_paths = self.extract_imports_path(&source_unit); - let file = File::new(id.clone(), source_unit); - self.files.insert(id, file); + let file = File::new(id.to_string(), file_id, source_unit); + self.files.insert(file_id, file); - Ok(AddFileResponse { import_paths }) + Ok(AddFileResponse { + file_id, + import_paths, + }) } pub fn resolve_import( &mut self, - source_file_id: &str, + source_file_id: FileId, node_id: NodeId, - destination_file_id: String, + destination_file: &str, ) -> Result<(), ResolveImportError> { self.files - .get_mut(source_file_id) - .ok_or_else(|| ResolveImportError::SourceFileNotFound(source_file_id.to_owned()))? - .add_resolved_import(node_id, destination_file_id); + .get_mut(&source_file_id) + .ok_or_else(|| { + ResolveImportError::SourceFileNotFound( + self.interner.resolve(source_file_id).to_owned(), + ) + })? + .add_resolved_import(node_id, self.interner.intern(destination_file)); Ok(()) } - fn extract_imports_path(source_unit: &ir::SourceUnit) -> Vec<(NodeId, String)> { + fn extract_imports_path(&self, source_unit: &ir::SourceUnit) -> Vec<(NodeId, String)> { let mut import_paths = Vec::new(); for member in &source_unit.members { @@ -63,12 +75,16 @@ impl InternalCompilationBuilder { continue; }; let (node_id, path) = match import_clause { - ir::ImportClause::PathImport(path_import) => { - (path_import.id(), path_import.path.unparse().to_owned()) - } + ir::ImportClause::PathImport(path_import) => ( + path_import.id(), + path_import.path.unparse(&self.interner).to_owned(), + ), ir::ImportClause::ImportDeconstruction(import_deconstruction) => ( import_deconstruction.id(), - import_deconstruction.path.unparse().to_owned(), + import_deconstruction + .path + .unparse(&self.interner) + .to_owned(), ), }; import_paths.push((node_id, path)); @@ -78,14 +94,16 @@ impl InternalCompilationBuilder { pub fn build(self) -> CompilationUnit { let files: Vec = self.files.into_values().collect(); - let semantic = SemanticContext::build_from(self.language_version, &files); + let interner = Rc::new(self.interner); + let semantic = SemanticContext::build_from(self.language_version, &files, &interner); - CompilationUnit::create(self.language_version, files, Rc::new(semantic)) + CompilationUnit::create(self.language_version, files, Rc::new(semantic), interner) } } #[doc(hidden)] pub struct AddFileResponse { + pub file_id: FileId, pub import_paths: Vec<(NodeId, String)>, } diff --git a/crates/solidity-v2/outputs/cargo/slang_solidity/src/compilation/unit.rs b/crates/solidity-v2/outputs/cargo/slang_solidity/src/compilation/unit.rs index d7f7770a21..46e92219e1 100644 --- a/crates/solidity-v2/outputs/cargo/slang_solidity/src/compilation/unit.rs +++ b/crates/solidity-v2/outputs/cargo/slang_solidity/src/compilation/unit.rs @@ -1,13 +1,16 @@ use std::collections::BTreeMap; use std::rc::Rc; +use slang_solidity_v2_ast::{abi, ast}; use slang_solidity_v2_common::versions::LanguageVersion; +use slang_solidity_v2_ir::interner::Interner; use slang_solidity_v2_semantic::context::{SemanticContext, SemanticFile}; use super::file::File; pub struct CompilationUnit { language_version: LanguageVersion, + interner: Rc, files: BTreeMap>, semantic: Rc, } @@ -17,13 +20,15 @@ impl CompilationUnit { language_version: LanguageVersion, files: Vec, semantic: Rc, + interner: Rc, ) -> Self { let files: BTreeMap> = files .into_iter() - .map(|file| (file.id().to_string(), Rc::new(file))) + .map(|file| (interner.resolve(file.file_id()).to_string(), Rc::new(file))) .collect(); Self { language_version, + interner, files, semantic, } @@ -44,7 +49,45 @@ impl CompilationUnit { self.files.get(id).cloned() } + pub fn interner(&self) -> &Interner { + &self.interner + } + + // TODO: this should be semi-public pub fn semantic(&self) -> &Rc { &self.semantic } + + pub fn get_file_ast_root(&self, file_id: &str) -> Option { + self.files + .get(file_id) + .map(|file| ast::create_source_unit(file.ir_root(), &self.semantic)) + } + + pub fn all_definitions(&self) -> impl Iterator + use<'_> { + self.semantic.all_definitions().map(|definition| { + ast::Definition::try_create(definition.node_id(), &self.semantic).unwrap() + }) + } + + pub fn all_references(&self) -> impl Iterator + use<'_> { + self.semantic.all_references().map(|reference| { + ast::Reference::try_create(&reference.identifier, &self.semantic).unwrap() + }) + } + + pub fn find_contract_by_name(self: &Rc, name: &str) -> Option { + self.semantic + .find_contract_by_name(name) + .map(|contract| ast::create_contract_definition(&contract, &self.semantic)) + } + + pub fn compute_contracts_abi(&self) -> Vec { + self.files + .values() + .flat_map(|file| { + ast::create_source_unit(file.ir_root(), &self.semantic).compute_contracts_abi() + }) + .collect() + } } diff --git a/crates/solidity-v2/outputs/cargo/slang_solidity/src/lib.rs b/crates/solidity-v2/outputs/cargo/slang_solidity/src/lib.rs index 8753047299..7def3bbcb8 100644 --- a/crates/solidity-v2/outputs/cargo/slang_solidity/src/lib.rs +++ b/crates/solidity-v2/outputs/cargo/slang_solidity/src/lib.rs @@ -1 +1,4 @@ pub mod compilation; + +#[cfg(test)] +mod tests; diff --git a/crates/solidity-v2/outputs/cargo/slang_solidity/src/tests/abi.rs b/crates/solidity-v2/outputs/cargo/slang_solidity/src/tests/abi.rs new file mode 100644 index 0000000000..5d4050fe3d --- /dev/null +++ b/crates/solidity-v2/outputs/cargo/slang_solidity/src/tests/abi.rs @@ -0,0 +1,281 @@ +use anyhow::Result; +use slang_solidity_v2_ast::abi::{AbiEntry, ParameterComponent}; + +use super::fixtures; + +#[test] +fn test_get_contracts_abi() -> Result<()> { + let unit = fixtures::Counter::build_compilation_unit()?; + + let contracts = unit.compute_contracts_abi(); + assert_eq!(1, contracts.len()); + assert_eq!("Counter", contracts[0].name); + assert_eq!("main.sol", contracts[0].file_id); + assert_eq!(7, contracts[0].entries.len()); + + let entries = &contracts[0].entries; + + assert!(matches!(entries[0], AbiEntry::Constructor { .. })); + assert!(matches!(entries[1], AbiEntry::Function { ref name, .. } if name == "click")); + assert!(matches!(entries[2], AbiEntry::Function { ref name, .. } if name == "count")); + assert!(matches!(entries[3], AbiEntry::Function { ref name, .. } if name == "disable")); + assert!(matches!(entries[4], AbiEntry::Function { ref name, .. } if name == "enable")); + assert!(matches!(entries[5], AbiEntry::Function { ref name, .. } if name == "increment")); + assert!(matches!(entries[6], AbiEntry::Function { ref name, .. } if name == "isEnabled")); + + Ok(()) +} + +macro_rules! assert_layout_item_eq { + ($item:expr, $name:expr, $slot:expr, $offset:expr, $type:expr) => { + assert_eq!($item.label, $name); + assert_eq!($item.r#type, $type); + assert_eq!($item.slot, $slot); + assert_eq!($item.offset, $offset); + }; +} + +#[test] +fn test_storage_layout() -> Result<()> { + let unit = fixtures::StorageLayout::build_compilation_unit()?; + + let counter = unit + .find_contract_by_name("C") + .expect("contract can be found"); + let counter_abi = counter + .compute_abi_with_file_id("main.sol".to_string()) + .expect("can compute ABI"); + let layout = &counter_abi.storage_layout; + + assert_eq!(layout.len(), 12); + + assert_layout_item_eq!(layout[0], "a", 0, 0, "uint256"); + assert_layout_item_eq!(layout[1], "e", 1, 0, "uint8[]"); + assert_layout_item_eq!(layout[2], "f", 2, 0, "mapping(uint256 => S)"); + assert_layout_item_eq!(layout[3], "g", 3, 0, "uint16"); + assert_layout_item_eq!(layout[4], "h", 3, 2, "uint16"); + assert_layout_item_eq!(layout[5], "s", 4, 0, "S"); + assert_layout_item_eq!(layout[6], "k", 5, 0, "int8"); + assert_layout_item_eq!(layout[7], "l", 5, 1, "bytes21"); + assert_layout_item_eq!(layout[8], "m", 6, 0, "uint8[10]"); + assert_layout_item_eq!(layout[9], "n", 7, 0, "bytes5[8]"); + assert_layout_item_eq!(layout[10], "t", 9, 0, "T[2]"); + assert_layout_item_eq!(layout[11], "o", 13, 0, "bytes5"); + + let transient_layout = &counter_abi.transient_storage_layout; + assert!(transient_layout.is_empty()); + + Ok(()) +} + +#[test] +fn test_transient_and_custom_storage_layout() -> Result<()> { + let unit = fixtures::StorageLayout::build_compilation_unit()?; + + let d_contract = unit + .find_contract_by_name("D") + .expect("contract can be found"); + let d_abi = d_contract + .compute_abi_with_file_id("main.sol".to_string()) + .expect("can compute ABI"); + let d_layout = &d_abi.storage_layout; + + assert_eq!(d_layout.len(), 2); + assert_layout_item_eq!(d_layout[0], "a", 42, 0, "uint256"); + assert_layout_item_eq!(d_layout[1], "p", 43, 0, "uint256"); + + let e_contract = unit + .find_contract_by_name("E") + .expect("contract can be found"); + let e_abi = e_contract + .compute_abi_with_file_id("main.sol".to_string()) + .expect("can compute ABI"); + let e_layout = &e_abi.storage_layout; + let e_transient_layout = &e_abi.transient_storage_layout; + + assert_eq!(e_layout.len(), 2); + assert_layout_item_eq!(e_layout[0], "q", 20, 0, "int8"); + assert_layout_item_eq!(e_layout[1], "r", 20, 1, "bytes5"); + + assert_eq!(e_transient_layout.len(), 2); + assert_layout_item_eq!(e_transient_layout[0], "qt", 0, 0, "int8"); + assert_layout_item_eq!(e_transient_layout[1], "rt", 0, 1, "bytes5"); + + Ok(()) +} + +#[test] +fn test_function_selector() -> Result<()> { + let unit = fixtures::Counter::build_compilation_unit()?; + + let counter = unit + .find_contract_by_name("Counter") + .expect("contract can be found"); + + let functions = counter.compute_linearised_functions(); + assert_eq!(functions.len(), 5); + + // all the functions in the contract are public + assert_eq!(functions[0].compute_selector(), Some(0x7d55_923d_u32)); // click() + assert_eq!(functions[1].compute_selector(), Some(0x2f27_70db_u32)); // disable() + assert_eq!(functions[2].compute_selector(), Some(0xa390_7d71_u32)); // enable() + assert_eq!(functions[3].compute_selector(), Some(0x7cf5_dab0_u32)); // increment(uint256) + assert_eq!(functions[4].compute_selector(), Some(0x6aa6_33b6_u32)); // isEnabled() + + let state_variables = counter.compute_linearised_state_variables(); + assert_eq!(state_variables.len(), 4); + + // for state variables, selectors only make sense for public getters + assert_eq!(state_variables[0].compute_selector(), None); // _owner + assert_eq!(state_variables[1].compute_selector(), None); // _state + assert_eq!(state_variables[2].compute_selector(), Some(0x0666_1abd_u32)); // count() + assert_eq!(state_variables[3].compute_selector(), None); // _clickers + + Ok(()) +} + +#[test] +fn test_full_abi_with_events_and_errors() -> Result<()> { + let unit = fixtures::FullAbi::build_compilation_unit()?; + + let contracts_abi = unit.compute_contracts_abi(); + assert_eq!(contracts_abi.len(), 1); + assert_eq!(contracts_abi[0].name, "Test"); + + let entries = &contracts_abi[0].entries; + assert_eq!(entries.len(), 9); + + assert!(matches!(entries[0], AbiEntry::Constructor { .. })); + assert!( + matches!(entries[1], AbiEntry::Error { ref name, .. } if name == "InsufficientBalance") + ); + assert!(matches!(entries[2], AbiEntry::Error { ref name, .. } if name == "SomethingWrong")); + assert!(matches!(entries[3], AbiEntry::Event { ref name, .. } if name == "BaseEvent")); + assert!(matches!(entries[4], AbiEntry::Event { ref name, .. } if name == "Event")); + assert!(matches!(entries[5], AbiEntry::Fallback { .. })); + assert!(matches!(entries[6], AbiEntry::Function { ref name, .. } if name == "b")); + assert!(matches!(entries[7], AbiEntry::Function { ref name, .. } if name == "foo")); + assert!(matches!(entries[8], AbiEntry::Receive { .. })); + + Ok(()) +} + +#[test] +fn test_abi_entries_with_tuples() -> Result<()> { + let unit = fixtures::AbiWithTuples::build_compilation_unit()?; + + let contracts_abi = unit.compute_contracts_abi(); + assert_eq!(contracts_abi.len(), 1); + assert_eq!(contracts_abi[0].name, "Test"); + + let entries = &contracts_abi[0].entries; + + let AbiEntry::Function { + name, + inputs, + outputs, + .. + } = &entries[0] + else { + panic!("expected ABI for function"); + }; + assert_eq!(name, "f"); + assert_eq!(inputs.len(), 3); + assert!(inputs[0].name.is_none()); + assert_eq!(inputs[0].r#type, "tuple"); + assert_eq!( + inputs[0].components, + vec![ + ParameterComponent { + name: "a".to_string(), + r#type: "uint256".to_string(), + components: Vec::new() + }, + ParameterComponent { + name: "b".to_string(), + r#type: "uint256[]".to_string(), + components: Vec::new() + }, + ParameterComponent { + name: "c".to_string(), + r#type: "tuple[]".to_string(), + components: vec![ + ParameterComponent { + name: "x".to_string(), + r#type: "uint256".to_string(), + components: Vec::new() + }, + ParameterComponent { + name: "y".to_string(), + r#type: "uint256".to_string(), + components: Vec::new() + }, + ] + }, + ] + ); + + assert!(inputs[1].name.is_none()); + assert_eq!(inputs[1].r#type, "tuple"); + assert_eq!( + inputs[1].components, + vec![ + ParameterComponent { + name: "x".to_string(), + r#type: "uint256".to_string(), + components: Vec::new() + }, + ParameterComponent { + name: "y".to_string(), + r#type: "uint256".to_string(), + components: Vec::new() + }, + ] + ); + + assert!(inputs[2].name.is_none()); + assert_eq!(inputs[2].r#type, "uint256"); + assert!(inputs[2].components.is_empty()); + assert!(outputs.is_empty()); + + let AbiEntry::Function { + name, + inputs, + outputs, + .. + } = &entries[1] + else { + panic!("expected ABI for function"); + }; + assert_eq!(name, "g"); + assert!(inputs.is_empty()); + assert_eq!(outputs.len(), 3); + assert!(outputs[0].name.is_none()); + assert_eq!(outputs[0].r#type, "tuple"); + assert_eq!(outputs[0].components.len(), 3); + assert!(outputs[1].name.is_none()); + assert_eq!(outputs[1].r#type, "tuple"); + assert_eq!(outputs[1].components.len(), 2); + assert!(outputs[2].name.is_none()); + assert_eq!(outputs[2].r#type, "uint256"); + assert!(outputs[2].components.is_empty()); + + Ok(()) +} + +#[test] +fn test_selectors_for_functions_with_tuple_parameters() -> Result<()> { + let unit = fixtures::AbiWithTuples::build_compilation_unit()?; + + let test = unit + .find_contract_by_name("Test") + .expect("contract is found"); + let functions = test.functions(); + + // f((uint256,uint256[],(uint256,uint256)[]),(uint256,uint256),uint256) + assert_eq!(functions[0].compute_selector(), Some(0x6f2b_e728_u32)); + // g() + assert_eq!(functions[1].compute_selector(), Some(0xe217_9b8e_u32)); + + Ok(()) +} diff --git a/crates/solidity-v2/outputs/cargo/slang_solidity/src/tests/ast.rs b/crates/solidity-v2/outputs/cargo/slang_solidity/src/tests/ast.rs new file mode 100644 index 0000000000..0de46cd03a --- /dev/null +++ b/crates/solidity-v2/outputs/cargo/slang_solidity/src/tests/ast.rs @@ -0,0 +1,415 @@ +use anyhow::Result; +use slang_solidity_v2_ast::ast::{self, ContractBase, ContractMember, Definition, FunctionKind}; + +use super::fixtures; + +#[derive(Default)] +struct IdentifierCounter { + total: usize, + definitions: usize, + references: usize, +} + +impl ast::visitor::Visitor for IdentifierCounter { + fn visit_identifier(&mut self, node: &ast::Identifier) { + if node.is_name_of_definition() { + self.definitions += 1; + } + if node.is_reference() { + self.references += 1; + } + self.total += 1; + } +} + +#[test] +fn test_ast_visitor() -> Result<()> { + let unit = fixtures::Counter::build_compilation_unit()?; + + let main_ast = unit.get_file_ast_root("main.sol").unwrap(); + + let mut main_visitor = IdentifierCounter::default(); + ast::visitor::accept_source_unit(&main_ast, &mut main_visitor); + + assert_eq!(main_visitor.total, 25); + assert_eq!(main_visitor.definitions, 9); + assert_eq!(main_visitor.references, 18); + + let ownable_ast = unit.get_file_ast_root("ownable.sol").unwrap(); + + let mut ownable_visitor = IdentifierCounter::default(); + ast::visitor::accept_source_unit(&ownable_ast, &mut ownable_visitor); + + assert_eq!(ownable_visitor.total, 11); + assert_eq!(ownable_visitor.definitions, 3); + assert_eq!(ownable_visitor.references, 8); + + let activatable_ast = unit.get_file_ast_root("activatable.sol").unwrap(); + + let mut activatable_visitor = IdentifierCounter::default(); + ast::visitor::accept_source_unit(&activatable_ast, &mut activatable_visitor); + + assert_eq!(activatable_visitor.total, 31); + assert_eq!(activatable_visitor.definitions, 10); + assert_eq!(activatable_visitor.references, 22); + + Ok(()) +} + +#[test] +fn test_identifier_path_resolve_to_immediate_definition() -> Result<()> { + let unit = fixtures::Counter::build_compilation_unit()?; + + let counter = unit + .find_contract_by_name("Counter") + .expect("contract is found"); + let counter_bases: Vec<_> = counter + .inheritance_types() + .iter() + .map(|base_type| base_type.type_name()) + .collect(); + assert_eq!(counter_bases.len(), 2); + + assert_eq!(counter_bases[0].name(), "Ownable"); + assert!(matches!( + counter_bases[0].resolve_to_definition(), + Some(ast::Definition::Contract(_)) + )); + assert!(matches!( + counter_bases[0].resolve_to_immediate_definition(), + Some(ast::Definition::ImportedSymbol(_)) + )); + + assert_eq!(counter_bases[1].name(), "Activatable"); + assert!(matches!( + counter_bases[1].resolve_to_definition(), + Some(ast::Definition::Contract(_)) + )); + assert!(matches!( + counter_bases[1].resolve_to_immediate_definition(), + Some(ast::Definition::ImportedSymbol(_)) + )); + + Ok(()) +} + +#[test] +fn test_identifier_path_resolve_to_immediate_resolves_to_direct_definition() -> Result<()> { + let unit = fixtures::ChainedImports::build_compilation_unit()?; + + let a1 = unit.find_contract_by_name("A1").expect("contract is found"); + let i1_typename = a1 + .inheritance_types() + .iter() + .next() + .expect("there is at least one inheritance type") + .type_name(); + assert_eq!(i1_typename.name(), "I1"); + let Some(i1) = i1_typename.resolve_to_definition() else { + panic!("i1 can be resolved"); + }; + let Some(i1_immediate) = i1_typename.resolve_to_immediate_definition() else { + panic!("i1 can be resolved immediately"); + }; + + assert!(matches!( + (i1, i1_immediate), + (ast::Definition::Interface(_), ast::Definition::Interface(_)) + )); + + Ok(()) +} + +#[test] +fn test_chained_imports_resolution() -> Result<()> { + let unit = fixtures::ChainedImports::build_compilation_unit()?; + + let a1 = unit.find_contract_by_name("A1").expect("contract is found"); + let b1_typename = a1 + .inheritance_types() + .iter() + .nth(1) + .expect("there are at least two inheritance types") + .type_name(); + assert_eq!(b1_typename.name(), "B1"); + + let b1 = b1_typename + .resolve_to_immediate_definition() + .expect("b1 base can be resolved"); + let ast::Definition::ImportedSymbol(b1_import) = b1 else { + panic!("b1 resolves to an import symbol"); + }; + + let b2 = b1_import + .name() + .resolve_to_immediate_definition() + .expect("b1 import can be resolved"); + let ast::Definition::ImportedSymbol(b2_import) = b2 else { + panic!("b2 resolves to an import symbol"); + }; + + let b3 = b2_import + .name() + .resolve_to_immediate_definition() + .expect("b2 import can be resolved"); + let ast::Definition::Contract(b3_contract) = b3 else { + panic!("b3 resolves to a contract"); + }; + assert_eq!(b3_contract.name().name(), "B3"); + + Ok(()) +} + +#[test] +fn test_get_type() -> Result<()> { + let unit = fixtures::Counter::build_compilation_unit()?; + + let ownable = unit + .find_contract_by_name("Ownable") + .expect("contract is found"); + + let state_variables = ownable + .members() + .iter() + .filter_map(|member| { + if let ast::ContractMember::StateVariableDefinition(definition) = member { + Some(definition) + } else { + None + } + }) + .collect::>(); + + assert_eq!(state_variables.len(), 1); + let owner = &state_variables[0]; + assert_eq!(owner.name().name(), "_owner"); + + let owner_type = owner + .get_type() + .expect("_owner state variable has resolved type"); + assert!(matches!(owner_type, ast::Type::Address(_))); + + Ok(()) +} + +#[test] +fn test_function_get_type() -> Result<()> { + let unit = fixtures::Counter::build_compilation_unit()?; + + let counter = unit + .find_contract_by_name("Counter") + .expect("contract is found"); + + let increment = counter + .members() + .iter() + .find_map(|member| { + if let ast::ContractMember::FunctionDefinition(function_definition) = member { + if function_definition + .name() + .is_some_and(|name| name.name() == "increment") + { + Some(function_definition) + } else { + None + } + } else { + None + } + }) + .expect("increment method is found"); + + let increment_type = increment.get_type().expect("increment method has a type"); + let ast::Type::Function(function_type) = increment_type else { + panic!("method's type is expected to be a function"); + }; + assert!(function_type.external()); + assert!(matches!(function_type.return_type(), ast::Type::Integer(_))); + assert!(function_type + .associated_definition() + .is_some_and(|definition| matches!(definition, ast::Definition::Function(_)))); + + Ok(()) +} + +#[test] +fn test_contract_direct_bases() -> Result<()> { + let unit = fixtures::Counter::build_compilation_unit()?; + + let counter = unit + .find_contract_by_name("Counter") + .expect("can find Counter contract"); + let bases = counter.direct_bases(); + assert_eq!(bases.len(), 2); + + let ContractBase::Contract(ownable) = &bases[0] else { + panic!("Base is not a contract"); + }; + assert_eq!(ownable.name().name(), "Ownable"); + let ContractBase::Contract(activatable) = &bases[1] else { + panic!("Base is not a contract"); + }; + assert_eq!(activatable.name().name(), "Activatable"); + + Ok(()) +} + +#[test] +fn test_contract_compute_linearised_bases() -> Result<()> { + let unit = fixtures::Counter::build_compilation_unit()?; + + let counter = unit + .find_contract_by_name("Counter") + .expect("can find Counter contract"); + let bases = counter.compute_linearised_bases(); + assert_eq!(bases.len(), 3); + + let ContractBase::Contract(counter) = &bases[0] else { + panic!("Base is not a contract"); + }; + assert_eq!(counter.name().name(), "Counter"); + let ContractBase::Contract(activatable) = &bases[1] else { + panic!("Base is not a contract"); + }; + assert_eq!(activatable.name().name(), "Activatable"); + let ContractBase::Contract(ownable) = &bases[2] else { + panic!("Base is not a contract"); + }; + assert_eq!(ownable.name().name(), "Ownable"); + + Ok(()) +} + +#[test] +fn test_definition_references() -> Result<()> { + let unit = fixtures::Counter::build_compilation_unit()?; + + let ownable = unit + .find_contract_by_name("Ownable") + .expect("can find Ownable contract"); + + // find the `onlyOwner` modifier defined in the `Ownable` contract + let only_owner = ownable + .members() + .iter() + .find_map(|member| { + let ContractMember::FunctionDefinition(function) = member else { + return None; + }; + if matches!(function.kind(), FunctionKind::Modifier) + && function + .name() + .is_some_and(|name| name.name() == "onlyOwner") + { + Some(function) + } else { + None + } + }) + .expect("can find onlyOwner modifier"); + + let references = only_owner.references(); + assert_eq!(references.len(), 3); + assert!(references.iter().all(|reference| reference + .resolve_to_definition() + .and_then(|definition| { + if let Definition::Modifier(modifier) = definition { + Some(modifier) + } else { + None + } + }) + .is_some_and(|modifier| modifier + .name() + .is_some_and(|name| name.name() == "onlyOwner")))); + + Ok(()) +} + +#[test] +fn test_contract_compute_linearised_state_variables() -> Result<()> { + let unit = fixtures::Counter::build_compilation_unit()?; + + let counter = unit + .find_contract_by_name("Counter") + .expect("can find Counter contract"); + + let state_variables = counter.compute_linearised_state_variables(); + assert_eq!(state_variables.len(), 4); + + assert_eq!(state_variables[0].name().name(), "_owner"); + assert_eq!(state_variables[1].name().name(), "_state"); + assert_eq!(state_variables[2].name().name(), "count"); + assert_eq!(state_variables[3].name().name(), "_clickers"); + + Ok(()) +} + +#[test] +fn test_contract_compute_linearised_functions() -> Result<()> { + let unit = fixtures::Counter::build_compilation_unit()?; + + let counter = unit + .find_contract_by_name("Counter") + .expect("can find Counter contract"); + + let functions = counter.compute_linearised_functions(); + assert_eq!(functions.len(), 5); + + assert!(functions[0] + .name() + .is_some_and(|name| name.name() == "click")); + assert!(functions[1] + .name() + .is_some_and(|name| name.name() == "disable")); + assert!(functions[2] + .name() + .is_some_and(|name| name.name() == "enable")); + assert!(functions[3] + .name() + .is_some_and(|name| name.name() == "increment")); + assert!(functions[4] + .name() + .is_some_and(|name| name.name() == "isEnabled")); + + Ok(()) +} + +#[test] +fn test_contract_constructor_and_modifiers() -> Result<()> { + let unit = fixtures::Counter::build_compilation_unit()?; + + let counter = unit + .find_contract_by_name("Counter") + .expect("can find Counter contract"); + + let constructor = counter.constructor(); + assert!(constructor.is_some()); + + let modifiers = counter.modifiers(); + assert_eq!(modifiers.len(), 0); + + Ok(()) +} + +#[test] +fn test_contract_compute_linearised_functions_with_overrides() -> Result<()> { + let unit = fixtures::Overrides::build_compilation_unit()?; + + let inherited = unit + .find_contract_by_name("Inherited") + .expect("can find contract"); + let functions = inherited.compute_linearised_functions(); + assert_eq!(functions.len(), 3); + assert!(functions[0] + .name() + .is_some_and(|name| name.name() == "in_base")); + assert!(functions[1] + .name() + .is_some_and(|name| name.name() == "in_middle")); + assert!(functions[2] + .name() + .is_some_and(|name| name.name() == "override_me")); + + Ok(()) +} diff --git a/crates/solidity-v2/outputs/cargo/slang_solidity/src/tests/fixtures/abi_with_tuples.rs b/crates/solidity-v2/outputs/cargo/slang_solidity/src/tests/fixtures/abi_with_tuples.rs new file mode 100644 index 0000000000..7029feb10e --- /dev/null +++ b/crates/solidity-v2/outputs/cargo/slang_solidity/src/tests/fixtures/abi_with_tuples.rs @@ -0,0 +1,13 @@ +use crate::define_fixture; + +define_fixture!( + AbiWithTuples, + file: "main.sol", r#" +contract Test { + struct S { uint a; uint[] b; T[] c; } + struct T { uint x; uint y; } + function f(S memory, T memory, uint) public pure {} + function g() public pure returns (S memory, T memory, uint) {} +} +"#, +); diff --git a/crates/solidity-v2/outputs/cargo/slang_solidity/src/tests/fixtures/chained_imports.rs b/crates/solidity-v2/outputs/cargo/slang_solidity/src/tests/fixtures/chained_imports.rs new file mode 100644 index 0000000000..8ca9eadbd0 --- /dev/null +++ b/crates/solidity-v2/outputs/cargo/slang_solidity/src/tests/fixtures/chained_imports.rs @@ -0,0 +1,16 @@ +use crate::define_fixture; + +define_fixture!( + ChainedImports, + file: "first.sol", r#" +import {B2 as B1} from "second.sol"; +interface I1 {} +contract A1 is I1, B1 {} +"#, + file: "second.sol", r#" +import {B3 as B2} from "third.sol"; +"#, + file: "third.sol", r#" +contract B3 {} +"#, +); diff --git a/crates/solidity-v2/outputs/cargo/slang_solidity/src/tests/fixtures/counter.rs b/crates/solidity-v2/outputs/cargo/slang_solidity/src/tests/fixtures/counter.rs new file mode 100644 index 0000000000..0ef3397317 --- /dev/null +++ b/crates/solidity-v2/outputs/cargo/slang_solidity/src/tests/fixtures/counter.rs @@ -0,0 +1,74 @@ +use crate::define_fixture; + +define_fixture!( + Counter, + file: "main.sol", r#" +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.8.29; + +import {Ownable} from "ownable.sol"; +import {Activatable} from "activatable.sol"; + +contract Counter is Ownable, Activatable { + uint public count; + mapping (address => uint) _clickers; + + constructor(uint initial) { + count = initial; + } + function increment(uint delta) public onlyOwner returns (uint) { + count += delta; + return count; + } + function click() public checkEnabled returns (uint) { + count += 1; + _clickers[msg.sender] += 1; + return _clickers[msg.sender]; + } +} +"#, + file: "ownable.sol", r#" +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.8.29; + +abstract contract Ownable { + address _owner; + constructor() { + _owner = msg.sender; + } + modifier onlyOwner() { + require(msg.sender == _owner, "Only owner allowed"); + _; + } +} +"#, + file: "activatable.sol", r#" +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.8.29; + +import {Ownable} from "ownable.sol"; + +abstract contract Activatable is Ownable { + enum State { DISABLED, ENABLED } + + State _state; + + constructor() { + _state = State.DISABLED; + } + function enable() public onlyOwner { + _state = State.ENABLED; + } + function disable() public onlyOwner { + _state = State.DISABLED; + } + function isEnabled() public view returns (bool) { + return _state == State.ENABLED; + } + modifier checkEnabled() { + require(_state == State.ENABLED, "Contract is disabled"); + _; + } +} +"#, +); diff --git a/crates/solidity-v2/outputs/cargo/slang_solidity/src/tests/fixtures/full_abi.rs b/crates/solidity-v2/outputs/cargo/slang_solidity/src/tests/fixtures/full_abi.rs new file mode 100644 index 0000000000..9565e42527 --- /dev/null +++ b/crates/solidity-v2/outputs/cargo/slang_solidity/src/tests/fixtures/full_abi.rs @@ -0,0 +1,24 @@ +use crate::define_fixture; + +define_fixture!( + FullAbi, + file: "main.sol", r#" +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.8; + +interface Base { + error SomethingWrong(string); + event BaseEvent(uint a, string m) anonymous; +} + +contract Test is Base { + bytes32 public b; + constructor() { b = hex"12345678901234567890123456789012"; } + event Event(uint indexed a, bytes32 b); + error InsufficientBalance(uint256 available, uint256 required); + function foo(uint a) public { emit Event(a, b); } + receive() external payable { } + fallback() external { } +} +"#, +); diff --git a/crates/solidity-v2/outputs/cargo/slang_solidity/src/tests/fixtures/mod.rs b/crates/solidity-v2/outputs/cargo/slang_solidity/src/tests/fixtures/mod.rs new file mode 100644 index 0000000000..93691a9257 --- /dev/null +++ b/crates/solidity-v2/outputs/cargo/slang_solidity/src/tests/fixtures/mod.rs @@ -0,0 +1,146 @@ +use std::rc::Rc; + +use anyhow::Result; +use slang_solidity_v2_common::versions::LanguageVersion; + +use crate::compilation::builder::{ + CompilationBuilder, CompilationBuilderConfig, CompilationBuilderError, +}; +use crate::compilation::unit::CompilationUnit; + +mod abi_with_tuples; +mod chained_imports; +mod counter; +mod full_abi; +mod overrides; +mod storage_layout; + +pub(super) use abi_with_tuples::AbiWithTuples; +pub(super) use chained_imports::ChainedImports; +pub(super) use counter::Counter; +pub(super) use full_abi::FullAbi; +pub(super) use overrides::Overrides; +pub(super) use storage_layout::StorageLayout; + +pub(super) struct FixtureFile<'a> { + id: &'a str, + contents: &'a str, +} + +#[macro_export] +macro_rules! define_fixture { + // Recursive case: consume one file definition + (@accum [$($acc:expr),*] ; $name:ident ; file : $k:literal, $v:literal $(, $($rest:tt)*)?) => { + define_fixture!( + @accum [$($acc,)* $crate::tests::fixtures::FixtureFile { id: $k, contents: $v }] ; + $name ; + $($($rest)*)?); + }; + + // Base case: emit the declaration + (@accum [$($acc:expr),*] ; $name:ident ;) => { + const FILES: &[$crate::tests::fixtures::FixtureFile<'_>] = &[$($acc),*]; + pub(crate) struct $name; + + impl $name { + pub(crate) fn build_compilation_unit( + ) -> anyhow::Result> { + $crate::tests::fixtures::build_compilation_unit_from_fixture(FILES) + } + } + }; + + // Entry point + ($name:ident, $($rest:tt)*) => { + define_fixture!(@accum [] ; $name ; $($rest)*); + }; +} + +struct FixtureBuildConfig<'a> { + files: &'a [FixtureFile<'a>], +} + +impl CompilationBuilderConfig for FixtureBuildConfig<'_> { + type Error = anyhow::Error; + + fn read_file(&mut self, file_id: &str) -> Result> { + Ok(self + .files + .iter() + .find(|file| file.id == file_id) + .map(|file| file.contents.to_owned())) + } + + fn resolve_import( + &mut self, + _source_file_id: &str, + import_path: &str, + ) -> Result> { + let path = import_path + .strip_prefix(|c: char| matches!(c, '"' | '\'')) + .and_then(|p| p.strip_suffix(|c: char| matches!(c, '"' | '\''))); + Ok(path.map(|p| p.to_owned())) + } +} + +pub(super) fn build_compilation_unit_from_fixture( + files: &[FixtureFile<'_>], +) -> Result> { + let version = LanguageVersion::V0_8_30; + let mut builder = CompilationBuilder::create(version, FixtureBuildConfig { files }); + + for file in files { + builder.add_file(file.id).map_err(|error| match error { + CompilationBuilderError::ParserError(error) => { + anyhow::anyhow!("Parser error: {error:?}") + } + CompilationBuilderError::UserError(error) => error, + })?; + } + + Ok(Rc::new(builder.build())) +} + +// Fixture build tests + +#[test] +fn test_build_abi_with_tuples_fixture() -> Result<()> { + let unit = AbiWithTuples::build_compilation_unit()?; + assert_eq!(1, unit.files().len()); + Ok(()) +} + +#[test] +fn test_build_chained_imports_fixture() -> Result<()> { + let unit = ChainedImports::build_compilation_unit()?; + assert_eq!(3, unit.files().len()); + Ok(()) +} + +#[test] +fn test_build_counter_fixture() -> Result<()> { + let unit = Counter::build_compilation_unit()?; + assert_eq!(3, unit.files().len()); + Ok(()) +} + +#[test] +fn test_build_full_abi_fixture() -> Result<()> { + let unit = FullAbi::build_compilation_unit()?; + assert_eq!(1, unit.files().len()); + Ok(()) +} + +#[test] +fn test_build_overrides_fixture() -> Result<()> { + let unit = Overrides::build_compilation_unit()?; + assert_eq!(1, unit.files().len()); + Ok(()) +} + +#[test] +fn test_build_storage_layout_fixture() -> Result<()> { + let unit = StorageLayout::build_compilation_unit()?; + assert_eq!(1, unit.files().len()); + Ok(()) +} diff --git a/crates/solidity-v2/outputs/cargo/slang_solidity/src/tests/fixtures/overrides.rs b/crates/solidity-v2/outputs/cargo/slang_solidity/src/tests/fixtures/overrides.rs new file mode 100644 index 0000000000..9f61d74424 --- /dev/null +++ b/crates/solidity-v2/outputs/cargo/slang_solidity/src/tests/fixtures/overrides.rs @@ -0,0 +1,25 @@ +use crate::define_fixture; + +define_fixture!( + Overrides, + file: "main.sol", r#" +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.8.29; + +contract Base +{ + function in_base() internal pure {} + function override_me() virtual external view {} +} + +contract Middle is Base { + function in_middle() external pure {} + function override_me() virtual override public view {} +} + +contract Inherited is Middle +{ + function override_me() override public pure {} +} +"#, +); diff --git a/crates/solidity-v2/outputs/cargo/slang_solidity/src/tests/fixtures/storage_layout.rs b/crates/solidity-v2/outputs/cargo/slang_solidity/src/tests/fixtures/storage_layout.rs new file mode 100644 index 0000000000..620eb5c3ff --- /dev/null +++ b/crates/solidity-v2/outputs/cargo/slang_solidity/src/tests/fixtures/storage_layout.rs @@ -0,0 +1,52 @@ +use crate::define_fixture; + +// Sample adapted from: https://docs.soliditylang.org/en/v0.8.33/internals/layout_in_storage.html#layout-of-state-variables-in-storage-and-transient-storage +define_fixture!( + StorageLayout, + file: "main.sol", r#" +struct S { + int32 x; + bool y; +} +struct T { + uint256 z; + uint32 w; +} + +contract A { + uint a; + uint constant c = 10; + uint immutable d = 12; +} + +contract B { + uint8[] e; + mapping(uint => S) f; + uint16 g; + uint16 h; + S s; + int8 k; +} + +contract C is A, B { + bytes21 l; + uint8[10] m; + bytes5[8] n; + T[2] t; + bytes5 o; +} + +contract D is A layout at 42 { + uint p; +} + +uint constant BASE = 5; + +contract E layout at BASE * 2 + 10 { + int8 q; + int8 transient qt; + bytes5 r; + bytes5 transient rt; +} +"#, +); diff --git a/crates/solidity-v2/outputs/cargo/slang_solidity/src/tests/mod.rs b/crates/solidity-v2/outputs/cargo/slang_solidity/src/tests/mod.rs new file mode 100644 index 0000000000..9d8c5e6202 --- /dev/null +++ b/crates/solidity-v2/outputs/cargo/slang_solidity/src/tests/mod.rs @@ -0,0 +1,4 @@ +mod abi; +mod ast; +mod fixtures; +mod unit; diff --git a/crates/solidity-v2/outputs/cargo/slang_solidity/src/tests/unit.rs b/crates/solidity-v2/outputs/cargo/slang_solidity/src/tests/unit.rs new file mode 100644 index 0000000000..47acf83006 --- /dev/null +++ b/crates/solidity-v2/outputs/cargo/slang_solidity/src/tests/unit.rs @@ -0,0 +1,92 @@ +use anyhow::Result; +use slang_solidity_v2_ast::ast::Definition; + +use super::fixtures; + +#[test] +fn test_get_file_ast_root() -> Result<()> { + let unit = fixtures::Counter::build_compilation_unit()?; + + assert_eq!(unit.files().len(), 3); + + let main_ast = unit + .get_file_ast_root("main.sol") + .expect("main.sol is a file of the compilation unit"); + let ownable_ast = unit + .get_file_ast_root("ownable.sol") + .expect("ownable.sol is a file in the compilation unit"); + let activatable_ast = unit + .get_file_ast_root("activatable.sol") + .expect("activatable.sol is a file in the compilation unit"); + + assert_eq!(main_ast.file_id(), "main.sol"); + assert_eq!(ownable_ast.file_id(), "ownable.sol"); + assert_eq!(activatable_ast.file_id(), "activatable.sol"); + + assert_eq!(main_ast.contracts().len(), 1); + assert_eq!(ownable_ast.contracts().len(), 1); + assert_eq!(activatable_ast.contracts().len(), 1); + + let main_contracts = main_ast.contracts(); + let counter_contract = main_contracts.first().unwrap(); + assert_eq!(counter_contract.name().name(), "Counter"); + assert_eq!(counter_contract.inheritance_types().iter().count(), 2); + + let counter_bases = counter_contract + .inheritance_types() + .iter() + .collect::>(); + + let Definition::Contract(ownable_contract) = counter_bases[0] + .type_name() + .resolve_to_definition() + .expect("Counter base is resolved") + else { + panic!("Counter base is a contract"); + }; + assert_eq!(ownable_contract.name().name(), "Ownable"); + + let Definition::Contract(activatable_contract) = counter_bases[1] + .type_name() + .resolve_to_definition() + .expect("Counter base is resolved") + else { + panic!("Counter base is a contract"); + }; + assert_eq!(activatable_contract.name().name(), "Activatable"); + + Ok(()) +} + +#[test] +fn test_get_all_definitions() -> Result<()> { + let unit = fixtures::Counter::build_compilation_unit()?; + + let count = unit.all_definitions().count(); + assert_eq!(count, 22); + + Ok(()) +} + +#[test] +fn test_find_contract_by_name() -> Result<()> { + let unit = fixtures::Counter::build_compilation_unit()?; + + let counter = unit + .find_contract_by_name("Counter") + .expect("Counter contract is found"); + let ownable = unit + .find_contract_by_name("Ownable") + .expect("Ownable contract is found"); + let activatable = unit + .find_contract_by_name("Activatable") + .expect("Activatable contract is found"); + + assert_eq!(counter.name().name(), "Counter"); + assert_eq!(ownable.name().name(), "Ownable"); + assert!(ownable.abstract_keyword()); + assert_eq!(activatable.name().name(), "Activatable"); + assert!(activatable.abstract_keyword()); + + Ok(()) +} diff --git a/crates/solidity-v2/outputs/cargo/tests/src/semantic/semantic_output/report.rs b/crates/solidity-v2/outputs/cargo/tests/src/semantic/semantic_output/report.rs index 1af0aa12c2..085b541641 100644 --- a/crates/solidity-v2/outputs/cargo/tests/src/semantic/semantic_output/report.rs +++ b/crates/solidity-v2/outputs/cargo/tests/src/semantic/semantic_output/report.rs @@ -7,7 +7,7 @@ use ariadne::{Color, Config, Label, Report, ReportBuilder, ReportKind, Source}; use slang_solidity_v2_ir::ir::NodeId; use slang_solidity_v2_parser::ParserError; use slang_solidity_v2_semantic::binder::Resolution; -use slang_solidity_v2_semantic::context::{SemanticContext, SemanticFile}; +use slang_solidity_v2_semantic::context::SemanticContext; use solidity_v2_testing_utils::reporting::diagnostic; use super::report_data::{ diff --git a/crates/solidity-v2/outputs/cargo/tests/src/semantic/semantic_output/report_data.rs b/crates/solidity-v2/outputs/cargo/tests/src/semantic/semantic_output/report_data.rs index 91fb6b9162..f4e301f9c5 100644 --- a/crates/solidity-v2/outputs/cargo/tests/src/semantic/semantic_output/report_data.rs +++ b/crates/solidity-v2/outputs/cargo/tests/src/semantic/semantic_output/report_data.rs @@ -3,6 +3,7 @@ use std::fmt::Display; use std::ops::Range; use slang_solidity_v2::compilation::unit::CompilationUnit; +use slang_solidity_v2_ir::interner::Interner; use slang_solidity_v2_ir::ir::visitor::{accept_source_unit, Visitor}; use slang_solidity_v2_ir::ir::{Identifier, NodeId}; use slang_solidity_v2_parser::ParserError; @@ -84,6 +85,7 @@ impl<'a> ReportData<'a> { struct IdentifierCollector<'a> { identifiers: Vec, + interner: &'a Interner, current_file: Option<(&'a String, &'a String)>, } @@ -94,7 +96,7 @@ impl Visitor for IdentifierCollector<'_> { file_id: self.current_file_id(), node_id: node.id(), range: node.range.clone(), - text: node.text.clone(), + text: node.unparse(self.interner).to_owned(), line, column, }); @@ -140,6 +142,7 @@ fn collect_all_identifiers( ) -> Vec { let mut collector = IdentifierCollector { identifiers: Vec::new(), + interner: compilation.interner(), current_file: None, }; @@ -421,8 +424,8 @@ impl CollectedDefinitionDisplay<'_> { .find_definition_by_id(definition_id) .unwrap() .identifier() - .text - .clone() + .unparse(self.semantic.interner()) + .to_string() } } diff --git a/crates/solidity/testing/perf/cargo/src/tests/slang_v2/ir_builder.rs b/crates/solidity/testing/perf/cargo/src/tests/slang_v2/ir_builder.rs index da667b3eb2..33fa4fc0ca 100644 --- a/crates/solidity/testing/perf/cargo/src/tests/slang_v2/ir_builder.rs +++ b/crates/solidity/testing/perf/cargo/src/tests/slang_v2/ir_builder.rs @@ -1,4 +1,5 @@ use slang_solidity_v2_cst::structured_cst::nodes::SourceUnit as InputSourceUnit; +use slang_solidity_v2_ir::interner::Interner; use slang_solidity_v2_ir::ir::{self, SourceUnit, SourceUnitMember}; use crate::dataset::SolidityProject; @@ -17,6 +18,7 @@ pub fn test( project: &'static SolidityProject, sources: Vec<(String, InputSourceUnit)>, ) -> Vec { + let mut interner = Interner::new(); let mut ir_source_units = Vec::new(); for (name, source) in sources { ir_source_units.push(ir::build( @@ -25,6 +27,7 @@ pub fn test( .sources .get(&name) .expect("Source not found in project"), + &mut interner, )); } ir_source_units