191 lines
5.7 KiB
Rust
191 lines
5.7 KiB
Rust
unsafe extern "C" {
|
|
fn init_atoms();
|
|
fn parse_next_token(src: *mut Source<'_>) -> Object;
|
|
fn init_env() -> Object;
|
|
fn eval(expr: Object, env: Object) -> Object;
|
|
fn get_env() -> Object;
|
|
|
|
#[link_name = "nil"]
|
|
static NIL: ();
|
|
#[link_name = "env"]
|
|
static mut GENV: ();
|
|
}
|
|
|
|
struct Source<'a> {
|
|
iter: core::iter::Peekable<core::slice::Iter<'a, u8>>,
|
|
}
|
|
|
|
impl<'a> From<&'a [u8]> for Source<'a> {
|
|
fn from(value: &'a [u8]) -> Self {
|
|
Self {
|
|
iter: value.iter().peekable(),
|
|
}
|
|
}
|
|
}
|
|
|
|
#[unsafe(no_mangle)]
|
|
extern "C" fn peekc(src: *mut Source) -> u8 {
|
|
unsafe { (*src).iter.peek().cloned().unwrap_or(&0).clone() }
|
|
}
|
|
|
|
#[unsafe(no_mangle)]
|
|
extern "C" fn getc(src: *mut Source) -> u8 {
|
|
unsafe { (*src).iter.next().unwrap_or(&0).clone() }
|
|
}
|
|
|
|
#[unsafe(no_mangle)]
|
|
extern "C" fn alloc(size: usize, align: usize) -> *mut u8 {
|
|
let layout = core::alloc::Layout::from_size_align(size, align).unwrap();
|
|
unsafe { std::alloc::alloc(layout) }
|
|
}
|
|
|
|
#[unsafe(no_mangle)]
|
|
extern "C" fn dealloc(ptr: *mut u8, size: usize, align: usize) {
|
|
let layout = core::alloc::Layout::from_size_align(size, align).unwrap();
|
|
unsafe { std::alloc::dealloc(ptr, layout) }
|
|
}
|
|
|
|
#[unsafe(no_mangle)]
|
|
extern "C" fn panic_abort(cstr: *const u8) -> ! {
|
|
if cstr.is_null() {
|
|
panic!("abort");
|
|
} else {
|
|
let mut len = 0;
|
|
while unsafe { *cstr.add(len) } != 0 {
|
|
len += 1;
|
|
}
|
|
let slice = unsafe { core::slice::from_raw_parts(cstr, len) };
|
|
let message = core::str::from_utf8(slice).unwrap_or("abort");
|
|
panic!("{}", message);
|
|
}
|
|
}
|
|
|
|
#[unsafe(no_mangle)]
|
|
extern "C" fn print(obj: Object) {
|
|
println!("{:?}", obj);
|
|
}
|
|
|
|
static mut ENV_INIT: std::cell::LazyCell<Object> =
|
|
std::cell::LazyCell::new(|| unsafe { init_env() });
|
|
|
|
#[repr(C)]
|
|
#[derive(Copy, Clone)]
|
|
struct Object(*mut ());
|
|
|
|
// impl Clone for Object {
|
|
// fn clone(&self) -> Self {
|
|
// unsafe {
|
|
// *self.ptr().cast::<u32>().as_mut().unwrap() += 1;
|
|
// }
|
|
// Self(self.0)
|
|
// }
|
|
// }
|
|
|
|
// impl Drop for Object {
|
|
// fn drop(&mut self) {
|
|
// unsafe {
|
|
// *self.ptr().cast::<u32>().as_mut().unwrap() -= 1;
|
|
// }
|
|
// }
|
|
// }
|
|
|
|
use std::fmt;
|
|
impl fmt::Debug for Object {
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
if self.0 as *const () == &raw const NIL {
|
|
return write!(f, "nil");
|
|
}
|
|
match self.tag() {
|
|
0 => write!(f, "'{}'", (self.0.addr() >> 8) as u8 as char),
|
|
1 => unsafe {
|
|
let car = self.ptr().byte_add(8).cast::<Object>().read();
|
|
let cdr = self.ptr().byte_add(16).cast::<Object>().read();
|
|
write!(f, "({car:?} . {cdr:?})")
|
|
},
|
|
2 => unsafe {
|
|
let car = self.ptr().byte_add(8).cast::<Object>().read();
|
|
let env = self.ptr().byte_add(16).cast::<Object>().read();
|
|
assert_eq!(
|
|
car.tag(),
|
|
1,
|
|
"Expected a pair for lambda cdr, got tag {}",
|
|
car.tag()
|
|
);
|
|
let params = car.ptr().byte_add(8).cast::<Object>().read();
|
|
let body = car.ptr().byte_add(16).cast::<Object>().read();
|
|
|
|
write!(f, "λ ")?;
|
|
if env.0 as *const () == &raw const GENV || env.0 as *const () == &raw const NIL {
|
|
write!(f, " #<g_env> ++ ")?;
|
|
} else {
|
|
write!(f, " {env:?} ++ ")?;
|
|
}
|
|
write!(f, "{params:?} {body:?})")
|
|
},
|
|
3 => unsafe {
|
|
let str_ptr = self.ptr().byte_add(8).cast::<*const u8>().read();
|
|
let len = self.ptr().byte_add(4).cast::<u32>().read() as usize;
|
|
let slice = core::slice::from_raw_parts(str_ptr, len);
|
|
let string = core::str::from_utf8(slice).unwrap_or("<invalid utf-8>");
|
|
write!(f, "'{string}")
|
|
},
|
|
6 => unsafe {
|
|
let str_ptr = self.ptr().byte_add(8).cast::<*const u8>().read();
|
|
let len = self.ptr().byte_add(4).cast::<u32>().read() as usize;
|
|
let slice = core::slice::from_raw_parts(str_ptr, len);
|
|
let string = core::str::from_utf8(slice).unwrap_or("<invalid utf-8>");
|
|
write!(f, "\"{string}\"")
|
|
},
|
|
4 => unsafe {
|
|
let num = self.ptr().byte_add(8).cast::<u64>().read();
|
|
write!(f, "{num}")
|
|
},
|
|
5 => unsafe { write!(f, "#<prim>") },
|
|
_ => write!(f, "#<unknown tag {}>", self.tag()),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl Object {
|
|
fn tag(&self) -> u8 {
|
|
self.0.addr() as u8 & 0b111
|
|
}
|
|
fn ptr(&self) -> *mut () {
|
|
self.0.map_addr(|addr| addr & !0b111)
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn test_parse_list() {
|
|
let env = unsafe { *ENV_INIT };
|
|
println!("env: {:?}\n", env);
|
|
|
|
// let input = b"(let ((x 10) (y 20)) (+ x y))";
|
|
let input = b"(if () 1 2)";
|
|
let hello_world = b"(let* (
|
|
(msg \"hello world\\n\")
|
|
(msg-parts (str-parts msg))
|
|
(ptr (car msg-parts))
|
|
(len (cdr msg-parts))
|
|
(fd 1))
|
|
(syscall 1 fd ptr len))";
|
|
// let math = br#"
|
|
// (let (
|
|
// (a (< 1 2))
|
|
// (b (< 2 1))
|
|
// (c (+ 1 2 3))
|
|
// (d (* 2 3 4))
|
|
// (e (/ 10 2))
|
|
// (f (% 10 3))
|
|
// )
|
|
// (print-env)
|
|
// )
|
|
// "#;
|
|
let mut src = Source::from(&hello_world[..]);
|
|
let sexp = unsafe { parse_next_token(&raw mut src) };
|
|
println!("> {:?}", sexp);
|
|
let result = unsafe { eval(sexp, get_env()) };
|
|
println!("{:?}\n", result);
|
|
println!("env: {:?}", unsafe { get_env() });
|
|
}
|