Refactor codegen into more pieces

This commit is contained in:
Yehuda Katz 2017-04-21 16:22:01 -07:00
parent 4ebf9e9da5
commit ea51eeb654
5 changed files with 201 additions and 127 deletions

39
src/macros/alloc.rs Normal file
View File

@ -0,0 +1,39 @@
#[macro_export]
macro_rules! codegen_allocator {
({
type: class,
name: $name:tt,
meta: $meta:tt,
struct: (),
methods: $methods:tt
}) => ();
({
type: class,
name: $cls:tt,
meta: { pub: $pub:tt, reopen: false },
struct: $struct:tt,
methods: [ $($method:tt)* ]
}) => (
impl $cls {
extern "C" fn __mark__(_klass: &$cls) {}
extern "C" fn __free__(_klass: Option<Box<$cls>>) {}
#[inline]
fn __alloc_with__(rust_self: Option<Box<$cls>>) -> $crate::sys::VALUE {
use ::std::mem::transmute;
unsafe {
let instance = $crate::sys::Data_Wrap_Struct(
transmute($cls),
transmute($cls::__mark__ as usize),
transmute($cls::__free__ as usize),
transmute(rust_self)
);
instance
}
}
}
)
}

View File

@ -1,11 +1,19 @@
#[macro_export]
macro_rules! codegen {
{ [ $($ast:tt)* ] } => {
codegen! {
type: top,
classes: [],
buffer: [ $($ast)* ]
mod init_native {
codegen! {
type: top,
classes: [],
buffer: [ $($ast)* ]
}
codegen_init! { [ $($ast)* ] }
}
codegen_pub_classes!($($ast)*);
pub use self::init_native::Init_native;
};
{
@ -47,6 +55,14 @@ macro_rules! codegen {
],
buffer: [ $($rest)* ]
}
codegen_extra_impls!({
type: class,
name: $name,
meta: { pub: $pub, reopen: $reopen },
struct: $struct,
methods: [ $($method)* ]
});
};
{
@ -69,6 +85,41 @@ macro_rules! codegen {
};
}
#[macro_export]
macro_rules! codegen_pub_classes {
{
$({
type: class,
name: $name:tt,
meta: { pub: $pub:tt, reopen: $reopen:tt },
struct: $struct:tt,
methods: [ $($method:tt)* ]
})*
} => {
$(
codegen_pub_classes! {
type: class,
name: $name,
pub: $pub
}
)*
};
{
type: class,
name: $name:tt,
pub: false
} => {};
{
type: class,
name: $name:tt,
pub: true
} => {
pub use self::init_native::$name;
};
}
#[macro_export]
macro_rules! codegen_struct {
{ pub: false, name: $name:tt, struct: () } => {
@ -151,3 +202,11 @@ macro_rules! codegen_method {
pub fn $name($($ownership)* $self, $($args)*) -> $($ret)* $body
};
}
#[macro_export]
macro_rules! codegen_extra_impls {
($class:tt) => (
codegen_allocator!($class);
codegen_coercions!($class);
)
}

97
src/macros/coercions.rs Normal file
View File

@ -0,0 +1,97 @@
#[macro_export]
macro_rules! codegen_coercions {
({
type: class,
name: $cls:tt,
meta: { pub: $pub:tt, reopen: $reopen:tt },
struct: (),
methods: $methods:tt
}) => (
impl $crate::UncheckedValue<$cls> for $crate::sys::VALUE {
fn to_checked(self) -> $crate::CheckResult<$cls> {
use $crate::{CheckedValue, sys};
use ::std::ffi::{CStr};
if unsafe { $cls == ::std::mem::transmute(sys::rb_obj_class(self)) } {
Ok(unsafe { CheckedValue::new(self) })
} else {
let val = unsafe { CStr::from_ptr(sys::rb_obj_classname(self)).to_string_lossy() };
Err(format!("No implicit conversion of {} into {}", val, stringify!($cls)))
}
}
}
impl $crate::ToRust<$cls> for $crate::CheckedValue<$cls> {
fn to_rust(self) -> $cls {
$cls { helix: self.inner }
}
}
impl_to_ruby!(&'a $cls);
impl_to_ruby!(&'a mut $cls);
);
({
type: class,
name: $cls:tt,
meta: { pub: $pub:tt, reopen: false },
struct: $struct:tt,
methods: $methods:tt
}) => (
impl_struct_to_rust!(&'a $cls, $cls);
impl_struct_to_rust!(&'a mut $cls, $cls);
impl $crate::ToRuby for $cls {
fn to_ruby(self) -> $crate::sys::VALUE {
$cls::__alloc_with__(Some(Box::new(self)))
}
}
impl_to_ruby!(&'a $cls);
impl_to_ruby!(&'a mut $cls);
);
}
#[doc(hidden)]
#[macro_export]
macro_rules! impl_to_ruby {
($cls:ty) => {
item! {
impl<'a> $crate::ToRuby for $cls {
fn to_ruby(self) -> $crate::sys::VALUE {
self.helix
}
}
}
}
}
#[macro_export]
macro_rules! impl_struct_to_rust {
($cls:ty, $helix_id:tt) => {
impl<'a> $crate::ToRust<$cls> for $crate::CheckedValue<$cls> {
fn to_rust(self) -> $cls {
unsafe { ::std::mem::transmute($crate::sys::Data_Get_Struct_Value(self.inner)) }
}
}
impl<'a> $crate::UncheckedValue<$cls> for $crate::sys::VALUE {
fn to_checked(self) -> $crate::CheckResult<$cls> {
use $crate::{CheckedValue, sys};
use ::std::ffi::{CStr};
if unsafe { $helix_id == ::std::mem::transmute(sys::rb_obj_class(self)) } {
if unsafe { $crate::sys::Data_Get_Struct_Value(self) == ::std::ptr::null_mut() } {
Err(format!("Uninitialized {}", $crate::inspect(unsafe { sys::rb_obj_class(self) })))
} else {
Ok(unsafe { CheckedValue::new(self) })
}
} else {
let val = unsafe { CStr::from_ptr(sys::rb_obj_classname(self)).to_string_lossy() };
Err(format!("No implicit conversion of {} into {}", val, $crate::inspect(unsafe { sys::rb_obj_class(self) })))
}
}
}
}
}

View File

@ -6,8 +6,8 @@ macro_rules! codegen_init {
pub extern "C" fn Init_native() {
$crate::sys::check_version();
$(
codegen_class_coercions!($class);
codegen_class_binding!($class, $class);
)*
}
@ -59,31 +59,8 @@ macro_rules! codegen_class_binding {
} } => ({
use ::std::mem::transmute;
extern "C" fn __mark__(_klass: &$cls) {}
extern "C" fn __free__(_klass: Option<Box<$cls>>) {}
extern "C" fn __alloc__(_klass: $crate::sys::VALUE) -> $crate::sys::VALUE {
__alloc_with__(None)
}
impl $cls {
fn __alloc_with__(rust_self: Option<Box<$cls>>) -> $crate::sys::VALUE {
__alloc_with__(rust_self)
}
}
#[inline]
fn __alloc_with__(rust_self: Option<Box<$cls>>) -> $crate::sys::VALUE {
unsafe {
let instance = $crate::sys::Data_Wrap_Struct(
transmute($cls),
transmute(__mark__ as usize),
transmute(__free__ as usize),
transmute(rust_self)
);
instance
}
$cls::__alloc_with__(None)
}
let def = $crate::ClassDefinition::wrapped(cstr!(stringify!($cls)), __alloc__);
@ -301,60 +278,6 @@ macro_rules! codegen_define_method {
});
}
#[macro_export]
macro_rules! codegen_class_coercions {
({
type: class,
name: $cls:tt,
meta: { pub: $pub:tt, reopen: $reopen:tt },
struct: (),
methods: $methods:tt
}) => (
impl $crate::UncheckedValue<$cls> for $crate::sys::VALUE {
fn to_checked(self) -> $crate::CheckResult<$cls> {
use $crate::{CheckedValue, sys};
use ::std::ffi::{CStr};
if unsafe { $cls == ::std::mem::transmute(sys::rb_obj_class(self)) } {
Ok(unsafe { CheckedValue::new(self) })
} else {
let val = unsafe { CStr::from_ptr(sys::rb_obj_classname(self)).to_string_lossy() };
Err(format!("No implicit conversion of {} into {}", val, stringify!($cls)))
}
}
}
impl $crate::ToRust<$cls> for $crate::CheckedValue<$cls> {
fn to_rust(self) -> $cls {
$cls { helix: self.inner }
}
}
impl_to_ruby!(&'a $cls);
impl_to_ruby!(&'a mut $cls);
);
({
type: class,
name: $cls:tt,
meta: { pub: $pub:tt, reopen: false },
struct: $struct:tt,
methods: $methods:tt
}) => (
impl_struct_to_rust!(&'a $cls, $cls);
impl_struct_to_rust!(&'a mut $cls, $cls);
impl $crate::ToRuby for $cls {
fn to_ruby(self) -> $crate::sys::VALUE {
$cls::__alloc_with__(Some(Box::new(self)))
}
}
impl_to_ruby!(&'a $cls);
impl_to_ruby!(&'a mut $cls);
);
}
#[macro_export]
macro_rules! codegen_self_pointer_type {
@ -375,49 +298,6 @@ macro_rules! codegen_self_pointer_type {
};
}
#[doc(hidden)]
#[macro_export]
macro_rules! impl_to_ruby {
($cls:ty) => {
item! {
impl<'a> $crate::ToRuby for $cls {
fn to_ruby(self) -> $crate::sys::VALUE {
self.helix
}
}
}
}
}
#[macro_export]
macro_rules! impl_struct_to_rust {
($cls:ty, $helix_id:tt) => {
impl<'a> $crate::ToRust<$cls> for $crate::CheckedValue<$cls> {
fn to_rust(self) -> $cls {
unsafe { ::std::mem::transmute($crate::sys::Data_Get_Struct_Value(self.inner)) }
}
}
impl<'a> $crate::UncheckedValue<$cls> for $crate::sys::VALUE {
fn to_checked(self) -> $crate::CheckResult<$cls> {
use $crate::{CheckedValue, sys};
use ::std::ffi::{CStr};
if unsafe { $helix_id == ::std::mem::transmute(sys::rb_obj_class(self)) } {
if unsafe { $crate::sys::Data_Get_Struct_Value(self) == ::std::ptr::null_mut() } {
Err(format!("Uninitialized {}", $crate::inspect(unsafe { sys::rb_obj_class(self) })))
} else {
Ok(unsafe { CheckedValue::new(self) })
}
} else {
let val = unsafe { CStr::from_ptr(sys::rb_obj_classname(self)).to_string_lossy() };
Err(format!("No implicit conversion of {} into {}", val, $crate::inspect(unsafe { sys::rb_obj_class(self) })))
}
}
}
}
}
#[macro_export]
macro_rules! method_arity {
( $($arg:tt)* ) => {

View File

@ -76,7 +76,6 @@ macro_rules! parse {
stack: { ast: $ast:tt }
} => {
codegen! { $ast }
codegen_init! { $ast }
};
{