use super::{Function, FunctionId, MirType};
use solar_data_structures::{
fmt::{self, FmtIteratorExt},
index::IndexVec,
};
use solar_interface::Ident;
pub const IMMUTABLE_WORD_SIZE: usize = 32;
#[derive(Clone, Debug)]
pub struct Module {
pub name: Ident,
pub functions: IndexVec<FunctionId, Function>,
pub data_segments: Vec<DataSegment>,
pub storage_layout: Vec<StorageSlot>,
pub immutables: Vec<ImmutableSlot>,
pub is_interface: bool,
}
impl Module {
#[must_use]
pub fn new(name: Ident) -> Self {
Self {
name,
functions: IndexVec::new(),
data_segments: Vec::new(),
storage_layout: Vec::new(),
immutables: Vec::new(),
is_interface: false,
}
}
pub fn add_function(&mut self, function: Function) -> FunctionId {
self.functions.push(function)
}
#[must_use]
pub fn function(&self, id: FunctionId) -> &Function {
&self.functions[id]
}
pub fn function_mut(&mut self, id: FunctionId) -> &mut Function {
&mut self.functions[id]
}
pub fn add_data_segment(&mut self, data: Vec<u8>) -> usize {
let index = self.data_segments.len();
self.data_segments.push(DataSegment { data });
index
}
pub fn add_storage_slot(&mut self, slot: StorageSlot) -> usize {
let index = self.storage_layout.len();
self.storage_layout.push(slot);
index
}
pub fn add_immutable_slot(&mut self, slot: ImmutableSlot) -> usize {
let index = self.immutables.len();
self.immutables.push(slot);
index
}
#[must_use]
pub fn immutable_data_len(&self) -> usize {
self.immutables.len() * IMMUTABLE_WORD_SIZE
}
pub fn iter_functions(&self) -> impl Iterator<Item = (FunctionId, &Function)> {
self.functions.iter_enumerated()
}
pub fn to_text(&self) -> impl fmt::Display + '_ {
fmt::from_fn(move |f| {
writeln!(f, "; module @{}", self.name)?;
write!(
f,
"{}",
self.functions.iter().map(super::display::display_function_text).format("\n")
)
})
}
pub fn to_dot(&self) -> impl fmt::Display + '_ {
fmt::from_fn(move |f| {
write!(
f,
"{}",
self.functions.iter().map(super::display::display_function_dot).format("\n\n")
)
})
}
}
#[derive(Clone, Debug)]
pub struct DataSegment {
pub data: Vec<u8>,
}
#[derive(Clone, Debug)]
pub struct StorageSlot {
pub slot: u64,
pub offset: u8,
pub ty: MirType,
pub name: Option<Ident>,
}
#[derive(Clone, Debug)]
pub struct ImmutableSlot {
pub offset: u32,
pub ty: MirType,
pub name: Option<Ident>,
}
impl StorageSlot {
#[must_use]
pub fn new(slot: u64, ty: MirType) -> Self {
Self { slot, offset: 0, ty, name: None }
}
#[must_use]
pub fn with_offset(slot: u64, offset: u8, ty: MirType) -> Self {
Self { slot, offset, ty, name: None }
}
}
impl fmt::Display for Module {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
writeln!(f, "module {} {{", self.name)?;
if !self.storage_layout.is_empty() {
writeln!(f, " storage:")?;
for slot in &self.storage_layout {
writeln!(f, " slot {} @ {}: {}", slot.slot, slot.offset, slot.ty)?;
}
writeln!(f)?;
}
for (id, func) in self.functions.iter_enumerated() {
writeln!(f, " ; function {}", id.index())?;
writeln!(f, " {func}")?;
}
writeln!(f, "}}")
}
}