Add VisitObj and Obj::accept(&self, ..) method

- VisitObj is for visiting object instances and dyn objects (and thus
  dynamically dispatching accept)
- Obj::accept method is used for dispatching to the specific visitor
  method
- GcMark ZST added for visiting/marking living objects

Signed-off-by: Alek Ratzloff <alekratz@gmail.com>
This commit is contained in:
2020-05-22 19:19:12 -04:00
parent 86afce8686
commit c5e1dca7ac
11 changed files with 188 additions and 74 deletions

View File

@@ -1,7 +1,6 @@
use crate::{
compile::{ctx::Ctx, error::*, ir},
syn::{ast::*, op::BinOp, span::*},
visit::*,
syn::ast::*,
};
// basic block
@@ -9,8 +8,39 @@ pub enum Block {
Body(ir::Body),
Blocks(Vec<Block>),
}
/*
* Current problem:
* Visiting a TranslateAst would generally return the IR directly per-function. However, returning
* a different value type per Acceptor would make it impossible to have &dyn Acceptor refs, which
* is needed for visitor-based GC.
*
* Ideas:
* - Remove Visit::Out return value, and instead expect that the acceptor implementation to report
* anything new to its visitor. Visitors/acceptors that require returning an error should use
* TryVisit and TryAccept.
* - Doesn't play nicely with something that might want to return something else.
* - TranslateAst doesn't necessarily need to be a Visitor, except for the context
* - Can we just fake it with TryFrom?
* impl TryFrom<(&'_ mut Ctx, ast::Stmt)> for ir::Stmt { ... }
*
*/
trait ToIr<I> {
fn to_ir(&self, ctx: &mut Ctx) -> Result<I>;
}
trait FromAst<A>: Sized {
fn from_ast(other: &A, ctx: &mut Ctx) -> Result<Self>;
}
impl<I, A> FromAst<A> for I
where A: ToIr<I>
{
fn from_ast(other: &A, ctx: &mut Ctx) -> Result<Self> {
other.to_ir(ctx)
}
}
////////////////////////////////////////////////////////////////////////////////
// TranslateAst
////////////////////////////////////////////////////////////////////////////////
@@ -25,27 +55,40 @@ impl<'c, 't> TranslateAst<'c, 't> {
TranslateAst { ctx, text }
}
pub fn translate(&mut self, _ast: &Vec<Stmt>) -> Result<Block> {
todo!()
}
fn visit_lhs_expr(&mut self, expr: &Expr) -> Result<ir::Lhs> {
match expr {
Expr::Bin(b) if b.op == BinOp::Dot => todo!(),
Expr::Base(BaseExpr {
kind: BaseExprKind::Ident,
..
}) => {
let _name = expr.text_at(self.text);
//let name_id = self.ctx.
todo!()
//Ok(ir::Lhs::Name(
}
_ => Err(Error::InvalidLhs { span: expr.span() }),
pub fn translate(&mut self, ast: &Vec<Stmt>) -> Result<ir::Body> {
let mut body = Vec::new();
for stmt in ast.iter() {
body.push(stmt.to_ir(self.ctx)?);
}
Ok(body)
}
}
impl ToIr<ir::Stmt> for Stmt {
fn to_ir(&self, _ctx: &mut Ctx) -> Result<ir::Stmt> {
todo!()
}
}
impl ToIr<ir::Stmt> for AssignStmt {
fn to_ir(&self, _ctx: &mut Ctx) -> Result<ir::Stmt> {
todo!()
}
}
impl ToIr<ir::Expr> for Expr {
fn to_ir(&self, _ctx: &mut Ctx) -> Result<ir::Expr> {
todo!()
}
}
impl ToIr<ir::Lhs> for Expr {
fn to_ir(&self, _ctx: &mut Ctx) -> Result<ir::Lhs> {
todo!()
}
}
/*
impl Visit<Stmt> for TranslateAst<'_, '_> {
type Out = Result<ir::Stmt>;

View File

@@ -1,5 +1,5 @@
#![allow(dead_code)]
#![feature(unsize, coerce_unsized, new_uninit)]
#![feature(unsize, coerce_unsized, new_uninit, box_into_pin)]
#[macro_use] mod visit;
mod compile;

View File

@@ -2,31 +2,20 @@ use crate::{
mem::{gc::Gc, ptr::ObjCell},
obj::prelude::*,
};
use std::ptr::NonNull;
use std::pin::Pin;
#[derive(Default)]
pub struct BasicGc {
objects: Vec<Box<ObjCell<dyn Obj>>>,
objects: Vec<Pin<Box<ObjCell<dyn Obj>>>>,
}
impl Gc for BasicGc {
fn alloc<O: Obj + 'static>(&mut self, obj: O) -> ObjRef<O> {
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<ObjCell<dyn Obj>>) {
fn add_obj(&mut self, owned: Pin<Box<ObjCell<dyn Obj>>>) {
self.objects.push(owned);
}
fn mark(&mut self, _alive: &[DynRef]) {
todo!()
}
fn sweep(&mut self) {
todo!()
self.objects.retain(|cell| cell.is_marked())
}
}

View File

@@ -1,11 +1,56 @@
use crate::{mem::ptr::ObjCell, obj::prelude::*, visit::{Accept, Visit},};
use crate::{mem::ptr::ObjCell, obj::prelude::*};
use std::pin::Pin;
pub trait Gc {
fn alloc<O: Obj + 'static>(&mut self, obj: O) -> ObjRef<O>;
fn alloc<O: Obj + 'static>(&mut self, obj: O) -> ObjRef<O> {
let obj_cell = Box::pin(ObjCell::new(obj));
let obj_ptr = &*obj_cell as *const _ as *mut _;
self.add_obj(obj_cell);
ObjRef::new(std::ptr::NonNull::new(obj_ptr).unwrap())
}
fn add_obj(&mut self, owned: Box<ObjCell<dyn Obj>>);
fn add_obj(&mut self, owned: Pin<Box<ObjCell<dyn Obj>>>);
fn mark(&mut self, alive: &[DynRef]);
fn mark(&mut self, alive: &[DynRef]) {
alive.iter()
.copied()
.for_each(|obj| GcMark.visit(obj));
}
fn sweep(&mut self);
}
pub struct GcMark;
impl VisitObj for GcMark {
fn visit(&mut self, obj: DynRef) {
if obj.is_marked() {
return;
}
obj.set_marked(true);
obj.borrow().accept(self)
}
fn visit_attrs(&mut self, attrs: &Attrs) {
attrs.inner()
.values()
.copied()
.for_each(|obj| {
self.visit(obj);
});
}
fn visit_dict(&mut self, d: &Dict) {
d.dict()
.iter()
.for_each(|(k, v)| {
self.visit(*k);
self.visit(*v);
});
self.visit(d.attrs());
}
fn visit_str(&mut self, s: &Str) {
self.visit(s.attrs())
}
}

View File

@@ -1,7 +1,7 @@
use crate::obj::Obj;
use std::{
any,
cell::RefCell,
cell::{Cell, RefCell},
fmt::{self, Debug, Formatter},
marker::Unsize,
ops::{CoerceUnsized, Deref},
@@ -51,7 +51,7 @@ impl<O> Deref for ObjRef<O>
where
O: Obj + ?Sized,
{
type Target = RefCell<O>;
type Target = ObjCell<O>;
fn deref(&self) -> &Self::Target {
// Safe, so long as there are no dangling pointers from the GC
@@ -140,22 +140,34 @@ where
{
}
//
////////////////////////////////////////////////////////////////////////////////
// ObjCell
//
////////////////////////////////////////////////////////////////////////////////
#[derive(Debug, Clone)]
pub struct ObjCell<O: Obj + ?Sized> {
marked: Cell<bool>,
cell: RefCell<O>,
}
impl<O: Obj> ObjCell<O> {
pub fn new(obj: O) -> Self {
ObjCell {
marked: Cell::new(false),
cell: RefCell::new(obj),
}
}
}
impl<O: Obj + ?Sized> ObjCell<O> {
pub fn is_marked(&self) -> bool {
self.marked.get()
}
pub fn set_marked(&self, marked: bool) {
self.marked.set(marked);
}
}
impl<O: Obj + ?Sized> Deref for ObjCell<O> {
type Target = RefCell<O>;

View File

@@ -1,7 +1,6 @@
use crate::{
mem::ptr::{DynRef, ObjCell},
obj::prelude::*,
visit::Visit,
};
use std::{
cell::Cell,
@@ -42,10 +41,14 @@ impl Attrs {
};
// Add the object to the allocator pool
gc.add_obj(obj);
gc.add_obj(Box::into_pin(obj));
obj_ref
}
pub fn inner(&self) -> &Ss {
&self.attrs
}
pub fn insert(&mut self, sym: Sym, value: DynRef) -> Option<DynRef> {
self.attrs.insert(sym, value)
}
@@ -64,17 +67,8 @@ impl Obj for Attrs {
fn as_any(&self) -> &dyn std::any::Any {
self
}
}
/*
impl_accept!(Attrs);
impl<G: Gc> Visit<Attrs> for G {
type Out = ();
fn visit(&mut self, attrs: &Attrs) -> Self::Out {
attrs.attrs.values()
.for_each(|obj| obj.accept(self));
fn accept(&self, visitor: &mut dyn VisitObj) {
visitor.visit_attrs(self);
}
}
*/

View File

@@ -1,12 +1,11 @@
use crate::{obj::prelude::*, visit::Visit};
use std::{any::Any, cell::Cell};
use crate::obj::prelude::*;
use std::any::Any;
pub type DictRef = ObjRef<Dict>;
pub struct Dict {
dict: Vec<(DynRef, DynRef)>,
attrs: ObjRef<Attrs>,
marked: Cell<bool>,
}
impl Dict {
@@ -14,9 +13,16 @@ impl Dict {
Dict {
dict: Default::default(),
attrs,
marked: Cell::new(false),
}
}
pub fn dict(&self) -> &Vec<(DynRef, DynRef)> {
&self.dict
}
pub fn dict_mut(&mut self) -> &mut Vec<(DynRef, DynRef)> {
&mut self.dict
}
}
impl Obj for Dict {
@@ -27,4 +33,8 @@ impl Obj for Dict {
fn as_any(&self) -> &dyn Any {
self
}
fn accept(&self, visitor: &mut dyn VisitObj) {
visitor.visit_dict(self);
}
}

View File

@@ -27,6 +27,10 @@ impl Obj for NativeFun {
fn as_any(&self) -> &dyn std::any::Any {
self
}
fn accept(&self, _: &mut dyn VisitObj) {
todo!("visit NativeFun");
}
}
pub struct Fun {
@@ -57,4 +61,8 @@ impl Obj for Fun {
fn as_any(&self) -> &dyn Any {
self
}
fn accept(&self, _: &mut dyn VisitObj) {
todo!("visit Fun");
}
}

View File

@@ -20,6 +20,7 @@ pub mod ns {
}
pub mod str;
pub mod sym;
pub mod visit;
pub mod prelude {
pub use crate::{
@@ -30,7 +31,7 @@ pub mod prelude {
},
obj::{
Attrs, AttrsRef, Dict, DictRef, Fun, NameId, NativeFun, Ns, Obj, ObjCtx, Ss, Str,
StrRef, Sym,
StrRef, Sym, VisitObj,
},
};
}
@@ -44,13 +45,14 @@ pub use self::{
ns::{Ns, Ss},
str::{Str, StrRef},
sym::Sym,
visit::VisitObj,
};
use crate::mem::ptr::ObjRef;
use crate::visit::*;
use std::any::Any;
pub trait Obj {
fn attrs(&self) -> ObjRef<Attrs>;
fn as_any(&self) -> &dyn Any;
}
fn accept(&self, visitor: &mut dyn VisitObj);
}

View File

@@ -1,6 +1,6 @@
use crate::{obj::prelude::*, visit::Visit};
use crate::obj::prelude::*;
use derivative::Derivative;
use std::{any::Any, cell::Cell};
use std::any::Any;
pub type StrRef = ObjRef<Str>;
@@ -11,18 +11,11 @@ pub struct Str {
attrs: AttrsRef,
contents: String,
#[derivative(PartialEq = "ignore", PartialOrd = "ignore", Ord = "ignore")]
marked: Cell<bool>,
}
impl Str {
pub fn new<G: Gc>(attrs: AttrsRef, contents: String) -> Self {
Str {
attrs,
contents,
marked: Cell::new(false),
}
Str { attrs, contents }
}
pub fn contents(&self) -> &String {
@@ -38,4 +31,8 @@ impl Obj for Str {
fn as_any(&self) -> &dyn Any {
self
}
fn accept(&self, visitor: &mut dyn VisitObj) {
visitor.visit_str(self);
}
}

14
src/obj/visit.rs Normal file
View File

@@ -0,0 +1,14 @@
use crate::obj::prelude::*;
pub trait VisitObj {
fn visit(&mut self, obj: DynRef) where Self: Sized {
obj.borrow().accept(self)
}
fn visit_attrs(&mut self, attrs: &Attrs);
fn visit_str(&mut self, s: &Str);
fn visit_dict(&mut self, d: &Dict);
}