ldmc/src/struct_layout.rs

168 lines
5.1 KiB
Rust
Raw Normal View History

2025-03-24 10:14:25 +01:00
use laddertypes::{parser::*, unparser::*, SugaredStructMember, SugaredTypeTerm, TypeDict, TypeTerm};
#[derive(Clone, Copy, Debug)]
pub enum ObjectSize {
Static(u64),
Dynamic(/* function to get size at runtime */),
Unknown
}
pub fn get_type_size( dict: &mut impl TypeDict, ty: TypeTerm ) -> ObjectSize {
let ty = ty.clone().get_lnf_vec().last().unwrap().clone();
if ty == dict.parse("native.UInt8").expect("") {
return ObjectSize::Static(1);
}
if ty == dict.parse("native.UInt16").expect("") {
return ObjectSize::Static(2);
}
if ty == dict.parse("native.UInt32").expect("") ||
ty == dict.parse("native.Float").expect("") {
return ObjectSize::Static(4);
}
if ty == dict.parse("native.UInt64").expect("") ||
ty == dict.parse("native.Double").expect("") {
return ObjectSize::Static(8);
}
if let Some(layout) = StructLayout::parse( dict, ty ) {
return layout.get_size();
}
ObjectSize::Unknown
}
#[derive(Clone, Copy, Debug, PartialEq)]
enum LayoutType {
Natural,
Packed
}
#[derive(Clone, Debug)]
pub struct StructLayout {
ty: laddertypes::TypeTerm,
item_type: laddertypes::TypeTerm,
pub members: Vec< (String, laddertypes::TypeTerm) >,
offsets: std::collections::HashMap< String, u64 >,
size: ObjectSize
}
impl StructLayout {
pub fn get_type(&self) -> TypeTerm {
self.ty.clone()
}
pub fn get_size(&self) -> ObjectSize {
self.size
}
pub fn get_offset(&self, name: &String) -> u64 {
*self.offsets.get(name).expect("")
}
pub fn calculate_offsets(&mut self, dict: &mut impl TypeDict) {
let layout_type = LayoutType::Natural;
let mut offset = 0;
for (field_name, field_type) in self.members.iter() {
//let field_c_type = crate::c_gen::get_c_repr_type(dict, field_type.clone(), true).expect("cant get c-repr for struct field");
match get_type_size( dict, field_type.clone() ) {
ObjectSize::Static(field_size) => {
if layout_type == LayoutType::Natural {
// add padding to natural alignment
if offset % field_size > 0 {
offset = field_size * ((offset / field_size)+1);
}
}
// take offset
self.offsets.insert(field_name.clone(), offset);
// advance by current size
offset += field_size;
}
ObjectSize::Dynamic() => {
eprintln!("dynamically sized Field in struct!");
self.offsets.insert(field_name.clone(), offset);
self.size = ObjectSize::Dynamic();
return;
}
ObjectSize::Unknown => {
eprintln!("unknown field size!");
self.offsets.insert(field_name.clone(), offset);
self.size = ObjectSize::Unknown;
return;
}
}
}
match self.size {
ObjectSize::Dynamic() => {
}
_ => {
self.size = ObjectSize::Static(offset);
}
}
}
pub fn generate_members(&self, dict: &mut impl TypeDict, prefix: &str, base_ptr: &str) {
let mut offset = 0;
for (field_name, field_type) in self.members.iter() {
let field_c_type = crate::c_gen::get_c_repr_type(dict, field_type.clone(), true).expect("cant get c-repr for struct field");
let offset = self.get_offset(field_name);
println!(" {} * restrict {}_{} = {} + {};",
field_c_type, prefix, field_name, base_ptr, offset
);
}
}
pub fn parse(dict: &mut impl TypeDict, struct_type: TypeTerm) -> Option <Self> {
match struct_type.sugar(dict) {
SugaredTypeTerm::Struct(sugared_members) => {
let mut members = Vec::new();
let mut item_type = dict.parse("Byte").expect("");
for SugaredStructMember{ symbol, ty } in sugared_members {
members.push((symbol, ty.desugar(dict)));
}
let mut sl = StructLayout {
ty: TypeTerm::unit(),
item_type,
members,
offsets: std::collections::HashMap::new(),
size: ObjectSize::Unknown
};
sl.calculate_offsets(dict);
sl.calculate_type(dict);
Some(sl)
}
_ => {
eprintln!("not a struct");
None
}
}
}
fn calculate_type(&mut self, dict: &mut impl TypeDict) {
self.ty =
SugaredTypeTerm::Struct(
self.members
.iter()
.cloned()
.map(|(symbol,ty)|
SugaredStructMember{ symbol, ty:ty.sugar(dict) })
.collect()
)
.desugar(dict);
}
}