diff --git a/src/main.rs b/src/main.rs index af57342..690b804 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,4 +1,9 @@ +#![allow(dead_code)] +#![feature(new_uninit)] + mod syn; +mod obj; +mod mem; use std::{ convert::TryFrom, diff --git a/src/mem/basic.rs b/src/mem/basic.rs new file mode 100644 index 0000000..0d8d495 --- /dev/null +++ b/src/mem/basic.rs @@ -0,0 +1,71 @@ +use crate::{ + mem::{ + gc::Gc, + intern::Intern, + ptr::{DynRef, ObjCell, ObjRef}, + }, + obj::{ctx::ObjCtx, Obj, Str, Sym}, +}; +use std::{collections::HashMap, ptr::NonNull}; + +pub struct BasicGc { + objects: Vec>>, + strs: HashMap>, + syms: HashMap, +} + +impl Gc for BasicGc { + fn alloc(&mut self, obj: O) -> ObjRef { + let obj_cell = Box::new(ObjCell::new(obj)); + let obj_ptr = &*obj_cell as *const _ as *mut _; + self.objects.push(obj_cell); + ObjRef::new(NonNull::new(obj_ptr).unwrap()) + } + + fn add_obj(&mut self, owned: Box>) { + self.objects.push(owned); + } + + fn mark(&mut self, alive: &[DynRef]) { + for obj in alive.iter() { + obj.borrow().mark(); + } + // TODO : where should interned strings be marked? + } + + fn sweep(&mut self) { + // sweep + self.objects.retain(|cell| { + let obj = cell.borrow(); + !obj.is_marked() + }); + // unmark all objects + self.objects + .iter_mut() + .for_each(|cell| cell.borrow().unmark()); + } +} + +impl Intern for BasicGc { + fn get_str(&self, s: &str) -> Option> { + self.strs.get(s).copied() + } + + fn add_str(&mut self, ctx: &mut ObjCtx, s: &str) -> ObjRef { + *self.strs.entry(s.to_string()) + .or_insert_with(|| { + let s = Str::new(ctx, s.to_string()); + ctx.gc_mut().alloc(s) + }) + } + + fn get_sym(&self, s: &str) -> Option { + self.syms.get(s).copied() + } + + fn add_sym(&mut self, s: &str) -> Sym { + let len = self.syms.len(); + *self.syms.entry(s.to_string()) + .or_insert_with(|| len) + } +} diff --git a/src/mem/gc.rs b/src/mem/gc.rs new file mode 100644 index 0000000..06df5c1 --- /dev/null +++ b/src/mem/gc.rs @@ -0,0 +1,22 @@ +use crate::{ + obj::prelude::*, + mem::{ + ptr::ObjCell, + intern::Intern, + } +}; + +pub trait Gc: Intern { + fn alloc(&mut self, obj: O) -> ObjRef; + + fn add_obj(&mut self, owned: Box>); + + fn mark(&mut self, alive: &[DynRef]) { + for obj in alive.iter() { + obj.borrow_mut().mark(); + } + } + + fn sweep(&mut self); +} + diff --git a/src/mem/intern.rs b/src/mem/intern.rs new file mode 100644 index 0000000..8c36f44 --- /dev/null +++ b/src/mem/intern.rs @@ -0,0 +1,15 @@ +use crate::{ + mem::ptr::ObjRef, + obj::{ + ctx::ObjCtx, + Str, Sym, + }, +}; + +pub trait Intern { + fn get_str(&self, s: &str) -> Option>; + fn add_str(&mut self, ctx: &mut ObjCtx, s: &str) -> ObjRef; + + fn get_sym(&self, s: &str) -> Option; + fn add_sym(&mut self, s: &str) -> Sym; +} diff --git a/src/mem/mod.rs b/src/mem/mod.rs new file mode 100644 index 0000000..c13c41a --- /dev/null +++ b/src/mem/mod.rs @@ -0,0 +1,16 @@ +mod basic; +pub mod intern; +pub mod gc; +pub mod ptr; + +pub use self::basic::BasicGc; + +/* +pub mod prelude { + pub use crate::mem::{ + alloc::Alloc, + gc::Gc, + ptr::* + } +} +*/ diff --git a/src/mem/ptr.rs b/src/mem/ptr.rs new file mode 100644 index 0000000..c38784b --- /dev/null +++ b/src/mem/ptr.rs @@ -0,0 +1,130 @@ +use crate::obj::Obj; +use std::{ + any, + cell::RefCell, + fmt::{self, Debug, Formatter}, + ops::Deref, + ptr::NonNull, +}; + +pub type DynRef = ObjRef; + +pub struct ObjRef + where O: Obj + ?Sized +{ + ptr: NonNull>, +} + +impl ObjRef + where O: Obj + ?Sized +{ + pub fn new(ptr: NonNull>) -> Self { + ObjRef { ptr } + } + + pub fn as_ptr(&self) -> *const ObjCell { + self.ptr.as_ptr() + } +} + +impl ObjRef + where O: Obj +{ + pub fn as_dyn(&self) -> ObjRef { + let ptr = self.as_ptr() as *const ObjCell; + ObjRef::new(NonNull::new(ptr as *mut _).unwrap()) + } +} + +impl Deref for ObjRef + where O: Obj + ?Sized +{ + type Target = RefCell; + + fn deref(&self) -> &Self::Target { + // Safe, so long as there are no dangling pointers from the GC + unsafe { &*self.as_ptr() } + } +} + +impl Clone for ObjRef + where O: Obj + ?Sized +{ + fn clone(&self) -> Self { + ObjRef { ptr: self.ptr } + } +} + +impl Copy for ObjRef + where O: Obj + ?Sized +{} + +impl Debug for ObjRef + where O: Obj + Debug + ?Sized +{ + fn fmt(&self, fmt: &mut Formatter) -> fmt::Result { + write!(fmt, "<{} object at {:#x}>", any::type_name::(), self.as_ptr() as *const () as usize) + } +} + +impl Debug for ObjRef { + fn fmt(&self, fmt: &mut Formatter) -> fmt::Result { + write!(fmt, "", self.as_ptr() as *const () as usize) + } +} + +// +// Comparison impls +// +impl PartialEq for ObjRef +where + O: Obj + ?Sized + PartialEq, +{ + fn eq(&self, other: &Self) -> bool { + self.borrow().eq(&other.borrow()) + } +} + +impl Eq for ObjRef where O: Obj + ?Sized + Eq {} + +impl PartialOrd for ObjRef +where + O: Obj + ?Sized + PartialOrd, +{ + fn partial_cmp(&self, other: &Self) -> Option { + self.borrow().partial_cmp(&other.borrow()) + } +} + +impl Ord for ObjRef +where + O: Obj + ?Sized + Ord, +{ + fn cmp(&self, other: &Self) -> std::cmp::Ordering { + self.borrow().cmp(&other.borrow()) + } +} + +// +// ObjCell +// +#[derive(Debug, Clone)] +pub struct ObjCell { + cell: RefCell, +} + +impl ObjCell { + pub fn new(obj: O) -> Self { + ObjCell { + cell: RefCell::new(obj), + } + } +} + +impl Deref for ObjCell { + type Target = RefCell; + + fn deref(&self) -> &Self::Target { + &self.cell + } +} diff --git a/src/obj/attrs.rs b/src/obj/attrs.rs new file mode 100644 index 0000000..b132e53 --- /dev/null +++ b/src/obj/attrs.rs @@ -0,0 +1,86 @@ +use crate::{ + mem::ptr::{DynRef, ObjCell}, + obj::prelude::*, +}; +use std::{ + cell::Cell, + mem::MaybeUninit, + ptr::{self, NonNull}, +}; + +#[derive(Clone)] +pub struct Attrs { + attrs: Vec<(Sym, DynRef)>, + marked: Cell, + this: ObjRef, +} + +impl Attrs { + pub fn new(ctx: &mut ObjCtx) -> Self { + let obj: Box> = unsafe { + let mut obj: Box>> = Box::new_uninit(); + // maybe UB? taking away the uninit right before it's initialized may be bad + let this = &*obj as *const _ as *const ObjCell; + + obj.as_mut_ptr().write(ObjCell::new(Attrs { + attrs: Default::default(), + marked: Cell::new(false), + this: ObjRef::new(NonNull::new(this as *mut _).unwrap()), + })); + + obj.assume_init() + }; + + let attrs = { + let obj_ref: &Attrs = &obj.borrow(); + assert!( + ptr::eq(&*obj as *const _, obj_ref.this.as_ptr()), + "Attr 'this' member does not point to itself" + ); + obj_ref.clone() + }; + + // Add the object to the allocator pool + ctx.gc_mut().add_obj(obj); + + attrs + } +} + +impl Obj for Attrs { + fn attrs(&self) -> ObjRef { + self.this + } + + fn is_marked(&self) -> bool { + self.marked.get() + } + + fn mark(&self) { + if self.is_marked() { + return; + } + self.marked.set(true); + self.attrs.iter().for_each(|(_, v)| v.borrow().mark()); + } + + fn unmark(&self) { + if !self.is_marked() { + return; + } + self.marked.set(false); + self.attrs.iter().for_each(|(_, v)| v.borrow().unmark()); + } + + fn as_any(&self) -> &dyn std::any::Any { + self + } +} + +#[test] +fn test_attrs_new() { + /* + use crate::mem::*; + let mut ctx = ObjCtx::new( + */ +} diff --git a/src/obj/ctx.rs b/src/obj/ctx.rs new file mode 100644 index 0000000..2ab87c6 --- /dev/null +++ b/src/obj/ctx.rs @@ -0,0 +1,26 @@ +use crate::mem::{gc::Gc, BasicGc}; + +pub type DefaultGc = BasicGc; + +pub struct ObjCtx +where + G: Gc, +{ + gc: G, +} + +impl ObjCtx +where + G: Gc, +{ + pub fn new(gc: G) -> Self { + ObjCtx { gc } + } + + pub fn gc(&self) -> &G { + &self.gc + } + pub fn gc_mut(&mut self) -> &mut G { + &mut self.gc + } +} diff --git a/src/obj/dict.rs b/src/obj/dict.rs new file mode 100644 index 0000000..30806d4 --- /dev/null +++ b/src/obj/dict.rs @@ -0,0 +1,61 @@ +use crate::obj::prelude::*; +use std::{any::Any, cell::Cell}; + +pub type DictRef = ObjRef; + +pub struct Dict { + dict: Vec<(DynRef, DynRef)>, + attrs: ObjRef, + marked: Cell, +} + +impl Dict { + // TODO : base types need to be interned. This should probably be stored in a root namespace. + // * How to get the root namespace? + // * ObjCtx object that holds allocator, gc, root namespace, etc..? + // * How to create initial types? + pub fn new(ctx: &mut ObjCtx) -> Self { + todo!() + /* + Dict { + dict: Default::default(), + attrs: Attrs::new(ctx), + marked: Cell::new(false), + } + */ + } +} + +impl Obj for Dict { + fn attrs(&self) -> ObjRef { + self.attrs + } + + fn is_marked(&self) -> bool { + self.marked.get() + } + + fn mark(&self) { + if self.is_marked() { + return; + } + self.marked.set(true); + // TODO: dict + self.attrs.borrow().mark(); + todo!() + } + + fn unmark(&self) { + if !self.is_marked() { + return; + } + self.marked.set(false); + // TODO: dict + self.attrs.borrow().unmark(); + todo!() + } + + fn as_any(&self) -> &dyn Any { + self + } +} diff --git a/src/obj/error.rs b/src/obj/error.rs new file mode 100644 index 0000000..f243112 --- /dev/null +++ b/src/obj/error.rs @@ -0,0 +1,13 @@ +use crate::mem::ptr::DynRef; +use snafu::Snafu; + +#[derive(Debug, Snafu)] +pub enum Error { + #[snafu(display("illegal attr key"))] + AttrKey { + key: DynRef + } +} + +pub type Result = std::result::Result; + diff --git a/src/obj/mod.rs b/src/obj/mod.rs new file mode 100644 index 0000000..98b6c81 --- /dev/null +++ b/src/obj/mod.rs @@ -0,0 +1,44 @@ +pub mod attrs; +pub mod ctx; +pub mod dict; +pub mod error; +//pub mod native_fun; +//pub mod num; +pub mod str; +pub mod sym { + pub type Sym = usize; +} +//pub mod ty; + +pub mod prelude { + pub use crate::{ + obj::{ + Attrs, Dict, DictRef, Str, StrRef, Sym, ObjCtx, Obj, + }, + mem::{ + ptr::{ObjRef, DynRef}, + intern::Intern, + gc::Gc, + } + }; +} + +pub use self::{ + attrs::Attrs, + dict::{Dict, DictRef}, + ctx::ObjCtx, + str::{Str, StrRef}, + sym::Sym, +}; +use crate::mem::ptr::ObjRef; +use std::any::Any; + +pub trait Obj { + fn attrs(&self) -> ObjRef; + + fn is_marked(&self) -> bool; + fn mark(&self); + fn unmark(&self); + + fn as_any(&self) -> &dyn Any; +} diff --git a/src/obj/native_fun.rs b/src/obj/native_fun.rs new file mode 100644 index 0000000..413bdab --- /dev/null +++ b/src/obj/native_fun.rs @@ -0,0 +1,27 @@ +use crate::obj::prelude::*; + +pub type NativeFunPtr = *const fn(); + +pub struct NativeFun { + attrs: Attrs, + fn_ptr: NativeFunPtr, +} + +impl NativeFun { + pub fn new(ctx: &mut ObjCtx, name: StrRef, fn_ptr: NativeFunPtr) -> Self { + todo!() + /* + let attrs = Attrs::default(); + NativeFun { + attrs, + fn_ptr, + } + */ + } +} +/* + +impl Obj for NativeFun { + fn get_attr(&self, key: &DynRef) -> Option +} +*/ diff --git a/src/obj/num.rs b/src/obj/num.rs new file mode 100644 index 0000000..e69de29 diff --git a/src/obj/str.rs b/src/obj/str.rs new file mode 100644 index 0000000..bf189c0 --- /dev/null +++ b/src/obj/str.rs @@ -0,0 +1,64 @@ +use crate::obj::prelude::*; +use derivative::Derivative; +use std::{any::Any, cell::Cell}; + +pub type StrRef = ObjRef; + +#[derive(Derivative)] +#[derivative(PartialEq, PartialOrd, Ord, Eq)] +pub struct Str { + #[derivative(PartialEq = "ignore", PartialOrd = "ignore", Ord = "ignore")] + attrs: ObjRef, + + contents: String, + + #[derivative(PartialEq = "ignore", PartialOrd = "ignore", Ord = "ignore")] + marked: Cell, +} + +impl Str { + pub fn new(ctx: &mut ObjCtx, contents: String) -> Self { + todo!() + /* + Str { + attrs: Default::default(), + contents, + marked: Cell::new(false), + } + */ + } + + pub fn contents(&self) -> &String { + &self.contents + } +} + +impl Obj for Str { + fn attrs(&self) -> ObjRef { + self.attrs + } + + fn is_marked(&self) -> bool { + self.marked.get() + } + + fn mark(&self) { + if self.is_marked() { + return; + } + self.marked.set(true); + todo!() + } + + fn unmark(&self) { + if !self.is_marked() { + return; + } + self.marked.set(false); + todo!() + } + + fn as_any(&self) -> &dyn Any { + self + } +} diff --git a/src/obj/ty.rs b/src/obj/ty.rs new file mode 100644 index 0000000..f969771 --- /dev/null +++ b/src/obj/ty.rs @@ -0,0 +1,35 @@ +use crate::obj::prelude::*; +use std::cell::Cell; + +pub struct Ty { + marked: Cell, + this: ObjRef, +} + +impl Ty { + pub fn new(ctx: &mut ObjCtx) -> Self { + todo!() + } +} + +impl Obj for Ty { + fn attrs(&self) -> ObjRef { + todo!() + } + + fn is_marked(&self) -> bool { + self.marked.get() + } + + fn mark(&self) { + self.marked.set(true); + } + + fn unmark(&self) { + self.marked.set(false); + } + + fn as_any(&self) -> &dyn std::any::Any { + self + } +}