~jojo/Carth

90a524f8ccb200737738903ceb93727abf431c8c — JoJo 1 year, 11 months ago 1e75b80
Add FFI functions display-inline, str-append

Also add hello-world.carth, making use of these.
3 files changed, 86 insertions(+), 9 deletions(-)

A examples/hello-world.carth
D examples/test.carth
M foreign-core/src/lib.rs
A examples/hello-world.carth => examples/hello-world.carth +15 -0
@@ 0,0 1,15 @@
(extern display-inline (Fun Str Unit))
(extern str-append (Fun (Pair Str Str) Str))

(type (Pair a b)
  (Pair a b))

(define (main _)
  (display "Hello, world!"))

(define (display s)
  (display-inline (str-append (Pair s "\n"))))

(define (flip f a b) (f b a))
(define (after f g a) (f (g a)))
(define (after2 f g a b) (f (g a b)))

D examples/test.carth => examples/test.carth +0 -4
@@ 1,4 0,0 @@
(extern print-int (Fun Int Unit))

(define (main _)
  (print-int 123))

M foreign-core/src/lib.rs => foreign-core/src/lib.rs +71 -5
@@ 1,6 1,7 @@
#![feature(const_fn)]

use std::ptr;
use std::io::{self, Write};
use std::{alloc, ptr, slice, str};

pub type Captures = *const ();
pub type ClosureFunc<A, B> = extern "C" fn(Captures, A) -> B;


@@ 22,9 23,74 @@ impl<A, B> Closure<A, B> {
    }
}

#[export_name = "print-int"]
pub static PRINT_INT: Closure<i64, ()> = Closure::new(print_int);
#[repr(C)]
pub struct Array<A> {
    _tag: u64,
    elems: *mut A,
    len: u64,
}

impl<A> Array<A> {
    fn new(xs: Vec<A>) -> Array<A> {
        let len = xs.len() as u64;
        Array {
            _tag: 0,
            elems: Box::into_raw(xs.into_boxed_slice()) as *mut A,
            len,
        }
    }
}

#[repr(C)]
pub struct Str {
    _tag: u64,
    array: Array<u8>,
}

impl Str {
    fn new(s: String) -> Str {
        Str {
            _tag: 0,
            array: Array::new(s.into_bytes()),
        }
    }
}

#[repr(C)]
pub struct Pair<A, B> {
    _tag: u64,
    fst: A,
    snd: B,
}

// TODO: Do it properly.
//       https://en.cppreference.com/w/c/types/max_align_t
const MAX_ALIGN: usize = 8;

#[no_mangle]
pub extern "C" fn carth_alloc(size: u64) -> *mut u8 {
    unsafe { alloc::alloc(alloc::Layout::from_size_align(size as usize, MAX_ALIGN).unwrap()) }
}

#[export_name = "display-inline"]
pub static DISPLAY_INLINE: Closure<*const Str, ()> = Closure::new(display_inline_f);
pub extern "C" fn display_inline_f(_: Captures, s: *const Str) {
    let s = unsafe { from_carth_str(&*s) };
    print!("{}", s);
    io::stdout().flush().ok();
}

pub extern "C" fn print_int(_: Captures, n: i64) {
    println!("{}", n)
#[export_name = "str-append"]
pub static STR_APPEND: Closure<*const Pair<Str, Str>, Str> = Closure::new(str_append_f);
pub extern "C" fn str_append_f(_: Captures, pair: *const Pair<Str, Str>) -> Str {
    let (s1, s2) = unsafe { (from_carth_str(&(*pair).fst), from_carth_str(&(*pair).snd)) };
    Str::new(s1.to_string() + s2)
}

fn from_carth_str(s: &Str) -> &str {
    unsafe {
        let Array { elems, len, .. } = (*s).array;
        let slice = slice::from_raw_parts(elems, len as usize);
        str::from_utf8_unchecked(slice)
    }
}