~tim/scheme-vm

82e799de37eb74f44fef9422a1cc72e4a56ac1fa — Tim Morgan 4 years ago ac6b8bc
Use ruby-sys to integrate better with Ruby
3 files changed, 77 insertions(+), 14 deletions(-)

M src/lib.rs
A src/rb.rs
M test.rb
M src/lib.rs => src/lib.rs +12 -12
@@ 4,24 4,24 @@ extern crate ruby_sys;
mod values;
mod tests;

#[macro_use] mod rb;
use rb::{CallbackPtr, Value, RB_TRUE, RB_FALSE};

mod lisp {
    include!(concat!(env!("OUT_DIR"), "/lisp.rs"));
}

#[no_mangle]
pub extern "C" fn is_ok(program_ptr: *const libc::c_char) -> i64 {
    let program = string_from_c_ptr(program_ptr);
    if lisp::program(&program).is_ok() {
        0x14
fn is_ok(_rself: Value, program: Value) -> Value {
    let program_str = rbstr2str!(&program);
    if lisp::program(&program_str).is_ok() {
        RB_TRUE
    } else {
        0
        RB_FALSE
    }
}

fn string_from_c_ptr(c_ptr: *const libc::c_char) -> String {
    let c_str = unsafe {
        assert!(!c_ptr.is_null());
        std::ffi::CStr::from_ptr(c_ptr)
    };
    c_str.to_str().unwrap().to_string()
#[no_mangle]
pub extern fn init_parser() {
  let m_parser = rb::define_module("Parser");
  rb::define_singleton_method(&m_parser, "ok?", is_ok as CallbackPtr, 1);
}

A src/rb.rs => src/rb.rs +62 -0
@@ 0,0 1,62 @@
// borrowed from https://github.com/ubcsanskrit/sanscript.rb (MIT)

use ruby_sys::class;
use ruby_sys::value::RubySpecialConsts::{Nil, True, False};

pub use ruby_sys::types::{CallbackPtr, Value};

pub const RB_NIL: Value = Value { value: Nil as usize };
pub const RB_TRUE: Value = Value { value: True as usize };
pub const RB_FALSE: Value = Value { value: False as usize };

//
// Helper functions/macros for dealing with Ruby and CStrings
//

macro_rules! str2cstr {
  ($s:expr) => { ::std::ffi::CString::new($s).unwrap() }
}

macro_rules! str2cstrp {
  ($s:expr) => { str2cstr!($s).as_ptr() }
}

macro_rules! rbstr2cstrp {
  ($s:expr) => { ::ruby_sys::string::rb_string_value_cstr($s) }
}

macro_rules! rbstr2str {
  ($s:expr) => {
    unsafe { ::std::ffi::CStr::from_ptr(rbstr2cstrp!($s)).to_str().unwrap() }
  }
}

macro_rules! str2rbid {
  ($s:expr) => { ::ruby_sys::util::rb_intern(str2cstrp!($s)) }
}

macro_rules! str2sym {
  ($s:expr) => {
    unsafe { ::ruby_sys::symbol::rb_id2sym(str2rbid!($s)) }
  }
}

pub fn define_module(name: &str) -> Value {
  unsafe { class::rb_define_module(str2cstrp!(name)) }
}

pub fn define_module_under(parent: &Value, name: &str) -> Value {
  unsafe { class::rb_define_module_under(*parent, str2cstrp!(name)) }
}

pub fn define_method(module: &Value, name: &str, method: CallbackPtr, argc: i32) {
  unsafe { class::rb_define_method(*module, str2cstrp!(name), method, argc) }
}

pub fn define_singleton_method(module: &Value, name: &str, method: CallbackPtr, argc: i32) {
  unsafe { class::rb_define_singleton_method(*module, str2cstrp!(name), method, argc) }
}

pub fn extend_object(object: &Value, module: &Value) {
  unsafe { class::rb_extend_object(*object, *module) }
}

M test.rb => test.rb +3 -2
@@ 1,6 1,7 @@
require 'fiddle'

library = Fiddle::dlopen('target/release/libscheme_vm.dylib')
is_ok = Fiddle::Function.new(library['is_ok'], [Fiddle::TYPE_VOIDP], Fiddle::TYPE_VOIDP)
init_parser = Fiddle::Function.new(library['init_parser'], [], Fiddle::TYPE_VOID)
init_parser.call

p is_ok.call(ARGV.first)
p Parser.ok?(ARGV.first)