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); } }