from-scratch/stages/lisp0/lisp.rs
2026-06-09 00:09:07 +02:00

138 lines
4.1 KiB
Rust

unsafe extern "C" {
fn init_atoms();
fn parse_next_token(src: *mut Source<'_>) -> Object;
fn init_env() -> Object;
}
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);
}
}
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 {
match self.tag() {
0 => write!(f, "nil"),
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 cdr = self.ptr().byte_add(16).cast::<Object>().read();
write!(f, "(λ {car:?} {cdr:?})")
},
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: {:?}", env);
let input = b"('a 3 4 5)";
let mut src = Source::from(&input[..]);
let sexp = unsafe { parse_next_token(&raw mut src) };
println!("{:?}", sexp);
}