Skip to content

Commit

Permalink
Refactor Fuel JSON ABI generation into its own module. (FuelLabs#3911)
Browse files Browse the repository at this point in the history
This PR refactors the current JSON ABI generation code to be inside a
single module, instead of it being spread out all over the place.

Main reason is for an upcoming addition of JSON ABI generation following
the Solidity ABI for EVM.

---------

Co-authored-by: Mohammad Fawaz <[email protected]>
  • Loading branch information
tritao and mohammadfawaz authored Jan 27, 2023
1 parent 7074632 commit d733408
Show file tree
Hide file tree
Showing 11 changed files with 735 additions and 729 deletions.
5 changes: 3 additions & 2 deletions forc-pkg/src/pkg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ use std::{
str::FromStr,
};
use sway_core::{
abi_generation::generate_json_abi_program,
asm_generation::ProgramABI,
decl_engine::{DeclEngine, DeclId},
fuel_prelude::{
Expand All @@ -36,7 +37,7 @@ use sway_core::{
language::{
lexed::LexedProgram,
parsed::{ParseProgram, TreeType},
ty,
ty::{self},
},
semantic_analysis::namespace,
source_map::SourceMap,
Expand Down Expand Up @@ -2523,7 +2524,7 @@ pub fn compile(
let mut types = vec![];
ProgramABI::Fuel(time_expr!(
"generate JSON ABI program",
typed_program.generate_json_abi_program(engines.te(), &mut types)
generate_json_abi_program(typed_program, engines.te(), &mut types)
))
}
BuildTarget::EVM => match &asm_res.value {
Expand Down
714 changes: 714 additions & 0 deletions sway-core/src/abi_generation/fuel_json_abi.rs

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions sway-core/src/abi_generation/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
mod fuel_json_abi;
pub use fuel_json_abi::*;
76 changes: 0 additions & 76 deletions sway-core/src/language/ty/declaration/function.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,6 @@ use crate::{
type_system::*,
};

use fuel_abi_types::program_abi;

use sway_types::{
constants::{INLINE_ALWAYS_NAME, INLINE_NEVER_NAME},
Ident, Span, Spanned,
Expand Down Expand Up @@ -297,80 +295,6 @@ impl TyFunctionDeclaration {
)
}

pub(crate) fn generate_json_abi_function(
&self,
type_engine: &TypeEngine,
types: &mut Vec<program_abi::TypeDeclaration>,
) -> program_abi::ABIFunction {
// A list of all `program_abi::TypeDeclaration`s needed for inputs
let input_types = self
.parameters
.iter()
.map(|x| program_abi::TypeDeclaration {
type_id: x.initial_type_id.index(),
type_field: x.initial_type_id.get_json_type_str(type_engine, x.type_id),
components: x.initial_type_id.get_json_type_components(
type_engine,
types,
x.type_id,
),
type_parameters: x
.type_id
.get_json_type_parameters(type_engine, types, x.type_id),
})
.collect::<Vec<_>>();

// The single `program_abi::TypeDeclaration` needed for the output
let output_type = program_abi::TypeDeclaration {
type_id: self.initial_return_type.index(),
type_field: self
.initial_return_type
.get_json_type_str(type_engine, self.return_type),
components: self.return_type.get_json_type_components(
type_engine,
types,
self.return_type,
),
type_parameters: self.return_type.get_json_type_parameters(
type_engine,
types,
self.return_type,
),
};

// Add the new types to `types`
types.extend(input_types);
types.push(output_type);

// Generate the JSON data for the function
program_abi::ABIFunction {
name: self.name.as_str().to_string(),
inputs: self
.parameters
.iter()
.map(|x| program_abi::TypeApplication {
name: x.name.to_string(),
type_id: x.initial_type_id.index(),
type_arguments: x.initial_type_id.get_json_type_arguments(
type_engine,
types,
x.type_id,
),
})
.collect(),
output: program_abi::TypeApplication {
name: "".to_string(),
type_id: self.initial_return_type.index(),
type_arguments: self.initial_return_type.get_json_type_arguments(
type_engine,
types,
self.return_type,
),
},
attributes: transform::generate_json_abi_attributes_map(&self.attributes),
}
}

/// Whether or not this function is the default entry point.
pub fn is_main_entry(&self) -> bool {
// NOTE: We may want to make this check more sophisticated or customisable in the future,
Expand Down
197 changes: 15 additions & 182 deletions sway-core/src/language/ty/program.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,6 @@ use crate::{
use sway_error::error::CompileError;
use sway_types::*;

use fuel_abi_types::program_abi;

#[derive(Debug, Clone)]
pub struct TyProgram {
pub kind: TyProgramKind,
Expand Down Expand Up @@ -304,9 +302,22 @@ impl TyProgram {
)
}

/// All test function declarations within the program.
pub fn test_fns<'a: 'b, 'b>(
&'b self,
decl_engine: &'a DeclEngine,
) -> impl '_ + Iterator<Item = (TyFunctionDeclaration, DeclId)> {
self.root
.submodules_recursive()
.flat_map(|(_, submod)| submod.module.test_fns(decl_engine))
.chain(self.root.test_fns(decl_engine))
}
}

impl CollectTypesMetadata for TyProgram {
/// Collect various type information such as unresolved types and types of logged data
pub(crate) fn collect_types_metadata(
&mut self,
fn collect_types_metadata(
&self,
ctx: &mut CollectTypesMetadataContext,
) -> CompileResult<Vec<TypeMetadata>> {
let mut warnings = vec![];
Expand Down Expand Up @@ -419,184 +430,6 @@ impl TyProgram {
err(warnings, errors)
}
}

pub fn generate_json_abi_program(
&self,
type_engine: &TypeEngine,
types: &mut Vec<program_abi::TypeDeclaration>,
) -> program_abi::ProgramABI {
match &self.kind {
TyProgramKind::Contract { abi_entries, .. } => {
let functions = abi_entries
.iter()
.map(|x| x.generate_json_abi_function(type_engine, types))
.collect();
let logged_types = self.generate_json_logged_types(type_engine, types);
let messages_types = self.generate_json_messages_types(type_engine, types);
let configurables = self.generate_json_configurables(type_engine, types);
program_abi::ProgramABI {
types: types.to_vec(),
functions,
logged_types: Some(logged_types),
messages_types: Some(messages_types),
configurables: Some(configurables),
}
}
TyProgramKind::Script { main_function, .. }
| TyProgramKind::Predicate { main_function, .. } => {
let functions = vec![main_function.generate_json_abi_function(type_engine, types)];
let logged_types = self.generate_json_logged_types(type_engine, types);
let messages_types = self.generate_json_messages_types(type_engine, types);
let configurables = self.generate_json_configurables(type_engine, types);
program_abi::ProgramABI {
types: types.to_vec(),
functions,
logged_types: Some(logged_types),
messages_types: Some(messages_types),
configurables: Some(configurables),
}
}
_ => program_abi::ProgramABI {
types: vec![],
functions: vec![],
logged_types: None,
messages_types: None,
configurables: None,
},
}
}

fn generate_json_logged_types(
&self,
type_engine: &TypeEngine,
types: &mut Vec<program_abi::TypeDeclaration>,
) -> Vec<program_abi::LoggedType> {
// A list of all `program_abi::TypeDeclaration`s needed for the logged types
let logged_types = self
.logged_types
.iter()
.map(|(_, type_id)| program_abi::TypeDeclaration {
type_id: type_id.index(),
type_field: type_id.get_json_type_str(type_engine, *type_id),
components: type_id.get_json_type_components(type_engine, types, *type_id),
type_parameters: type_id.get_json_type_parameters(type_engine, types, *type_id),
})
.collect::<Vec<_>>();

// Add the new types to `types`
types.extend(logged_types);

// Generate the JSON data for the logged types
self.logged_types
.iter()
.map(|(log_id, type_id)| program_abi::LoggedType {
log_id: **log_id as u64,
application: program_abi::TypeApplication {
name: "".to_string(),
type_id: type_id.index(),
type_arguments: type_id.get_json_type_arguments(type_engine, types, *type_id),
},
})
.collect()
}

fn generate_json_messages_types(
&self,
type_engine: &TypeEngine,
types: &mut Vec<program_abi::TypeDeclaration>,
) -> Vec<program_abi::MessageType> {
// A list of all `program_abi::TypeDeclaration`s needed for the messages types
let messages_types = self
.messages_types
.iter()
.map(|(_, type_id)| program_abi::TypeDeclaration {
type_id: type_id.index(),
type_field: type_id.get_json_type_str(type_engine, *type_id),
components: type_id.get_json_type_components(type_engine, types, *type_id),
type_parameters: type_id.get_json_type_parameters(type_engine, types, *type_id),
})
.collect::<Vec<_>>();

// Add the new types to `types`
types.extend(messages_types);

// Generate the JSON data for the messages types
self.messages_types
.iter()
.map(|(message_id, type_id)| program_abi::MessageType {
message_id: **message_id as u64,
application: program_abi::TypeApplication {
name: "".to_string(),
type_id: type_id.index(),
type_arguments: type_id.get_json_type_arguments(type_engine, types, *type_id),
},
})
.collect()
}

fn generate_json_configurables(
&self,
type_engine: &TypeEngine,
types: &mut Vec<program_abi::TypeDeclaration>,
) -> Vec<program_abi::Configurable> {
// A list of all `program_abi::TypeDeclaration`s needed for the configurables types
let configurables_types = self
.configurables
.iter()
.map(
|TyConstantDeclaration { return_type, .. }| program_abi::TypeDeclaration {
type_id: return_type.index(),
type_field: return_type.get_json_type_str(type_engine, *return_type),
components: return_type.get_json_type_components(
type_engine,
types,
*return_type,
),
type_parameters: return_type.get_json_type_parameters(
type_engine,
types,
*return_type,
),
},
)
.collect::<Vec<_>>();

// Add the new types to `types`
types.extend(configurables_types);

// Generate the JSON data for the configurables types
self.configurables
.iter()
.map(
|TyConstantDeclaration {
name, return_type, ..
}| program_abi::Configurable {
name: name.to_string(),
application: program_abi::TypeApplication {
name: "".to_string(),
type_id: return_type.index(),
type_arguments: return_type.get_json_type_arguments(
type_engine,
types,
*return_type,
),
},
offset: 0,
},
)
.collect()
}

/// All test function declarations within the program.
pub fn test_fns<'a: 'b, 'b>(
&'b self,
decl_engine: &'a DeclEngine,
) -> impl '_ + Iterator<Item = (TyFunctionDeclaration, DeclId)> {
self.root
.submodules_recursive()
.flat_map(|(_, submod)| submod.module.test_fns(decl_engine))
.chain(self.root.test_fns(decl_engine))
}
}

#[derive(Clone, Debug)]
Expand Down
1 change: 1 addition & 0 deletions sway-core/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#[macro_use]
pub mod error;

pub mod abi_generation;
pub mod asm_generation;
mod asm_lang;
mod build_config;
Expand Down
22 changes: 0 additions & 22 deletions sway-core/src/transform/attribute.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,6 @@
use sway_types::{Ident, Span};

use fuel_abi_types::program_abi;

use std::{collections::HashMap, sync::Arc};

/// An attribute has a name (i.e "doc", "storage"),
Expand Down Expand Up @@ -81,23 +79,3 @@ impl std::ops::Deref for AttributesMap {
&self.0
}
}

pub(crate) fn generate_json_abi_attributes_map(
attr_map: &AttributesMap,
) -> Option<Vec<program_abi::Attribute>> {
if attr_map.is_empty() {
None
} else {
Some(
attr_map
.iter()
.flat_map(|(_attr_kind, attrs)| {
attrs.iter().map(|attr| program_abi::Attribute {
name: attr.name.to_string(),
arguments: attr.args.iter().map(|arg| arg.to_string()).collect(),
})
})
.collect(),
)
}
}
Loading

0 comments on commit d733408

Please sign in to comment.