From 80303049ad4a6f2d08efa10b4af8d58438eaff08 Mon Sep 17 00:00:00 2001 From: Dirk Van Haerenborgh Date: Sat, 26 May 2018 10:36:44 +0200 Subject: [PATCH] generate extern c functions --- src/codegen/subclass/class_impl.rs | 25 +-- .../subclass/virtual_method_body_chunks.rs | 39 +++++ src/codegen/subclass/virtual_methods.rs | 143 +++++++++++++++--- src/codegen/sys/mod.rs | 2 +- 4 files changed, 179 insertions(+), 30 deletions(-) diff --git a/src/codegen/subclass/class_impl.rs b/src/codegen/subclass/class_impl.rs index e835ccc5a..3dfedf4be 100644 --- a/src/codegen/subclass/class_impl.rs +++ b/src/codegen/subclass/class_impl.rs @@ -18,6 +18,7 @@ use std::result::Result as StdResult; use codegen::general; use codegen::subclass::virtual_methods; use codegen::sys::fields; + use library::*; use analysis::general::StatusedTypeId; @@ -554,18 +555,18 @@ fn generate_extern_c_funcs( object_analysis: &analysis::object::Info, subclass_info: &SubclassInfo, ) -> Result<()> { - // unsafe extern "C" fn application_startup(ptr: *mut gio_ffi::GApplication) - // where - // T::ImplType: ApplicationImpl, - // { - // callback_guard!(); - // floating_reference_guard!(ptr); - // let application = &*(ptr as *mut T::InstanceStructType); - // let wrap: T = from_glib_borrow(ptr as *mut T::InstanceStructType); - // let imp = application.get_impl(); - // - // imp.startup(&wrap) - // } + + + for method_analysis in &object_analysis.virtual_methods { + try!(virtual_methods::generate_extern_c_func( + w, + env, + object_analysis, + method_analysis, + subclass_info, + 0 + )); + } Ok(()) } diff --git a/src/codegen/subclass/virtual_method_body_chunks.rs b/src/codegen/subclass/virtual_method_body_chunks.rs index 4bb9e7c73..086f7fa25 100644 --- a/src/codegen/subclass/virtual_method_body_chunks.rs +++ b/src/codegen/subclass/virtual_method_body_chunks.rs @@ -21,6 +21,7 @@ use codegen::parameter::*; #[derive(Default)] pub struct Builder { + object_name: String, object_class_c_type: String, ffi_crate_name: String, method_name: String, @@ -36,6 +37,11 @@ impl Builder { Default::default() } + pub fn object_name(&mut self, name: &str) -> &mut Builder { + self.object_name = name.into(); + self + } + pub fn object_class_c_type(&mut self, c_class_type: &str) -> &mut Builder { self.object_class_c_type = c_class_type.into(); self @@ -109,6 +115,39 @@ impl Builder { Chunk::Chunks(chunks) } + pub fn generate_extern_c_func(&self, env: &Env) -> Chunk { + let mut chunks = Vec::new(); + + chunks.push(Chunk::Custom("callback_guard!();".to_owned())); + chunks.push(Chunk::Custom("floating_reference_guard!(ptr);".to_owned())); + + chunks.push(Chunk::Let{ is_mut:false, + name: self.object_name.to_lowercase(), + value: Box::new(Chunk::Custom("&*(ptr as *mut T::InstanceStructType)".to_owned())), + type_: None + }); + + chunks.push(Chunk::Let{ is_mut:false, + name: "wrap".to_owned(), + value: Box::new(Chunk::Custom("from_glib_borrow(ptr as *mut T::InstanceStructType))".to_owned())), + type_: Some(Box::new(Chunk::Custom("T".to_owned()))) + }); + + chunks.push(Chunk::Let{ is_mut:false, + name: "imp".to_owned(), + value: Box::new(Chunk::Custom(format!("{}.get_impl())", + self.object_name.to_lowercase()).to_owned())), + type_: None + }); + + chunks.push(Chunk::Custom(format!("imp.{}({})", + self.method_name, + &"").to_owned())); + + Chunk::Chunks(chunks) + } + + fn base_impl_body_chunk(&self) -> Chunk { Chunk::Closure { diff --git a/src/codegen/subclass/virtual_methods.rs b/src/codegen/subclass/virtual_methods.rs index cbeb751a3..37d7f0829 100644 --- a/src/codegen/subclass/virtual_methods.rs +++ b/src/codegen/subclass/virtual_methods.rs @@ -11,12 +11,16 @@ use writer::primitives::tabs; use writer::ToCode; use codegen::parameter::ToParameter; use chunk::{ffi_function_todo, Chunk}; +use traits::IntoString; +use nameutil; use std::result::Result as StdResult; use std::fmt; use codegen::subclass::class_impl::SubclassInfo; use codegen::subclass::virtual_method_body_chunks::Builder; +use codegen::sys::ffi_type::ffi_type; +use codegen::function_body_chunk::{Parameter, ReturnValue}; pub fn generate_default_impl( w: &mut Write, @@ -39,7 +43,7 @@ pub fn generate_default_impl( let parent_name = &method_analysis.parameters.rust_parameters[0].name; - let param_str = virtual_method_params(env, method_analysis, parent_name, true); + let param_str = virtual_method_params(env, method_analysis, Some(parent_name)); try!(writeln!(w, "{}){{", param_str)); @@ -97,7 +101,7 @@ fn virtual_method_args(method_analysis: &analysis::virtual_methods::Info, includ arg_str } -fn virtual_method_params(env: &Env, method_analysis: &analysis::virtual_methods::Info, parent_name: &String, include_templated: bool) -> String +fn virtual_method_params(env: &Env, method_analysis: &analysis::virtual_methods::Info, parent_name: Option<&String>) -> String { let mut param_str = String::with_capacity(100); for (pos, par) in method_analysis.parameters.rust_parameters.iter().enumerate() { @@ -106,12 +110,15 @@ fn virtual_method_params(env: &Env, method_analysis: &analysis::virtual_methods: } let c_par = &method_analysis.parameters.c_parameters[par.ind_c]; - let s = c_par.to_parameter(env, &method_analysis.bounds); + + // generate types, not trait bounds + let bounds = Bounds::default(); + let s = c_par.to_parameter(env, &bounds); param_str.push_str(&s); // insert the templated param - if include_templated && pos == 0{ - param_str.push_str(&format!(", {}: &T", parent_name)); + if parent_name.is_some() && pos == 0{ + param_str.push_str(&format!(", {}: &T", parent_name.as_ref().unwrap())); } } param_str @@ -137,16 +144,7 @@ pub fn generate_base_impl( method_analysis.name, )); - let mut param_str = String::with_capacity(100); - for (pos, par) in method_analysis.parameters.rust_parameters.iter().enumerate() { - if pos > 0 { - param_str.push_str(", "); - } - - let c_par = &method_analysis.parameters.c_parameters[par.ind_c]; - let s = c_par.to_parameter(env, &method_analysis.bounds); - param_str.push_str(&s); - } + let mut param_str = virtual_method_params(env, method_analysis, None); try!(writeln!(w, "{}){{", param_str)); @@ -240,7 +238,7 @@ pub fn generate_box_impl( let parent_name = &method_analysis.parameters.rust_parameters[0].name; - let param_str = virtual_method_params(env, method_analysis, parent_name, true); + let param_str = virtual_method_params(env, method_analysis, Some(parent_name)); try!(writeln!(w, "{}){{", param_str)); @@ -272,7 +270,56 @@ pub fn generate_box_impl( Ok(()) } +pub fn generate_extern_c_func( + w: &mut Write, + env: &Env, + object_analysis: &analysis::object::Info, + method_analysis: &analysis::virtual_methods::Info, + subclass_info: &SubclassInfo, + indent: usize, +) -> Result<()> { + + try!(writeln!(w)); + + try!(writeln!( + w, + "unsafe extern \"C\" fn {}_{}", + object_analysis.name.to_lowercase(), + method_analysis.name, + object_analysis.subclass_base_trait_name + )); + + let (_, sig) = function_signature(env, method_analysis, false); + + try!(writeln!( + w, + "{}", + sig + )); + try!(writeln!( + w, + "where\n{}T::ImplType: {}", + tabs(indent+1), + object_analysis.subclass_impl_trait_name + )); + try!(writeln!( + w, + "{{" + )); + + let body = extern_c_func_body_chunk(env, object_analysis, method_analysis, subclass_info).to_code(env); + for s in body { + try!(writeln!(w, "{}{}", tabs(indent+1), s)); + } + + try!(writeln!( + w, + "}}" + )); + + Ok(()) +} pub fn body_chunk_builder(env: &Env, object_analysis: &analysis::object::Info, @@ -284,7 +331,8 @@ pub fn body_chunk_builder(env: &Env, let outs_as_return = !method_analysis.outs.is_empty(); - builder.object_class_c_type(object_analysis.c_class_type.as_ref().unwrap()) + builder.object_name(&object_analysis.name) + .object_class_c_type(object_analysis.c_class_type.as_ref().unwrap()) .ffi_crate_name(&env.namespaces[object_analysis.type_id.ns_id].ffi_crate_name) .method_name(&method_analysis.name) .ret(&method_analysis.ret) @@ -312,3 +360,64 @@ pub fn base_impl_body_chunk(env: &Env, builder.generate_base_impl(env) } + +pub fn extern_c_func_body_chunk(env: &Env, + object_analysis: &analysis::object::Info, + method_analysis: &analysis::virtual_methods::Info, + subclass_info: &SubclassInfo + ) -> Chunk +{ + let mut builder = body_chunk_builder(env, object_analysis, method_analysis, subclass_info); + + builder.generate_extern_c_func(env) +} + + +pub fn function_signature(env: &Env, method: &analysis::virtual_methods::Info, bare: bool) -> (bool, String) { + let (mut commented, ret_str) = function_return_value(env, method); + + let mut parameter_strs: Vec = Vec::new(); + for par in &method.parameters.c_parameters { + let (c, par_str) = function_parameter(env, par, bare); + parameter_strs.push(par_str); + if c { + commented = true; + } + } + + ( + commented, + format!("({}){}", parameter_strs.join(", "), ret_str), + ) +} + +fn function_return_value(env: &Env, method: &analysis::virtual_methods::Info) -> (bool, String) { + if method.ret.parameter.is_none(){ + return (false, "".to_string()); + } + let ret = method.ret.parameter.as_ref().unwrap(); + if ret.typ == Default::default() { + return (false, String::new()); + } + let ffi_type = ffi_type(env, ret.typ, &ret.c_type); + let commented = ffi_type.is_err(); + (commented, format!(" -> {}", ffi_type.into_string())) +} + +fn function_parameter(env: &Env, par: &analysis::function_parameters::CParameter, bare: bool) -> (bool, String) { + if let library::Type::Fundamental(library::Fundamental::VarArgs) = *env.library.type_(par.typ) { + return (false, "...".into()); + } + let ffi_type = ffi_type(env, par.typ, &par.c_type); + let commented = ffi_type.is_err(); + let res = if bare { + ffi_type.into_string() + } else { + format!( + "{}: {}", + nameutil::mangle_keywords(&*par.name), + ffi_type.into_string() + ) + }; + (commented, res) +} diff --git a/src/codegen/sys/mod.rs b/src/codegen/sys/mod.rs index bfdedf3c6..8176713eb 100644 --- a/src/codegen/sys/mod.rs +++ b/src/codegen/sys/mod.rs @@ -5,7 +5,7 @@ mod build; mod cargo_toml; pub mod ffi_type; pub mod fields; -mod functions; +pub mod functions; mod lib_; mod statics; mod tests;