diff --git a/src/c_gen.rs b/src/c_gen.rs index ac68a93..7f5c7ea 100644 --- a/src/c_gen.rs +++ b/src/c_gen.rs @@ -1,6 +1,6 @@ use { - laddertypes::{TypeDict, TypeTerm, parser::*, unparser::*, morphism::{Morphism, MorphismInstance}}, - crate::morphism::{LdmcPrimCMorphism, LdmcMorphism} + crate::{morphism::{LdmcMorphism, LdmcPrimCMorphism}, struct_layout::{get_type_size, ObjectSize, StructLayout}}, + laddertypes::{morphism::{Morphism, MorphismInstance}, parser::*, unparser::*, TypeDict, TypeTerm}, }; /* @@ -85,7 +85,23 @@ pub fn get_c_repr_type(dict: &mut impl TypeDict, t: laddertypes::TypeTerm, skip_ } } else { - None + + if let Some(layout) = StructLayout::parse(dict, t.clone()) { + let mut c_type = String::from("struct {\n"); + + for (field_name, field_type) in layout.members.iter() { + let field_c_type = get_c_repr_type(dict, field_type.clone(), false).expect(""); + c_type.push_str(&format!(" {} {};\n", + field_c_type, + field_name + )); + } + + c_type.push_str("}"); + Some(c_type) + } else { + None + } } } @@ -205,14 +221,17 @@ morph {} ---> {}, subst σ = {:?}, halo Ψ = {} -*/"#, +*/ +{} +"#, type_dict.unparse(&morph_inst.get_type().dst_type.param_normalize().decurry()), type_dict.unparse(&morph_inst.m.get_type().src_type), type_dict.unparse(&morph_inst.m.get_type().dst_type), morph_inst.σ, type_dict.unparse(&morph_inst.halo), + morph_inst.m.generate_call(type_dict, &morph_inst.σ, i) ); - morph_inst.m.generate_call(type_dict, &morph_inst.σ, i); + i += 1; } @@ -322,7 +341,42 @@ int {} ( {} const * restrict src, {} * restrict dst ) {{ } impl LdmcMorphism { - pub fn generate_call(&self, dict: &mut impl TypeDict, σ: &std::collections::HashMap<laddertypes::TypeID, laddertypes::TypeTerm>, i: u64) { + pub fn into_prim_c_morphism(self, dict: &mut impl laddertypes::TypeDict, symbol: String, σ: &std::collections::HashMap<laddertypes::TypeID, laddertypes::TypeTerm>) -> LdmcPrimCMorphism { + + let src_type = self.get_type().src_type.clone().apply_substitution(&|k| σ.get(k).cloned()).clone(); + let dst_type = self.get_type().dst_type.clone().apply_substitution(&|k| σ.get(k).cloned()).clone(); + + let src_c_type = get_c_repr_type(dict, src_type.clone(), true).expect("cant get c-repr type for src type"); + let dst_c_type = get_c_repr_type(dict, dst_type.clone(), true).expect("cant get c-repr type for src type"); + + let c_source = + format!(" +typedef {} {}_src_t; + +typedef {} {}_dst_t; + +int {} ( {}_src_t const * restrict src, {}_dst_t * restrict dst ) +{{ +{} + return 0; +}} + ", + src_c_type, symbol, + dst_c_type, symbol, + symbol, symbol, symbol, + self.generate_call(dict, σ, 0) + ); + + LdmcPrimCMorphism { + symbol, + type_args: Vec::new(), + src_type, + dst_type, + c_source + } + } + + pub fn generate_call(&self, dict: &mut impl TypeDict, σ: &std::collections::HashMap<laddertypes::TypeID, laddertypes::TypeTerm>, i: u64) -> String { match self { LdmcMorphism::Primitive(prim_morph) => { let src_c_type = get_c_repr_type(dict, prim_morph.src_type.clone().apply_substitution(&|k| σ.get(k).cloned()).clone(), true).expect("cant get c-repr type for src type"); @@ -331,17 +385,16 @@ impl LdmcMorphism { let src_buf = if i%2 == 0 { "bufA" } else { "bufB" }; let dst_buf = if i%2 == 0 { "bufB" } else { "bufA" }; - println!(r#" - {} + format!(r#" + {{ {} const * restrict src = (void*) {}; {} * restrict dst = (void*) {}; {} ( src, dst ); - {}"#, - '{', + }}"#, src_c_type, src_buf, dst_c_type, dst_buf, prim_morph.instantiated_symbol_name(dict, σ), - '}'); + ) } LdmcMorphism::LengthPrefixMap { length_prefix_type, item_morph } => { let src_type = self.get_type().src_type.clone().apply_substitution(&|k| σ.get(k).cloned()).clone(); @@ -383,18 +436,17 @@ impl LdmcMorphism { let src_buf = if i%2 == 0 { "bufA" } else { "bufB" }; let dst_buf = if i%2 == 0 { "bufB" } else { "bufA" }; - println!(r#" - {} + format!(r#" + {{ {} const * restrict src = (void*) {}; {} * restrict dst = (void*) {}; {} ( {}, src, dst ); - {}"#, - '{', + }}"#, src_c_type, src_buf, dst_c_type, dst_buf, map_fn, item_morph.instantiated_symbol_name(dict, σ), - '}'); + ) } LdmcMorphism::ValueDelimMap { delim, item_morph } => { let src_c_type = get_c_repr_type(dict, item_morph.src_type.clone(), false).expect("cant get c-repr type for src type"); @@ -402,17 +454,54 @@ impl LdmcMorphism { let src_buf = if i%2 == 0 { "bufA" } else { "bufB" }; let dst_buf = if i%2 == 0 { "bufB" } else { "bufA" }; - println!(r#" - {} + format!(r#" + {{ {} const * restrict src = (void*) {}; {} * restrict dst = (void*) {}; value_delim_array_map_8_to_64( {}, src, dst ); - {}"#, - '{', + }}"#, src_c_type, src_buf, dst_c_type, dst_buf, - item_morph.instantiated_symbol_name(dict, σ), - '}'); + item_morph.instantiated_symbol_name(dict, σ) + ) + }, + + LdmcMorphism::StructMap { src_struct, dst_struct, member_morphisms } => { + let mut output = String::new(); + for member_morph in member_morphisms.iter() { + if let Some(m) = member_morph.item_morph.as_ref() { + //let src_c_type = get_c_repr_type(dict, m.src_type.clone(), false).expect("cant get c-repr type for field member"); + //let dst_c_type = get_c_repr_type(dict, m.dst_type.clone(), false).expect("cant get c-repr type for field member"); + + output.push_str(&format!(" {} ( &src->{}, &dst->{} );\n", + m.instantiated_symbol_name(dict, σ), + member_morph.field_name, + member_morph.field_name + )); + } else { + let mut field_type = None; + for (field_name, ft) in src_struct.members.iter() { + if field_name == &member_morph.field_name { + field_type = Some(ft); + } + } + + let field_type = field_type.expect("cant get field member type"); + //if let Some(field_c_type) = get_c_repr_type(dict, field_type.clone(), false).expect("cat get c-repr type for field member"); + + match get_type_size(dict, field_type.clone()) { + ObjectSize::Static(size) => { + output.push_str(&format!(" memcpy( &dst->{}, &src->{}, sizeof(dst->{}) );\n", + member_morph.field_name, member_morph.field_name, member_morph.field_name + )); + } + _ => { + eprintln!("cant assign field of unknown size!"); + } + } + } + } + output } } } diff --git a/src/main.rs b/src/main.rs index 13b8629..8769384 100644 --- a/src/main.rs +++ b/src/main.rs @@ -3,29 +3,25 @@ mod morphism; mod parser; mod c_gen; +mod struct_layout; use { - ariadne::{Color, Label, Report, ReportKind, Source}, - chumsky::prelude::*, - laddertypes::{ - parser::ParseLadderType, BimapTypeDict, MorphismType - }, - std::sync::{Arc, RwLock}, - tiny_ansi::TinyAnsi, - - crate::{ morphism::LdmcMorphism, parser::morphism_base_parser, - } + }, ariadne::{Color, Label, Report, ReportKind, Source}, chumsky::prelude::*, laddertypes::{ + parser::ParseLadderType, unparser::*, BimapTypeDict, MorphismType, TypeDict + }, std::{collections::HashMap, sync::{Arc, RwLock}}, tiny_ansi::TinyAnsi }; fn main() { let mut type_dict = Arc::new(RwLock::new(BimapTypeDict::new())); - let mut morphism_base = laddertypes::MorphismBase::<LdmcMorphism>::new(vec![ + + let mut morphism_base = laddertypes::morphism_base::MorphismBase::<LdmcMorphism>::new(vec![ //type_dict.parse("Seq~MsbCont").expect(""), //type_dict.parse("Seq~<ValueTerminated '\\0'>").expect(""), - type_dict.parse("Seq~<LengthPrefix native.UInt64>").expect("") + type_dict.parse("Seq~<LengthPrefix native.UInt64>").expect(""), + type_dict.parse("Struct").expect("") ]); let mut args = std::env::args().skip(1); @@ -60,14 +56,105 @@ fn main() { } } + let mut γ = HashMap::new(); + γ.insert( + type_dict.get_typeid_creat(&"Byte".into()), + type_dict.parse("<Seq~<StaticLength 8> Bit>").expect("parse") + .apply_substitution(&|k| γ.get(k).cloned()) + .clone() + ); + γ.insert( + type_dict.get_typeid_creat(&"x86.UInt8".into()), + type_dict.parse("ℤ_2^8 ~ <PosInt 2 BigEndian> ~ <Seq~<StaticLength 8> <Digit 2> ~ Bit>").expect("parse") + .apply_substitution(&|k| γ.get(k).cloned()) + .clone() + ); + γ.insert( + type_dict.get_typeid_creat(&"x86.UInt16".into()), + type_dict.parse("ℤ_2^16 ~ <PosInt 256 LittleEndian> ~ <Seq~<StaticLength 2> <Digit 256> ~ x86.UInt8 >").expect("parse") + .apply_substitution(&|k| γ.get(k).cloned()) + .clone() + ); + γ.insert( + type_dict.get_typeid_creat(&"x86.UInt32".into()), + type_dict.parse("ℤ_2^32 ~ <PosInt 256 LittleEndian> ~ <Seq~<StaticLength 4> <Digit 256> ~ x86.UInt8 >").expect("parse") + .apply_substitution(&|k| γ.get(k).cloned()) + .clone() + ); + γ.insert( + type_dict.get_typeid_creat(&"x86.UInt64".into()), + type_dict.parse("ℤ_2^64 ~ <PosInt 256 LittleEndian> ~ <Seq~<StaticLength 8> <Digit 256> ~ x86.UInt8 >").expect("parse") + .apply_substitution(&|k| γ.get(k).cloned()) + .clone() + ); + γ.insert( + type_dict.get_typeid_creat(&"x86.Float".into()), + type_dict.parse("ℝ ~ IEEE-754.Float32 ~ <Seq~<StaticLength 4> Byte>").expect("parse") + .apply_substitution(&|k| γ.get(k).cloned()) + .clone() + ); + let struct_type1 = type_dict.parse(" + <Struct + <Struct.Field online-since TimePoint ~ <TimeSince UnixEpoch> ~ Duration ~ Seconds ~ ℝ ~ <QuantizedLinear 0 1 1000> ~ ℕ ~ native.UInt64 > + <Struct.Field battery-capacity Energy ~ Wh ~ ℝ ~ <QuantizedLinear 0 1 1000> ~ ℕ ~ native.UInt64 > + <Struct.Field battery-charge Energy ~ Wh ~ ℝ ~ <QuantizedLinear 0 1 1000> ~ ℕ ~ native.UInt64 > + <Struct.Field min-sampling-period Duration ~ Seconds ~ ℝ ~ <QuantizedLinear 0 1 1000> ~ ℕ ~ native.UInt32 > + <Struct.Field cur-sampling-period Duration ~ Seconds ~ ℝ ~ <QuantizedLinear 0 1 1000> ~ ℕ ~ native.UInt32 > + <Struct.Field max-chunk-size ℕ ~ native.UInt32 > + <Struct.Field cur-chunk-size ℕ ~ native.UInt32 > + <Struct.Field n-chunks-capacity ℕ ~ native.UInt32 > + <Struct.Field n-full-data-chunks ℕ ~ native.UInt32 > + <Struct.Field n-empty-data-chunks ℕ ~ native.UInt32 > + > + ").expect("parse struct type"); + + eprintln!("{} + ", + struct_type1.clone().sugar(&mut type_dict).pretty(&type_dict, 0) + ); + + for m in morphism_base.enum_morphisms( &struct_type1 ) { + eprintln!("{:?} -> {:?}", + type_dict.read().unwrap().unparse(&m.get_type().src_type), + type_dict.read().unwrap().unparse(&m.get_type().dst_type) + ); + } + return; + + let struct_type2 = type_dict.parse(" + <Struct + + <Struct.Field battery-charge Energy ~ Wh ~ ℝ ~ native.Double > + <Struct.Field battery-capacity Energy ~ Wh ~ ℝ ~ native.Double > + <Struct.Field min-sampling-period Duration ~ Seconds ~ ℝ ~ native.Double > + <Struct.Field cur-sampling-period Duration ~ Seconds ~ ℝ ~ native.Double > + <Struct.Field max-chunk-size ℕ ~ native.UInt32 > + <Struct.Field cur-chunk-size ℕ ~ native.UInt32 > + <Struct.Field n-chunks-capacity ℕ ~ native.UInt32 > + <Struct.Field n-full-data-chunks ℕ ~ native.UInt32 > + <Struct.Field n-empty-data-chunks ℕ ~ native.UInt32 > + + <Struct.Field online-since TimePoint ~ <TimeSince UnixEpoch> ~ Duration ~ Seconds ~ ℝ ~ native.Double > + > + ").expect("parse struct type"); + + let m = LdmcMorphism::new_struct_map(&mut type_dict, &morphism_base, struct_type1, struct_type2); + + println!("{}", + m.into_prim_c_morphism(&mut type_dict, "morph_my_struct".into(), &HashMap::new()) + .c_source + ); +return; let src_type = type_dict.parse( src_type_arg.as_str() ).expect(""); let dst_type = type_dict.parse( dst_type_arg.as_str() ).expect(""); - let path = morphism_base.find_morphism_path(MorphismType { - src_type: src_type.clone(), - dst_type: dst_type.clone(), - }); + let path = laddertypes::morphism_path::ShortestPathProblem::new( + &morphism_base, + MorphismType { + src_type: src_type.clone(), + dst_type: dst_type.clone(), + }).solve(); match path { Some(path) => { diff --git a/src/morphism.rs b/src/morphism.rs index a1f2aab..c5a509f 100644 --- a/src/morphism.rs +++ b/src/morphism.rs @@ -1,5 +1,6 @@ -use laddertypes::morphism::Morphism; +use laddertypes::{morphism::Morphism, morphism_base::MorphismBase}; +use crate::{c_gen::encode_type_to_symbol, struct_layout::StructLayout}; #[derive(Clone, Debug)] pub struct LdmcPrimCMorphism { @@ -10,9 +11,18 @@ pub struct LdmcPrimCMorphism { pub c_source: String } +#[derive(Clone)] +pub struct StructFieldMorphism { + pub field_name: String, + pub item_morph: Option<Box<LdmcPrimCMorphism>>, + pub src_offset: u64, + pub dst_offset: u64, +} + #[derive(Clone)] pub enum LdmcMorphism { Primitive( LdmcPrimCMorphism ), + //Chain(Vec< LdmcPrimCMorphism >), LengthPrefixMap{ length_prefix_type: laddertypes::TypeTerm, item_morph: Box<LdmcPrimCMorphism> @@ -20,6 +30,104 @@ pub enum LdmcMorphism { ValueDelimMap{ delim: u64, item_morph: Box<LdmcPrimCMorphism> + }, + StructMap{ + src_struct: StructLayout, + dst_struct: StructLayout, + member_morphisms: Vec<StructFieldMorphism> + } +} + +impl LdmcMorphism { + /* + pub fn into_prim_c_morphism(self, dict: &mut impl laddertypes::TypeDict, symbol: String) -> LdmcPrimCMorphism { + + let src_c_type = ; + let dst_c_type = ; + + let c_source = + format!(" + int {} ( {} const * restrict src, {} * restrict dst ) {{ + {} + return 0; + }} + ", + symbol, src_c_type, dst_c_type, + self.generate_call(dict, &std::collections::HashMap::new(), 0) + ); + + LdmcPrimCMorphism { + symbol, + type_args: Vec::new(), + src_type, + dst_type, + c_source + } + } +*/ + pub fn new_struct_map( + dict: &mut impl laddertypes::TypeDict, + morph_base: &MorphismBase<LdmcMorphism>, + src: laddertypes::TypeTerm, + dst: laddertypes::TypeTerm, + ) -> Self { + let src_struct = StructLayout::parse(dict, src).expect("cant parse src struct layout"); + let dst_struct = StructLayout::parse(dict, dst).expect("cant parse dst struct layout"); + + let mut member_morphisms = Vec::new(); + + for (field_name, dst_type) in dst_struct.members.iter() { + let mut src_type = None; + for (src_name, st) in src_struct.members.iter() { + if src_name == field_name { + src_type = Some(st.clone()); + } + } + let src_type = src_type.expect(&format!("cant find member {} in src struct", field_name)); + + if src_type == *dst_type { + member_morphisms.push( + StructFieldMorphism { + field_name: field_name.to_string(), + item_morph: None, + src_offset: src_struct.get_offset( field_name ), + dst_offset: dst_struct.get_offset( field_name ), + } + ); + } else { + match morph_base.find_morphism( + &laddertypes::MorphismType { + src_type: src_type.clone(), + dst_type: dst_type.clone() + }, + dict + ) { + Some(item_morph) => { + let morph_symb = format!("morph_{}_to_{}", + encode_type_to_symbol(dict, &src_type), + encode_type_to_symbol(dict, &dst_type) + ); + member_morphisms.push( + StructFieldMorphism { + field_name: field_name.to_string(), + item_morph: Some(Box::new(item_morph.m.into_prim_c_morphism(dict, morph_symb, &item_morph.σ))), + src_offset: src_struct.get_offset( field_name ), + dst_offset: dst_struct.get_offset( field_name ), + } + ); + }, + + None => { + eprintln!("cant map field {}", field_name); + } + } + } + } + + LdmcMorphism::StructMap { + src_struct, dst_struct, + member_morphisms + } } } @@ -47,6 +155,12 @@ impl Morphism for LdmcMorphism { src_type: laddertypes::TypeTerm::App(vec![ value_delim_type.clone(), item_morph.src_type.clone() ]), dst_type: laddertypes::TypeTerm::App(vec![ value_delim_type.clone(), item_morph.dst_type.clone() ]), } + }, + LdmcMorphism::StructMap { src_struct, dst_struct, member_morphisms } => { + laddertypes::MorphismType { + src_type: src_struct.get_type(), + dst_type: dst_struct.get_type() + } } }.normalize() } diff --git a/src/struct_layout.rs b/src/struct_layout.rs new file mode 100644 index 0000000..d961602 --- /dev/null +++ b/src/struct_layout.rs @@ -0,0 +1,167 @@ + +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); + + } +}