use { ariadne::{Color, Label, Report, ReportKind, Source}, chumsky::{ prelude::*, text::* }, laddertypes::{ dict::TypeDict, parser::ParseLadderType, subtype_unify, unparser::UnparseLadderType, BimapTypeDict, Morphism, MorphismType }, std::{any::Any, sync::{Arc, RwLock}}, tiny_ansi::TinyAnsi }; /* */ pub fn get_c_repr_kind(kind: String) -> Option<String> { match kind.as_str() { "ℤ" => Some("uint64_t".into()), _ => None } } /* for a given ladder type `t`, get the corresponding C type */ pub fn get_c_repr_type(dict: &mut impl TypeDict, t: laddertypes::TypeTerm, skip_pointer: bool) -> Option<String> { let lnf = t.normalize().decurry().get_lnf_vec(); match lnf.last() { Some(t) => { if t == &dict.parse("Byte").expect("parse") || t == &dict.parse("x86.UInt8").expect("parse") || t == &dict.parse("<StaticLength 8 Bit>").expect("parse") { Some("uint8_t".into()) } else if t == &dict.parse("x86.UInt16").expect("parse") { Some("uint16_t".into()) } else if t == &dict.parse("x86.UInt32").expect("parse") { Some("uint32_t".into()) } else if t == &dict.parse("x86.UInt64").expect("parse") { Some("uint64_t".into()) } else { match t { laddertypes::TypeTerm::App(args) => { if args[0] == laddertypes::TypeTerm::TypeID(dict.get_typeid(&"LengthPrefix".into()).unwrap()) { let _length_type = args[1].clone(); let item_c_type : String = get_c_repr_type(dict, args[2].clone(), false)?; match item_c_type.as_str() { "uint8_t" => Some(format!("struct LengthPrefixUInt8Array")), "uint16_t" => Some(format!("struct LengthPrefixUInt16Array")), "uint32_t" => Some(format!("struct LengthPrefixUInt32Array")), "uint64_t" => Some(format!("struct LengthPrefixUInt64Array")), _ => None } } else if args[0] == laddertypes::TypeTerm::TypeID(dict.get_typeid(&"ValueTerminated".into()).unwrap()) { let _delim_val = args[1].clone(); let c_type = get_c_repr_type(dict, args[2].clone(), false)?; if skip_pointer { Some(c_type) } else { Some(format!("{} *", c_type)) } } else if args[0] == laddertypes::TypeTerm::TypeID(dict.get_typeid(&"MsbCont".into()).unwrap()) { let c_type = get_c_repr_type(dict, args[1].clone(), false)?; if skip_pointer { Some(c_type) } else { Some(format!("{} *", c_type)) } } else { None } } _ => None } } } None => None } } #[derive(Clone, Debug)] struct LdmcPrimCMorphism { symbol: String, type_args: Vec<(laddertypes::TypeID, String)>, src_type: laddertypes::TypeTerm, dst_type: laddertypes::TypeTerm, c_source: String } fn encode_type_to_symbol(dict: &mut impl TypeDict, t: &laddertypes::TypeTerm)-> String { match t { laddertypes::TypeTerm::Char(c) => { match c { '.' => format!("_dot_"), _ => format!("{}", (*c as u64)) } }, laddertypes::TypeTerm::Num(n) => { format!("{}", n) } laddertypes::TypeTerm::TypeID(ty_id) => { if let Some(name) = dict.get_typename(ty_id) { format!("{}", name.replace(".", "_dot_")) } else { format!("") } } laddertypes::TypeTerm::Ladder(rs) | laddertypes::TypeTerm::App(rs) => { let mut s = String::new(); for r in rs { s.push('_'); s.push_str(&encode_type_to_symbol(dict, r)); } s } } } fn encode_type_to_value(dict: &mut impl TypeDict, t: &laddertypes::TypeTerm) -> String { dict.unparse(t) } impl LdmcPrimCMorphism { pub fn instantiated_symbol_name(&self, dict: &mut impl TypeDict, σ: &std::collections::HashMap<laddertypes::TypeID, laddertypes::TypeTerm>) -> String { let mut s = self.symbol.clone(); for (k_id,v) in self.type_args.iter() { if let Some(val_trm) = σ.get(k_id) { if let laddertypes::TypeID::Var(var_id) = k_id { let name = dict.get_varname(*var_id).unwrap(); let val_str = encode_type_to_symbol(dict, val_trm); s.push_str(&format!("_{}_{}", name, val_str)); } } else { if let laddertypes::TypeID::Var(var_id) = k_id { let k = dict.get_varname(*var_id).unwrap(); s.push_str(&format!("_{:?}_MISSING", k)); eprintln!("INCOMPLETE MORPHISM INSTANTIATION, missing {} ({})", k, var_id); } } } s } pub fn expected_c_type_signature(&self, dict: &mut impl TypeDict, σ: &std::collections::HashMap<laddertypes::TypeID, laddertypes::TypeTerm>) -> String { format!("int {} ({} const * restrict src, {} * restrict dst);", self.instantiated_symbol_name(dict, σ), get_c_repr_type(dict, self.src_type.clone(), true).expect("cant get c-repr type for src type"), get_c_repr_type(dict, self.dst_type.clone(), true).expect("cant get c-repr type for dst type")) } pub fn generate_instantiation(&self, dict: &mut impl TypeDict, σ: &std::collections::HashMap<laddertypes::TypeID, laddertypes::TypeTerm>) -> Option<String> { let mut s = String::new(); s.push_str(&format!(r#" int {} ( {} const * restrict src, {} * restrict dst ) {{ "#, self.instantiated_symbol_name(dict, &σ), get_c_repr_type(dict, self.src_type.clone().apply_substitution(&|k| σ.get(k).cloned()).clone(), true).expect("cant get c-repr-type"), get_c_repr_type(dict, self.dst_type.clone().apply_substitution(&|k| σ.get(k).cloned()).clone(), true).expect("cant get c-repr-type"), )); for (ty_id, kind) in self.type_args.iter() { if let Some(val) = σ.get(ty_id) { s.push_str(&format!(" #define {} {}\n", dict.get_typename(&ty_id).unwrap(), encode_type_to_value(dict, val))); } } s.push_str(&self.c_source); for (ty_id, kind) in self.type_args.iter() { s.push_str(&format!("\n #undef {}", dict.get_typename(&ty_id).unwrap())); } s.push_str(&format!(r#" }} "#)); Some(s) } } #[derive(Clone)] enum LdmcMorphism { Primitive( LdmcPrimCMorphism ), LengthPrefixMap{ length_prefix_type: laddertypes::TypeTerm, item_morph: Box<LdmcPrimCMorphism> }, ValueDelimMap{ delim: u64, item_morph: Box<LdmcPrimCMorphism> } } impl LdmcMorphism { pub fn generate_call(&self, dict: &mut impl TypeDict, σ: &std::collections::HashMap<laddertypes::TypeID, laddertypes::TypeTerm>, i: u64) { match self { LdmcMorphism::Primitive(prim_morph) => { let src_c_type = get_c_repr_type(dict, prim_morph.src_type.clone(), true).expect("cant get c-repr type for src type"); let dst_c_type = get_c_repr_type(dict, prim_morph.dst_type.clone(), true).expect("cant get c-repr type for dst type"); let src_buf = if i%2 == 0 { "bufA" } else { "bufB" }; let dst_buf = if i%2 == 0 { "bufB" } else { "bufA" }; println!(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_c_type = get_c_repr_type(dict, self.get_type().src_type, true).expect("cant get c-repr type for src type"); let dst_c_type = get_c_repr_type(dict, self.get_type().dst_type, true).expect("cant get c-repr type for dst type"); let map_fn = match (src_c_type.as_str(), dst_c_type.as_str()) { ("struct LengthPrefixUInt64Array", "struct LengthPrefixUInt64Array") => "length_prefix_array_map_64_to_64", ("struct LengthPrefixUInt8Array", "struct LengthPrefixUInt64Array") => "length_prefix_array_map_8_to_64", ("struct LengthPrefixUInt64Array", "struct LengthPrefixUInt8Array") => "length_prefix_array_map_64_to_8", ("struct LengthPrefixUInt8Array", "struct LengthPrefixUInt8Array") => "length_prefix_array_map_8_to_8", _ => { "{{ ERROR: no map function implemented }}" } }; let src_buf = if i%2 == 0 { "bufA" } else { "bufB" }; let dst_buf = if i%2 == 0 { "bufB" } else { "bufA" }; println!(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"); let dst_c_type = get_c_repr_type(dict, item_morph.dst_type.clone(), false).expect("cant get c-repr type for dst type"); let src_buf = if i%2 == 0 { "bufA" } else { "bufB" }; let dst_buf = if i%2 == 0 { "bufB" } else { "bufA" }; println!(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, σ), '}'); } } } } impl Morphism for LdmcMorphism { fn weight(&self) -> u64 { 1 } fn get_type(&self) -> laddertypes::MorphismType { match self { LdmcMorphism::Primitive(prim_morph) => laddertypes::MorphismType { src_type: prim_morph.src_type.clone().normalize(), dst_type: prim_morph.dst_type.clone().normalize() }, LdmcMorphism::LengthPrefixMap{ length_prefix_type, item_morph } => { laddertypes::MorphismType { src_type: laddertypes::TypeTerm::App(vec![ length_prefix_type.clone(), item_morph.src_type.clone() ]), dst_type: laddertypes::TypeTerm::App(vec![ length_prefix_type.clone(), item_morph.dst_type.clone() ]), } }, LdmcMorphism::ValueDelimMap{ delim, item_morph } => { let value_delim_type = laddertypes::TypeTerm::App(vec![]); laddertypes::MorphismType { 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() ]), } } }.normalize() } fn map_morphism(&self, seq_type: laddertypes::TypeTerm) -> Option< Self > { match self { LdmcMorphism::Primitive(prim) => { let item_morph = Box::new(prim.clone()); /* if seq_type == self.length_prefix_type { */ Some(LdmcMorphism::LengthPrefixMap{ length_prefix_type: seq_type, item_morph, }) /* } else if seq_type == self.value_delim_type { Some(LdmcMorphism::ValueDelimMap { delim, item_morph }) } else { None } */ } _ => None } } } /* morphism-base text format: * NAME '(' [TYPE-ARG-NAME ':' KIND] ')' * SRC-TYPE * '-->' DST-TYPE * ``` * TEMPLATE-CODE * ``` */ fn parser( type_dict: Arc<RwLock< BimapTypeDict >> ) -> impl Parser<char, Vec<LdmcPrimCMorphism>, Error = Simple<char>> { // morph name ident().padded() // type args .then( ident().padded() .then_ignore(just(":").padded()) .then(none_of(",)").repeated().padded()) .separated_by(just(",").padded()) .delimited_by(just("("), just(")")) ) // newline .then_ignore(just('\n')) // src type .then(take_until(just("-->").ignored())) // dst_type .then(take_until(just("```"))) // c sourcecode template .then(take_until(just("```"))) .map( move |((((symbol, type_args), (src_type, _)), (dst_type, _)), (c_source, _))| { let c_source = c_source.iter().collect(); let mut type_dict = type_dict.write().unwrap(); let type_args : Vec<_> = type_args.into_iter().map(|(v,k)| (v,k.into_iter().collect())).collect(); let mut ty_args = Vec::new(); for (var, kind) in type_args.into_iter() { let var_id = type_dict.add_varname(var.clone()); ty_args.push((var_id, kind)); } let mut src_type = type_dict.parse(&src_type.iter().collect::<String>()).expect("couldnt parse src type"); let mut dst_type = type_dict.parse(&dst_type.iter().collect::<String>()).expect("couldnt parse dst type"); LdmcPrimCMorphism { symbol, type_args: ty_args, src_type, dst_type, c_source } }) .separated_by(text::newline()) } fn main() { let mut type_dict = Arc::new(RwLock::new(BimapTypeDict::new())); let mut morphism_base = laddertypes::MorphismBase::<LdmcMorphism>::new(vec![ //type_dict.parse("Seq~MsbCont").expect(""), //type_dict.parse("Seq~<ValueTerminated '\\0'>").expect(""), type_dict.parse("Seq~<LengthPrefix x86.UInt64>").expect("") ]); let mut args = std::env::args().skip(1); let src_type_arg = args.next().expect("src type expected"); let dst_type_arg = args.next().expect("dst type expected"); for mb_path in args { let src = std::fs::read_to_string(mb_path.clone()).expect("read"); let result = parser(type_dict.clone()).parse(src.clone()); match result { Ok(morphisms) => { eprintln!("[{}] parse ok.", mb_path.bright_yellow()); for m in morphisms { morphism_base.add_morphism(LdmcMorphism::Primitive(m)); } } Err(errs) => { errs.into_iter().for_each(|e| { Report::build(ReportKind::Error, (), e.span().start) .with_message(e.to_string()) .with_label( Label::new(e.span()) .with_message(e) .with_color(Color::Red), ) .finish() .print(Source::from(&src)) .unwrap() }); } } } 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(), }); match path { Some(path) => { let mut i = 0; /* todo: collect include files from morphism base */ println!(r#" #include <stdio.h> #include <unistd.h> #include <string.h> #include <stdint.h> #include <stdbool.h> #include <array/length-prefix.h> "#); let mut existing_instantiations = Vec::new(); for morph_inst in path.iter() { match &morph_inst.m { LdmcMorphism::Primitive( item_morph ) => { let name = item_morph.instantiated_symbol_name(&mut type_dict, &morph_inst.σ); if ! existing_instantiations.contains(&name) { if let Some(s) = item_morph.generate_instantiation(&mut type_dict, &morph_inst.σ) { println!("{}", s); } else { eprintln!("couldnt generate instance {}", name); } existing_instantiations.push( name ); } } LdmcMorphism::LengthPrefixMap { length_prefix_type, item_morph } => { let name = item_morph.instantiated_symbol_name(&mut type_dict, &morph_inst.σ); if ! existing_instantiations.contains(&name) { if let Some(s) = item_morph.generate_instantiation(&mut type_dict, &morph_inst.σ) { println!("{}", s); } else { eprintln!("couldnt generate instance {}", name); } existing_instantiations.push( name ); } } _ => {} } } println!(r#" int main() {{ uint8_t bufA[1024]; uint8_t bufB[1024]; char in_str[] = "read :: {} \n"; char out_str[]= "write:: {} \n"; write(2, in_str, strlen(in_str)); write(2, out_str, strlen(out_str)); int l = read(0, bufA, 1024); fprintf(stderr, "read %d bytes\n", l); "#, type_dict.unparse(&src_type).replace("\\", "\\\\"), type_dict.unparse(&dst_type).replace("\\", "\\\\") ); for morph_inst in path.iter() { println!(r#" /* morph to {} ...with 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(&mut type_dict, &morph_inst.σ, i); i += 1; } let out_buf = if i%2==0 { "bufA" } else { "bufB" }; let is_string = false; if let Ok((halo, σ)) = laddertypes::subtype_unify( &dst_type, &type_dict.parse("<Seq~<ValueTerminated 0> x86.UInt8>").unwrap() ) { println!(r#" printf("%s\n", {});"#, out_buf); } else if let Ok((halo, σ)) = laddertypes::subtype_unify( &dst_type, &type_dict.parse("<Seq~<LengthPrefix x86.UInt64> x86.UInt8>").unwrap() ) { println!(r#" /* write output */ {{ struct LengthPrefixUInt8Array * buf = (void*){}; write(1, {}, sizeof(uint64_t) + buf->len); }}"#, out_buf, out_buf); } else { println!(r#" write(1, {}, {});"#, out_buf, 1024 ); } println!(r#" return 0; }} "#); eprintln!("Success: generated C code"); } None => { eprintln!("Error: could not find morphism path"); std::process::exit(-1); } } }