diff --git a/internal_proc_macros/src/define_subr.rs b/internal_proc_macros/src/define_subr.rs new file mode 100644 index 0000000..45d1107 --- /dev/null +++ b/internal_proc_macros/src/define_subr.rs @@ -0,0 +1,117 @@ +use syn; +use quote; +use regex; +// use syn::token::{Semi}; +use syn::synom::{Synom}; +use syn::punctuated::Punctuated; +use quote::{ToTokens, Tokens}; +use proc_macro2::{TokenStream}; + +struct ReqArg { name: syn::Ident, typ: syn::TypePath } +struct OptArg { pub arg: ReqArg } +trait Arg { + fn get_name(&self) -> &syn::Ident; + fn get_type(&self) -> &syn::TypePath; + fn get_conv(&self) -> Tokens; +} + +impl Arg for ReqArg { + fn get_name(&self) -> &syn::Ident { &self.name } + fn get_type(&self) -> &syn::TypePath { &self.typ } + + fn get_conv(&self) -> Tokens { + quote!( + Scm::::from_raw(n).into_type().unwrap(); + ) + } +} + +impl Arg for OptArg { + fn get_name(&self) -> &syn::Ident { self.arg.get_name() } + fn get_type(&self) -> &syn::TypePath { self.arg.get_type() } + + fn get_conv(&self) -> Tokens { + quote!( + // TODO: figure out how to convert SCM to Option> + ) + } +} + +impl Synom for ReqArg { + named!(parse -> Self, do_parse!( + name: syn!(syn::Ident) >> + punct!(:) >> + typ: syn!(syn::TypePath) >> + cond_reduce!( + typ.path.segments.last().unwrap().value().ident == "Scm") >> + + (ReqArg { name, typ }) + )); +} + +impl Synom for OptArg { + named!(parse -> Self, do_parse!( + name: syn!(syn::Ident) >> + punct!(:) >> + + _opt: syn!(syn::Ident) >> + cond_reduce!(_opt == "Option") >> + + punct!(<) >> + typ: syn!(syn::TypePath) >> + cond_reduce!( + typ.path.segments.last().unwrap().value().ident == "Scm") >> + punct!(>) >> + + (OptArg { arg: ReqArg { name, typ } }) + )); +} + +named!(pub parse_guile_define_subr -> TokenStream, do_parse!( + name: syn!(syn::Expr) >> + punct!(,) >> + punct!(|) >> + args: call!(Punctuated::::parse_terminated) >> + oargs: call!(Punctuated::::parse_terminated) >> + punct!(|) >> + punct!(->) >> + ret: syn!(syn::TypePath) >> + cond_reduce!( + ret.path.segments.last().unwrap().value().ident == "Scm") >> + body: syn!(syn::Expr) >> + + ({ + let arg_names = args.iter().map(|ref a| a.get_name()) + .collect::>(); + let arg_names2 = arg_names.clone(); + let arg_types = args.iter().map(|ref a| a.get_type()); + let arg_convs = args.iter().map(|ref a| a.get_conv()); + let num_args = args.len(); + + let oarg_names = oargs.iter().map(|ref a| a.get_name()) + .collect::>(); + let oarg_names2 = oarg_names.clone(); + let oarg_types = oargs.iter().map(|ref a| a.get_type()); + let oarg_convs = oargs.iter().map(|ref a| a.get_conv()); + let num_oargs = oargs.len(); + + quote!({ + unsafe { + unsafe extern "C" ___tmp_c_fn(#(#arg_names: SCM),* , #(#oarg_names: SCM),* ) -> SCM { + #(let #arg_names2: #arg_types = #arg_convs; )* + #(let #oarg_names2: #oarg_types = #oarg_convs;)* + + let o: #ret = #body; + + o.into_raw() + } + + let _ = scm_c_define_gsubr( + CString::new(#name).unwrap().as_ptr(), + #num_args, #num_oargs, 0, + ___tmp_c_fn as scm_t_subr + ); + } + }).into() + }) +)); diff --git a/internal_proc_macros/src/guile_impl.rs b/internal_proc_macros/src/guile_impl.rs index 24dc763..bef0c52 100644 --- a/internal_proc_macros/src/guile_impl.rs +++ b/internal_proc_macros/src/guile_impl.rs @@ -288,12 +288,14 @@ impl GuileDef { }).collect(); let mut body = quote!( - unsafe { #cfunc(#(#cargs),*) } + #cfunc(#(#cargs),*) ); - if self.ret_from_raw { - body = quote!(Scm::_from_raw(#body)); - } + body = if self.ret_from_raw { + quote!(unsafe { Scm::_from_raw(#body) }) + } else { + quote!(unsafe { #body }) + }; if let syn::Type::Tuple(t) = syn::parse_str(&ret_ty.to_string()).expect("Parsing return type") { diff --git a/internal_proc_macros/src/lib.rs b/internal_proc_macros/src/lib.rs index 307a27e..51fd2ee 100644 --- a/internal_proc_macros/src/lib.rs +++ b/internal_proc_macros/src/lib.rs @@ -10,8 +10,10 @@ extern crate proc_macro2; mod guile_impl; +mod define_subr; use guile_impl::{parse_guile_impl, parse_guile_defs}; +use define_subr::parse_guile_define_subr; use syn::buffer::TokenBuffer; use proc_macro2::{TokenStream}; use quote::ToTokens; @@ -19,28 +21,37 @@ use quote::ToTokens; proc_macro_item_impl! { /// implement a guile func pub fn guile_impl_impl(input: &str) -> String { - let sb = TokenBuffer::new2( - syn::parse_str::(input).expect("Turning str into tokenstream")); + let sb = TokenBuffer::new2( + syn::parse_str::(input).expect("Turning str into tokenstream")); - format!("{}", parse_guile_impl(sb.begin()) - .expect("Expanding guile_impl macro").0) + format!("{}", parse_guile_impl(sb.begin()) + .expect("Expanding guile_impl macro").0) } } proc_macro_item_impl! { /// implement a guile struct pub fn guile_defs_impl(input: &str) -> String { - let sb = TokenBuffer::new2( - syn::parse_str::(input).expect("Turning str into tokenstream")); + let sb = TokenBuffer::new2( + syn::parse_str::(input).expect("Turning str into tokenstream")); - let gdefs = parse_guile_defs(sb.begin()) - .expect("Expanding guile_defs macro").0; + let gdefs = parse_guile_defs(sb.begin()) + .expect("Expanding guile_defs macro").0; - let mut mtokens = quote::Tokens::new(); + let mut mtokens = quote::Tokens::new(); - gdefs.iter().for_each( - |gd| gd.construct().to_tokens(&mut mtokens)); + gdefs.iter().for_each( + |gd| gd.construct().to_tokens(&mut mtokens)); - format!("{}", mtokens) + format!("{}", mtokens) + } +} + +proc_macro_item_impl! { + pub fn guile_define_subr_impl(input: &str) -> String { + let sb = TokenBuffer::new2( + syn::parse_str::(input).expect("Turning str into tokenstream")); + + format!("{}", parse_guile_define_subr(sb.begin()).expect("Expanding guile_define_subr macro").0) } } diff --git a/src/lib.rs b/src/lib.rs index 0c937ab..c968f5e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -170,6 +170,8 @@ mod tests { // // type SlotTypes = type_list![TestStruct]; unsafe extern "C" fn test_data(fo: SCM) -> SCM { + // let fo: Scm::> = Scm::::from_raw(fo); + let st = Scm::::from_raw(fo).into_foreign(&*FTYPE).unwrap(); assert!(st.is_foreign(&*FTYPE)); @@ -181,17 +183,33 @@ mod tests { } unsafe extern "C" fn get_foreign_o(n: SCM) -> SCM { - let n: u8 = Scm::::from_raw(n).into_integer().unwrap().try_as().unwrap(); + let n: Scm = Scm::::from_raw(n).into_integer().unwrap(); + + let o: Scm> = { + let n: u8 = n.try_as().unwrap(); + Scm::>::new(&*FTYPE, TestStruct { data0: n }) + }; - let st = Scm::>::new(&*FTYPE, TestStruct { data0: n }); + o.into_raw() - st.into_raw() + // |n: Scm| -> Scm> { + // let n: u8 = n.try_as().unwrap(); + // Scm::>::new(&*FTYPE, TestStruct { data0: n }) + // } + + // (n).into_raw() } let st = Scm::>::new(&*FTYPE, TestStruct { data0: 21 }); let _ = Guile::call_with_guile(|_| { + + guile_define_subr!("get_foreign_o", |n: Scm| -> Scm> { + let n: u8 = n.try_as().unwrap(); + Scm::>::new(&*FTYPE, TestStruct { data0: n }) + }); + unsafe { let _ = scm_c_define_gsubr( CString::new("test-data").unwrap().as_ptr(), diff --git a/src/scm/bool.rs b/src/scm/bool.rs index 9fccc1d..5e77ffd 100644 --- a/src/scm/bool.rs +++ b/src/scm/bool.rs @@ -14,14 +14,14 @@ impl Scm { /// Return a true litteral Scm object #[inline] pub fn true_c() -> Scm { - Scm::_from_raw(unsafe { gu_SCM_BOOL_T() }) + unsafe { Scm::_from_raw(gu_SCM_BOOL_T()) } // Scm { data: unsafe { gu_SCM_BOOL_T() } , spec: PhantomData } } /// Return a false litteral Scm object #[inline] pub fn false_c() -> Scm { - Scm::_from_raw(unsafe { gu_SCM_BOOL_F() }) + unsafe { Scm::_from_raw(gu_SCM_BOOL_F()) } // Scm { data: unsafe { gu_SCM_BOOL_F() }, spec: PhantomData } } @@ -37,6 +37,6 @@ impl Scm { impl Not for Scm { type Output = Scm; fn not(self) -> Scm { - Scm::_from_raw(unsafe { scm_not(self.data) }) + unsafe { Scm::_from_raw(scm_not(self.data)) } } } diff --git a/src/scm/foreign.rs b/src/scm/foreign.rs index 987e081..4d1b9e0 100644 --- a/src/scm/foreign.rs +++ b/src/scm/foreign.rs @@ -85,13 +85,13 @@ impl Scm> { Scm::::from("data") ].into(); - Scm::_from_raw_with_spec( - unsafe { + unsafe { + Scm::_from_raw_with_spec( scm_make_foreign_object_type(name.data, slots.data, - Some(Self::finalizer)) - }, + Some(Self::finalizer)), Foreign { _data: PhantomData }) + } } // // NOTE: types in slots should probably be Boxes!!!!! // pub fn new_type(name: &Scm, slot_names: &Scm, slot_types: Box) -> Self { @@ -135,14 +135,15 @@ impl Scm> { pub fn new(typ: &Scm>, data: T) -> Scm> { - Scm::_from_raw_with_spec( - unsafe { + unsafe { + Scm::_from_raw_with_spec( scm_make_foreign_object_1( typ.data, - Box::into_raw(Box::new(data)) - as *mut libc::c_void) - }, - ForeignObject { typ: (*typ).clone() }) + Box::into_raw(Box::new(data)) as *mut libc::c_void + ), + ForeignObject { typ: (*typ).clone() } + ) + } } pub unsafe fn get_raw(&self) -> *mut T { diff --git a/src/scm/list.rs b/src/scm/list.rs index 5e6e44a..77b22c0 100644 --- a/src/scm/list.rs +++ b/src/scm/list.rs @@ -13,7 +13,7 @@ impl From>> for Scm { fn from(l: Vec>) -> Scm { let mut l: Vec = l.into_iter().map(|e| e.data).collect(); l.push(unsafe { gu_SCM_UNDEFINED() }); - Scm::_from_raw(unsafe { gu_scm_list_n(l.as_mut_ptr()) }) + unsafe { Scm::_from_raw(gu_scm_list_n(l.as_mut_ptr())) } } } diff --git a/src/scm/mod.rs b/src/scm/mod.rs index 2b11e00..b54f16a 100644 --- a/src/scm/mod.rs +++ b/src/scm/mod.rs @@ -65,7 +65,7 @@ use std::marker::PhantomData; use std::ptr; use std::mem::transmute; use std::collections::VecDeque; -use std::any::Any; +use std::any::{Any, TypeId}; use std::fmt::Debug; use libc; @@ -141,32 +141,36 @@ unsafe impl Sync for Scm {} impl Scm { #[inline] - pub(crate) fn _from_raw(data: SCM) -> Scm { + pub(crate) unsafe fn _from_raw(data: SCM) -> Scm { // Scm { data, spec: PhantomData } Scm { data, spec: None } } #[inline] - pub(crate) fn _from_raw_with_spec(data: SCM, spec: TS) -> Scm { + pub(crate) unsafe fn _from_raw_with_spec(data: SCM, spec: TS) -> Scm { Scm { data, spec: Some(spec) } } #[inline] pub fn from_raw(data: SCM) -> Scm { - Scm::_from_raw(data) + unsafe { Scm::_from_raw(data) } } #[inline] - pub unsafe fn into_raw(self) -> SCM { self.data } + pub fn into_raw(self) -> SCM { self.data } - // Do not use this without checking for type first - fn into_type(self) -> Scm { - Scm::_from_raw(self.data) + #[inline] + pub fn into_type(self) -> Result, Scm> { + if self.is::() { + Ok(unsafe { Scm::_from_raw(self.data) }) + } else { + Err(self) + } } #[inline] pub fn into_unspecified(self) -> Scm { - Scm::into_type(self) + unsafe { Scm::_from_raw(self.data) } } #[inline] @@ -212,6 +216,25 @@ impl Scm { is_thing_p!(list_p => scm_list_p); is_thing_p!(hash_table_p => scm_hash_table_p); + pub fn is(&self) -> bool { + let num_id = TypeId::of::>(); + let int_id = TypeId::of::>(); + let sym_id = TypeId::of::>(); + let pai_id = TypeId::of::>(); + let lis_id = TypeId::of::>(); + let has_id = TypeId::of::>(); + + match TypeId::of::() { + num_id => self.is_number(), + int_id => self.is_integer(), + sym_id => self.is_symbol(), + pai_id => self.is_pair(), + lis_id => self.is_list(), + has_id => self.is_hash_table(), + _ => false + } + } + // === FOREIGN === pub fn is_foreign(&self, typ: &Scm>) -> bool { @@ -228,7 +251,7 @@ impl Scm { /// scheme operation: `eq?` #[inline] pub fn eq_p(&self, other: &Scm) -> Scm { - Scm::_from_raw(unsafe { scm_eq_p(self.data, other.data) }) + unsafe { Scm::_from_raw(scm_eq_p(self.data, other.data)) } } /// check for identity (`scm_eq_p`) @@ -374,7 +397,7 @@ macro_rules! type_list { impl From> for Scm { fn from(numeric: Scm) -> Scm { - Scm::_from_raw( unsafe { scm_number_to_string(numeric.data, ptr::null_mut()) } ) + unsafe { Scm::_from_raw(scm_number_to_string(numeric.data, ptr::null_mut())) } // Self { // data: unsafe { scm_number_to_string(numeric.data, ptr::null_mut()) }, // spec: PhantomData, diff --git a/src/scm/numeric/mod.rs b/src/scm/numeric/mod.rs index be7207b..b4bddb1 100644 --- a/src/scm/numeric/mod.rs +++ b/src/scm/numeric/mod.rs @@ -115,7 +115,7 @@ macro_rules! impl_op { type Output = Scm<$out>; fn $func(self, other: Scm) -> Scm<$out> { - Scm::_from_raw(unsafe { $cfunc(self.data, other.data) }) + unsafe { Scm::_from_raw($cfunc(self.data, other.data)) } } } }; @@ -125,7 +125,7 @@ macro_rules! impl_op { type Output = Scm<$out>; fn $func(self, other: Scm<$rhs>) -> Scm<$out> { - Scm::_from_raw(unsafe { $cfunc(self.data, other.data) }) + unsafe { Scm::_from_raw($cfunc(self.data, other.data)) } } } }; diff --git a/src/scm/string.rs b/src/scm/string.rs index d63ffc0..af762f9 100644 --- a/src/scm/string.rs +++ b/src/scm/string.rs @@ -41,6 +41,6 @@ guile_impl!(Scm { } pub fn into_symbol(self) -> Scm { - Scm::_from_raw(unsafe { scm_string_to_symbol(self.data) }) + unsafe { Scm::_from_raw(scm_string_to_symbol(self.data)) } } }); diff --git a/src/scm/untyped.rs b/src/scm/untyped.rs index 40c1bee..876b83e 100644 --- a/src/scm/untyped.rs +++ b/src/scm/untyped.rs @@ -24,9 +24,9 @@ impl Scm { Result>, ()> { if self.is_foreign(typ) { - Ok(Scm::_from_raw_with_spec( + Ok(unsafe { Scm::_from_raw_with_spec( self.data, - ForeignObject { typ: typ.clone() })) + ForeignObject { typ: typ.clone() }) }) } else { Err(()) } diff --git a/src/utils.rs b/src/utils.rs index 8e03d06..836e650 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -12,8 +12,8 @@ proc_macro_item_decl! { } proc_macro_item_decl! { - /// implement a foreign object type - foreign_impl! => foreign_impl_impl + /// define a subroutine that is callable from guile + guile_define_subr! => guile_define_subr_impl } /** into_type!() @@ -34,7 +34,7 @@ proc_macro_item_decl! { * * pub fn into_bool(self) -> Result, ()> { * if self.is_bool() { - * Ok(self.into_type()) + Ok(unsafe { Scm::_from_raw(self.data) }) * } else { * Err(()) * } @@ -53,7 +53,7 @@ macro_rules! into_type { ($inn:ident, $isn:ident, $spec:ident) => { pub fn $inn(self) -> Result, ()> { if self.$isn() { - Ok(self.into_type()) + Ok(unsafe { Scm::_from_raw(self.data) }) } else { Err(()) } @@ -84,14 +84,16 @@ macro_rules! into_type { * * #[inline] * pub fn exact_p(&self) -> Scm { - * Scm::_from_raw(unsafe { scm_exact_p(self.data) }) + * unsafe { Scm::_from_raw(scm_exact_p(self.data)) } * } * * #[inline] * pub fn gr_p(&self, other: T) -> Scm { - * Scm::_from_raw(unsafe { + * unsafe { + * Scm::_from_raw(unsafe { * scm_gr_p(self.data, other.data) * }) + * } * } * * ``` @@ -114,9 +116,11 @@ macro_rules! is_thing_p { pub fn $fname <$($tn: $at),*> (&self, $($an: &Scm<$tn>),*) -> Scm { - Scm::_from_raw(unsafe { - $cfunc(self.data, $($an.data),*) - }) + unsafe { + Scm::_from_raw( + $cfunc(self.data, $($an.data),*) + ) + } } }; } @@ -222,7 +226,7 @@ macro_rules! scm_func { ($fname:ident ($($an:ident: $at:ty),*) -> $r:ty, $cfunc:ident) => { #[inline] pub fn $fname(&self, $($an: $at),*) -> $r { - Scm::_from_raw(unsafe { $cfunc(self.data, $($an.data),*) }) + unsafe { Scm::_from_raw($cfunc(self.data, $($an.data),*)) } } }; ($fname:ident ($($an:ident: $at:ty),*), $cfunc:ident) => { @@ -234,7 +238,7 @@ macro_rules! scm_func { (P $fname:ident ($($an:ident: $tn:ident <$at:path>),*) -> $r:ty, $cfunc:ident) => { #[inline] pub fn $fname<$($tn: $at),*>(&self, $($an: &Scm<$tn>),*) -> $r { - Scm::_from_raw(unsafe { $cfunc(self.data, $($an.data),*) }) + unsafe { Scm::_from_raw($cfunc(self.data, $($an.data),*)) } } }; (P $fname:ident ($($an:ident: $tn:ident <$at:path>),*), $cfunc:ident) => { @@ -256,7 +260,7 @@ macro_rules! simple_from { ($from:ty, $cfunc: ident, $to:ty) => { impl From<$from> for $to { fn from(f: $from) -> $to { - Scm::_from_raw( unsafe{ $cfunc(f) } ) + unsafe { Scm::_from_raw($cfunc(f)) } // Self { // data: unsafe { $cfunc(f) }, // spec: PhantomData,