From 7de005b160dd046555fc8a56c344edc8b9aa566c Mon Sep 17 00:00:00 2001 From: Alek Ratzloff Date: Fri, 22 May 2020 12:04:27 -0400 Subject: [PATCH] WIP: DynAccept trait, Visitor-based GC DynAccept trait is necessary because we need some kind of Accept trait that doesn't have generic methods - this is so we can dynamically dispatch the .accept() method from a &dyn Obj type. I plan to work this into the regular Accept trait and do away with the DynAccept distinction entirely. I'm also experimenting with using visitors to do GC, so that all references are wrapped in a future GcRef, so they don't have to implement that as part of their object. The GC will be able to visit any Obj + ?Sized type, and can have a specific implementation if required. Signed-off-by: Alek Ratzloff --- src/mem/basic.rs | 17 +++----------- src/mem/gc.rs | 11 ++++++++- src/mem/ptr.rs | 24 ++++++++++++------- src/obj/attrs.rs | 42 +++++---------------------------- src/obj/dict.rs | 39 +++++++++++-------------------- src/obj/fun.rs | 29 ----------------------- src/obj/mod.rs | 5 ---- src/obj/str.rs | 40 +++++++++++++++----------------- src/syn/ast.rs | 36 +++++++++++++++++++++++++++++ src/visit.rs | 60 ++++++++++++------------------------------------ 10 files changed, 119 insertions(+), 184 deletions(-) diff --git a/src/mem/basic.rs b/src/mem/basic.rs index 1a616de..1db4857 100644 --- a/src/mem/basic.rs +++ b/src/mem/basic.rs @@ -21,23 +21,12 @@ impl Gc for BasicGc { 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 mark(&mut self, _alive: &[DynRef]) { + todo!() } 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()); + todo!() } } diff --git a/src/mem/gc.rs b/src/mem/gc.rs index 866e09e..4ba5e59 100644 --- a/src/mem/gc.rs +++ b/src/mem/gc.rs @@ -1,4 +1,4 @@ -use crate::{mem::ptr::ObjCell, obj::prelude::*}; +use crate::{mem::ptr::ObjCell, obj::prelude::*, visit::{Accept, Visit},}; pub trait Gc { fn alloc(&mut self, obj: O) -> ObjRef; @@ -9,3 +9,12 @@ pub trait Gc { fn sweep(&mut self); } + +impl Visit for O + where O: Obj + Accept +{ + type Out = (); + fn visit(&mut self, obj: &O) -> Self::Out { + obj.accept(self) + } +} diff --git a/src/mem/ptr.rs b/src/mem/ptr.rs index aa25436..2441c2c 100644 --- a/src/mem/ptr.rs +++ b/src/mem/ptr.rs @@ -1,4 +1,4 @@ -use crate::obj::Obj; +use crate::{obj::Obj, visit::{DynAccept, Accept, Visit}}; use std::{ any, cell::RefCell, @@ -30,13 +30,6 @@ where } } -impl AsRef> for ObjRef { - fn as_ref(&self) -> &ObjCell { - // safe because pointer should point at live data assuming GC is working appropriately - unsafe { &*self.as_ptr() } - } -} - impl ObjRef where O: Obj, @@ -47,6 +40,13 @@ where } } +impl AsRef> for ObjRef { + fn as_ref(&self) -> &ObjCell { + // safe because pointer should point at live data assuming GC is working appropriately + unsafe { &*self.as_ptr() } + } +} + impl Deref for ObjRef where O: Obj + ?Sized, @@ -94,6 +94,14 @@ impl Debug for ObjRef { } } +impl DynAccept for ObjRef + where O: Obj + ?Sized + DynAccept +{ + fn accept(&self, visitor: &mut impl Visit) { + todo!() + } +} + // // Comparison impls // diff --git a/src/obj/attrs.rs b/src/obj/attrs.rs index 68950b9..8825910 100644 --- a/src/obj/attrs.rs +++ b/src/obj/attrs.rs @@ -1,6 +1,7 @@ use crate::{ mem::ptr::{DynRef, ObjCell}, obj::prelude::*, + visit::Visit, }; use std::{ cell::Cell, @@ -60,48 +61,17 @@ impl Obj for Attrs { 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::BasicGc; +//impl_accept!(Attrs); - let mut gc = BasicGc::default(); +impl Visit for G { + type Out = (); - let attrs_ref = Attrs::new(&mut gc, Default::default()); - - { - let mut attrs = attrs_ref.borrow_mut(); - let sym = Sym::new(0); - attrs.insert(sym, attrs_ref.as_dyn()); - - assert!(ptr::eq( - dbg!(attrs.get(sym).unwrap().as_ptr()), - dbg!(attrs_ref.as_dyn().as_ptr()) - // as_dyn() is important here - this will cause the test to fail otherwise - ),); + fn visit(&mut self, _attrs: &Attrs) -> Self::Out { + todo!() } } diff --git a/src/obj/dict.rs b/src/obj/dict.rs index 74e8178..ecb6052 100644 --- a/src/obj/dict.rs +++ b/src/obj/dict.rs @@ -1,4 +1,4 @@ -use crate::obj::prelude::*; +use crate::{obj::prelude::*, visit::Visit}; use std::{any::Any, cell::Cell}; pub type DictRef = ObjRef; @@ -24,31 +24,20 @@ impl Obj for Dict { 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 } } + +//impl_accept!(Dict); + +impl Visit for G + where G: Gc + Visit, +{ + type Out = (); + + fn visit(&mut self, dict: &Dict) -> Self::Out { + let attrs_ref: &Attrs = &dict.attrs.borrow(); + self.visit(attrs_ref); + } +} diff --git a/src/obj/fun.rs b/src/obj/fun.rs index 274b667..3ebd120 100644 --- a/src/obj/fun.rs +++ b/src/obj/fun.rs @@ -24,15 +24,6 @@ impl Obj for NativeFun { self.attrs } - fn is_marked(&self) -> bool { - // native functions are always available - true - } - - fn mark(&self) {} - - fn unmark(&self) {} - fn as_any(&self) -> &dyn std::any::Any { self } @@ -63,26 +54,6 @@ impl Obj for Fun { self.attrs } - fn is_marked(&self) -> bool { - self.marked.get() - } - - fn mark(&self) { - if self.is_marked() { - return; - } - self.marked.set(true); - self.attrs.borrow().mark(); - } - - fn unmark(&self) { - if !self.is_marked() { - return; - } - self.marked.set(false); - self.attrs.borrow().unmark(); - } - fn as_any(&self) -> &dyn Any { self } diff --git a/src/obj/mod.rs b/src/obj/mod.rs index 65b5ca0..1b018a4 100644 --- a/src/obj/mod.rs +++ b/src/obj/mod.rs @@ -50,10 +50,5 @@ 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/str.rs b/src/obj/str.rs index 9b0979d..c4b2ff5 100644 --- a/src/obj/str.rs +++ b/src/obj/str.rs @@ -1,4 +1,4 @@ -use crate::obj::prelude::*; +use crate::{obj::prelude::*, visit::{DynAccept, Visit}}; use derivative::Derivative; use std::{any::Any, cell::Cell}; @@ -35,27 +35,25 @@ impl Obj for Str { self.attrs } - fn is_marked(&self) -> bool { - self.marked.get() - } - - fn mark(&self) { - if self.is_marked() { - return; - } - self.marked.set(true); - self.attrs.borrow().mark(); - } - - fn unmark(&self) { - if !self.is_marked() { - return; - } - self.marked.set(false); - todo!() - } - fn as_any(&self) -> &dyn Any { self } } + +//impl_accept!(Str); + +impl DynAccept for O + where O: Obj + ?Sized +{ + fn accept(&self, visitor: &mut impl Visit) { + visitor.visit(self) + } +} + +impl Visit for G { + type Out = (); + + fn visit(&mut self, _s: &Str) -> Self::Out { + todo!() + } +} diff --git a/src/syn/ast.rs b/src/syn/ast.rs index 5468f14..8c55d18 100644 --- a/src/syn/ast.rs +++ b/src/syn/ast.rs @@ -169,3 +169,39 @@ impl Spanned for BaseExpr { self.span } } + +//////////////////////////////////////////////////////////////////////////////// +// Acceptor (visitor) impls +//////////////////////////////////////////////////////////////////////////////// + +impl_accept!(Stmt); +impl_default_accept!(Stmt : AssignStmt, Expr => + fn default_accept(&self, visitor: &mut V) -> Out { + match self { + Stmt::Assign(a) => visitor.visit(a), + Stmt::Expr(e) => visitor.visit(e), + } + } +); +impl_accept!(AssignStmt); +impl_accept!(Expr); + +impl_default_accept!(Expr: BinExpr, UnExpr, FunCallExpr, IndexExpr, FunExpr, BaseExpr => + fn default_accept(&self, visitor: &mut V) -> Out { + match self { + Expr::Bin(b) => visitor.visit(b.as_ref()), + Expr::Un(u) => visitor.visit(u.as_ref()), + Expr::FunCall(f) => visitor.visit(f.as_ref()), + Expr::Index(i) => visitor.visit(i.as_ref()), + Expr::Fun(f) => visitor.visit(f.as_ref()), + Expr::Base(b) => visitor.visit(b), + } + } +); + +impl_accept!(BinExpr); +impl_accept!(UnExpr); +impl_accept!(FunCallExpr); +impl_accept!(IndexExpr); +impl_accept!(FunExpr); +impl_accept!(BaseExpr); diff --git a/src/visit.rs b/src/visit.rs index a25fe51..68cdd90 100644 --- a/src/visit.rs +++ b/src/visit.rs @@ -1,14 +1,14 @@ -use crate::syn::ast::prelude::*; - -pub trait Visit { +pub trait Visit { type Out; fn visit(&mut self, acceptor: &A) -> Self::Out; } pub trait Accept { - fn accept>(&self, visitor: &mut V) -> V::Out - where - Self: Sized; + fn accept>(&self, visitor: &mut V) -> V::Out; +} + +pub trait DynAccept { + fn accept(&self, visitor: &mut impl Visit); } pub trait DefaultAccept>: Accept + Sized { @@ -18,7 +18,7 @@ pub trait DefaultAccept>: Accept + Sized { #[macro_export] macro_rules! default_visitor { ($default:ident for $visitor:ty where Out = $out:ty) => { - impl crate::visit::Visit<$default> for $visitor { + impl $crate::visit::Visit<$default> for $visitor { type Out = $out; fn visit(&mut self, acceptor: &$default) -> Self::Out { acceptor.default_accept(self) @@ -30,61 +30,31 @@ macro_rules! default_visitor { #[macro_export] macro_rules! empty_visitor { ($default:ident for $visitor:ty) => { - impl crate::visit::Visit<$default> for $visitor { + impl $crate::visit::Visit<$default> for $visitor { type Out = (); fn visit(&mut self, _: &$default) -> Self::Out {} } }; } +#[macro_export] macro_rules! impl_accept { - ($what:ident) => { - impl crate::visit::Accept for $what { - fn accept>(&self, visitor: &mut V) -> V::Out { + ($what:ty) => { + impl $crate::visit::Accept for $what { + fn accept>(&self, visitor: &mut V) -> V::Out { visitor.visit(self) } } }; } +#[macro_export] macro_rules! impl_default_accept { ($what:ident : $($requires:ident),+ => $($tail:tt)+) => { - impl DefaultAccept for $what - where V: Visit $(+ Visit<$requires, Out=Out>)+ + impl $crate::visit::DefaultAccept for $what + where V: $crate::visit::Visit $(+ $crate::visit::Visit<$requires, Out=Out>)+ { $($tail)+ } }; } - -impl_accept!(Stmt); -impl_default_accept!(Stmt : AssignStmt, Expr => - fn default_accept(&self, visitor: &mut V) -> Out { - match self { - Stmt::Assign(a) => visitor.visit(a), - Stmt::Expr(e) => visitor.visit(e), - } - } -); -impl_accept!(AssignStmt); -impl_accept!(Expr); - -impl_default_accept!(Expr: BinExpr, UnExpr, FunCallExpr, IndexExpr, FunExpr, BaseExpr => - fn default_accept(&self, visitor: &mut V) -> Out { - match self { - Expr::Bin(b) => visitor.visit(b.as_ref()), - Expr::Un(u) => visitor.visit(u.as_ref()), - Expr::FunCall(f) => visitor.visit(f.as_ref()), - Expr::Index(i) => visitor.visit(i.as_ref()), - Expr::Fun(f) => visitor.visit(f.as_ref()), - Expr::Base(b) => visitor.visit(b), - } - } -); - -impl_accept!(BinExpr); -impl_accept!(UnExpr); -impl_accept!(FunCallExpr); -impl_accept!(IndexExpr); -impl_accept!(FunExpr); -impl_accept!(BaseExpr);