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 <alekratz@gmail.com>
This commit is contained in:
@@ -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!()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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<O: Obj + 'static>(&mut self, obj: O) -> ObjRef<O>;
|
||||
@@ -9,3 +9,12 @@ pub trait Gc {
|
||||
|
||||
fn sweep(&mut self);
|
||||
}
|
||||
|
||||
impl<O> Visit<O> for O
|
||||
where O: Obj + Accept
|
||||
{
|
||||
type Out = ();
|
||||
fn visit(&mut self, obj: &O) -> Self::Out {
|
||||
obj.accept(self)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<O: Obj + ?Sized> AsRef<ObjCell<O>> for ObjRef<O> {
|
||||
fn as_ref(&self) -> &ObjCell<O> {
|
||||
// safe because pointer should point at live data assuming GC is working appropriately
|
||||
unsafe { &*self.as_ptr() }
|
||||
}
|
||||
}
|
||||
|
||||
impl<O> ObjRef<O>
|
||||
where
|
||||
O: Obj,
|
||||
@@ -47,6 +40,13 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<O: Obj + ?Sized> AsRef<ObjCell<O>> for ObjRef<O> {
|
||||
fn as_ref(&self) -> &ObjCell<O> {
|
||||
// safe because pointer should point at live data assuming GC is working appropriately
|
||||
unsafe { &*self.as_ptr() }
|
||||
}
|
||||
}
|
||||
|
||||
impl<O> Deref for ObjRef<O>
|
||||
where
|
||||
O: Obj + ?Sized,
|
||||
@@ -94,6 +94,14 @@ impl Debug for ObjRef<dyn Obj> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<O> DynAccept for ObjRef<O>
|
||||
where O: Obj + ?Sized + DynAccept
|
||||
{
|
||||
fn accept(&self, visitor: &mut impl Visit<Self, Out=()>) {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Comparison impls
|
||||
//
|
||||
|
||||
@@ -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<G: Gc> Visit<Attrs> 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!()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use crate::obj::prelude::*;
|
||||
use crate::{obj::prelude::*, visit::Visit};
|
||||
use std::{any::Any, cell::Cell};
|
||||
|
||||
pub type DictRef = ObjRef<Dict>;
|
||||
@@ -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<G> Visit<Dict> for G
|
||||
where G: Gc + Visit<Attrs>,
|
||||
{
|
||||
type Out = ();
|
||||
|
||||
fn visit(&mut self, dict: &Dict) -> Self::Out {
|
||||
let attrs_ref: &Attrs = &dict.attrs.borrow();
|
||||
self.visit(attrs_ref);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -50,10 +50,5 @@ use std::any::Any;
|
||||
|
||||
pub trait Obj {
|
||||
fn attrs(&self) -> ObjRef<Attrs>;
|
||||
|
||||
fn is_marked(&self) -> bool;
|
||||
fn mark(&self);
|
||||
fn unmark(&self);
|
||||
|
||||
fn as_any(&self) -> &dyn Any;
|
||||
}
|
||||
|
||||
@@ -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<O> DynAccept for O
|
||||
where O: Obj + ?Sized
|
||||
{
|
||||
fn accept(&self, visitor: &mut impl Visit<Self, Out=()>) {
|
||||
visitor.visit(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<G: Gc> Visit<Str> for G {
|
||||
type Out = ();
|
||||
|
||||
fn visit(&mut self, _s: &Str) -> Self::Out {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
60
src/visit.rs
60
src/visit.rs
@@ -1,14 +1,14 @@
|
||||
use crate::syn::ast::prelude::*;
|
||||
|
||||
pub trait Visit<A: Accept> {
|
||||
pub trait Visit<A: ?Sized> {
|
||||
type Out;
|
||||
fn visit(&mut self, acceptor: &A) -> Self::Out;
|
||||
}
|
||||
|
||||
pub trait Accept {
|
||||
fn accept<V: Visit<Self>>(&self, visitor: &mut V) -> V::Out
|
||||
where
|
||||
Self: Sized;
|
||||
fn accept<V: Visit<Self>>(&self, visitor: &mut V) -> V::Out;
|
||||
}
|
||||
|
||||
pub trait DynAccept<Out=()> {
|
||||
fn accept(&self, visitor: &mut impl Visit<Self, Out=Out>);
|
||||
}
|
||||
|
||||
pub trait DefaultAccept<V: Visit<Self>>: Accept + Sized {
|
||||
@@ -18,7 +18,7 @@ pub trait DefaultAccept<V: Visit<Self>>: 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<V: Visit<Self>>(&self, visitor: &mut V) -> V::Out {
|
||||
($what:ty) => {
|
||||
impl $crate::visit::Accept for $what {
|
||||
fn accept<V: $crate::visit::Visit<Self>>(&self, visitor: &mut V) -> V::Out {
|
||||
visitor.visit(self)
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! impl_default_accept {
|
||||
($what:ident : $($requires:ident),+ => $($tail:tt)+) => {
|
||||
impl<V, Out> DefaultAccept<V> for $what
|
||||
where V: Visit<Self, Out=Out> $(+ Visit<$requires, Out=Out>)+
|
||||
impl<V, Out> $crate::visit::DefaultAccept<V> for $what
|
||||
where V: $crate::visit::Visit<Self, Out=Out> $(+ $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);
|
||||
|
||||
Reference in New Issue
Block a user