from-scratch/stages/lisp0/lisp.rs
2026-06-30 20:27:06 +02:00

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() });
}