diff --git a/slj/src/main.rs b/slj/src/main.rs index 283da06..1c27f6d 100644 --- a/slj/src/main.rs +++ b/slj/src/main.rs @@ -2,12 +2,203 @@ lalrpop_mod!(pub grammar); use anyhow::Result; -use std::rc::Rc; +use std::cell::Cell; +//use std::rc::Rc; use sl::eval; +use std::marker::PhantomData; +use std::ops::Deref; +use std::ptr::NonNull; +use std::mem::ManuallyDrop; + +use std::fmt; + +#[repr(C)] +pub struct Rc { + ptr: NonNull>, + phantom: PhantomData> +} +#[repr(C)] +pub struct RcInner { + rc: Cell, + data: T, +} +impl Rc { + pub fn new(data: T) -> Rc { + let boxed = Box::new(RcInner { rc: Cell::new(1), data }); + Rc { + ptr: NonNull::new(Box::into_raw(boxed)).unwrap(), + phantom: PhantomData, + } + } + pub fn into_ptr(self) -> *mut RcInner { + ManuallyDrop::new(self).ptr.as_ptr() as *mut RcInner + } + pub fn from_ptr(ptr: *mut RcInner) -> Self { + Rc { + ptr: NonNull::new(ptr).unwrap(), + phantom: PhantomData, + } + } +} +unsafe impl Send for Rc {} +unsafe impl Sync for Rc {} +impl Deref for Rc { + type Target = T; + fn deref(&self) -> &T { + let inner = unsafe { self.ptr.as_ref() }; + &inner.data + } +} +impl Clone for Rc { + fn clone(&self) -> Rc { + let inner = unsafe { self.ptr.as_ref() }; + let old = inner.rc.get(); + inner.rc.set(old + 1); + if old > isize::MAX as usize { + std::process::abort(); + } + Self { + ptr: self.ptr, + phantom: PhantomData, + } + } +} +impl Drop for Rc { + fn drop(&mut self) { + let inner = unsafe { self.ptr.as_mut() }; + let old = inner.rc.get(); + inner.rc.set(old - 1); + if old != 1 { + return; + } + unsafe { drop(Box::from_raw(self.ptr.as_ptr())); } + } +} + + +/* +pub enum Form { + Nil, + Int(i32), + Bool(bool), + Symbol(String), + Pair(Rc
, Rc), + Closure(Vec, Rc, Rc, ID), + Prim(Prim), +} +*/ +#[repr(C)] +struct Form { + data: *const Form, + phantom: PhantomData +} +#[repr(C)] +struct FormPair { + car: Form, + cdr: Form, +} +/* + * this better be a 64 bit platform + * huh, if we only support i32s, then we have a lot more room for tags + * 8 byte alignment gets us 3 bits, or uh 8 options + * we'll choose 000 for ints to make math easy + * + * 000 - Int + * 001 - Nil + * 010 - Bool(false) // this is needlessly wasteful of the bits but hay + * 011 - Bool(true) + * 100 - Symbol - will want to convert into an Rc around a StringRawParts struct + * 101 - Pair - an Rc around a Pair struct + * 110 - Closure- eek: Closure(Vec, Rc, Rc, ID), + * xxxx 111 - Prim (xxxx for which one) + * + * I don't actually think we need our own repr(C) Vec implementation, at least not for now - we can + * make do with a VecRawParts struct (without implementations) + * + * in both cases, StringRawParts and VecRawParts, we can rebuild slices from the raw parts for + * read-only access, which is all we need (until Drop, at which point we should re-constitute them + * from their raw parts, which is stable) + */ +impl Form { + fn new_int(x: isize) -> Self { + Self { data: (x << 3) as *const Form, phantom: PhantomData } + } + fn new_nil() -> Self { + Self { data: 0b001 as *const Form, phantom: PhantomData } + } + fn new_bool(b: bool) -> Self { + Self { data: (if b { 0b011 } else { 0b010 }) as *const Form, phantom: PhantomData } + } + fn new_pair(car: Form, cdr: Form) -> Self { + let p = Rc::new(FormPair { car, cdr }).into_ptr() as usize; + assert!(p & 0b111 == 0); + Self { data: (p | 0b101) as *const Form, phantom: PhantomData } + } +} +impl Drop for Form { + fn drop(&mut self) { + match self.data as usize & 0b111 { + 0b000 | 0b001 | 0b010 | 0b011 => { println!("dropping simple {self}"); }, // int, nil, false, true + 0b101 => { + // pair + let _ = Rc::::from_ptr( (self.data as usize & !0b111) as *mut RcInner ); + }, + _ => unreachable!(), + } + } +} +impl fmt::Display for Form { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self.data as usize & 0b111 { + 0b000 => { + write!(f, "{}", self.data as isize >> 3)?; + }, + 0b001 => { + write!(f, "nil")?; + }, + 0b010 => { + write!(f, "false")?; + }, + 0b011 => { + write!(f, "true")?; + }, + 0b101 => { + write!(f, "pair")?; + }, + _ => unreachable!(), + } + Ok(()) + } +} + + + +fn alias(a: Rc, b: Rc) { + println!("a: {}, b: {}", *a, *b); +} fn main() -> Result<()> { + // our Form shennigins will only work on 64 bit platforms + assert!(std::mem::size_of::() == 8); + + let x = Rc::new(1); + alias(Rc::clone(&x), x); + let rc_u64_size = std::mem::size_of::>(); + assert!(rc_u64_size == 8); + println!("for our Rc, we have size {}", rc_u64_size); + + let i = Form::new_int(23); + let n = Form::new_nil(); + let bf = Form::new_bool(false); + let bt = Form::new_bool(true); + + let p = Form::new_pair(Form::new_int(50), Form::new_nil()); + println!("{i} {n} {bf} {bt} {p}"); + + + /* let input = " (begin (debug 1) @@ -68,5 +259,6 @@ fn main() -> Result<()> { println!("Hello, world: {parsed_input}"); let evaled = eval(Rc::clone(&parsed_input))?; println!("evaled: {evaled}"); + */ Ok(()) }