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; } struct Source<'a> { iter: core::iter::Peekable>, } 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 = 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::().as_mut().unwrap() += 1; // } // Self(self.0) // } // } // impl Drop for Object { // fn drop(&mut self) { // unsafe { // *self.ptr().cast::().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::().read(); let cdr = self.ptr().byte_add(16).cast::().read(); write!(f, "({car:?} . {cdr:?})") }, 2 => unsafe { let car = self.ptr().byte_add(8).cast::().read(); let cdr = self.ptr().byte_add(16).cast::().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::().read() as usize; let slice = core::slice::from_raw_parts(str_ptr, len); let string = core::str::from_utf8(slice).unwrap_or(""); 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::().read() as usize; let slice = core::slice::from_raw_parts(str_ptr, len); let string = core::str::from_utf8(slice).unwrap_or(""); write!(f, "\"{string}\"") }, 4 => unsafe { let num = self.ptr().byte_add(8).cast::().read(); write!(f, "{num}") }, 5 => unsafe { write!(f, "#") }, _ => write!(f, "#", 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"(+ (+ 1 2) 3)"; let mut src = Source::from(&input[..]); let sexp = unsafe { parse_next_token(&raw mut src) }; println!("{:?}", sexp); let result = unsafe { eval(sexp, get_env()) }; println!("{:?}", result); }