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::{ use crate::{
compile::{ctx::Ctx, error::*, ir}, compile::{ctx::Ctx, error::*, ir},
syn::{ast::*, op::BinOp, span::*}, syn::ast::*,
visit::*,
}; };
// basic block // basic block
@@ -9,8 +8,39 @@ pub enum Block {
Body(ir::Body), Body(ir::Body),
Blocks(Vec<Block>), 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 // TranslateAst
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@@ -25,27 +55,40 @@ impl<'c, 't> TranslateAst<'c, 't> {
TranslateAst { ctx, text } TranslateAst { ctx, text }
} }
pub fn translate(&mut self, _ast: &Vec<Stmt>) -> Result<Block> { pub fn translate(&mut self, ast: &Vec<Stmt>) -> Result<ir::Body> {
todo!() let mut body = Vec::new();
} for stmt in ast.iter() {
body.push(stmt.to_ir(self.ctx)?);
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() }),
} }
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<'_, '_> { impl Visit<Stmt> for TranslateAst<'_, '_> {
type Out = Result<ir::Stmt>; type Out = Result<ir::Stmt>;

View File

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

View File

@@ -2,31 +2,20 @@ use crate::{
mem::{gc::Gc, ptr::ObjCell}, mem::{gc::Gc, ptr::ObjCell},
obj::prelude::*, obj::prelude::*,
}; };
use std::ptr::NonNull; use std::pin::Pin;
#[derive(Default)] #[derive(Default)]
pub struct BasicGc { pub struct BasicGc {
objects: Vec<Box<ObjCell<dyn Obj>>>, objects: Vec<Pin<Box<ObjCell<dyn Obj>>>>,
} }
impl Gc for BasicGc { impl Gc for BasicGc {
fn alloc<O: Obj + 'static>(&mut self, obj: O) -> ObjRef<O> { fn add_obj(&mut self, owned: Pin<Box<ObjCell<dyn Obj>>>) {
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>>) {
self.objects.push(owned); self.objects.push(owned);
} }
fn mark(&mut self, _alive: &[DynRef]) {
todo!()
}
fn sweep(&mut self) { 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 { 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); 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 crate::obj::Obj;
use std::{ use std::{
any, any,
cell::RefCell, cell::{Cell, RefCell},
fmt::{self, Debug, Formatter}, fmt::{self, Debug, Formatter},
marker::Unsize, marker::Unsize,
ops::{CoerceUnsized, Deref}, ops::{CoerceUnsized, Deref},
@@ -51,7 +51,7 @@ impl<O> Deref for ObjRef<O>
where where
O: Obj + ?Sized, O: Obj + ?Sized,
{ {
type Target = RefCell<O>; type Target = ObjCell<O>;
fn deref(&self) -> &Self::Target { fn deref(&self) -> &Self::Target {
// Safe, so long as there are no dangling pointers from the GC // Safe, so long as there are no dangling pointers from the GC
@@ -140,22 +140,34 @@ where
{ {
} }
// ////////////////////////////////////////////////////////////////////////////////
// ObjCell // ObjCell
// ////////////////////////////////////////////////////////////////////////////////
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct ObjCell<O: Obj + ?Sized> { pub struct ObjCell<O: Obj + ?Sized> {
marked: Cell<bool>,
cell: RefCell<O>, cell: RefCell<O>,
} }
impl<O: Obj> ObjCell<O> { impl<O: Obj> ObjCell<O> {
pub fn new(obj: O) -> Self { pub fn new(obj: O) -> Self {
ObjCell { ObjCell {
marked: Cell::new(false),
cell: RefCell::new(obj), 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> { impl<O: Obj + ?Sized> Deref for ObjCell<O> {
type Target = RefCell<O>; type Target = RefCell<O>;

View File

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

View File

@@ -1,12 +1,11 @@
use crate::{obj::prelude::*, visit::Visit}; use crate::obj::prelude::*;
use std::{any::Any, cell::Cell}; use std::any::Any;
pub type DictRef = ObjRef<Dict>; pub type DictRef = ObjRef<Dict>;
pub struct Dict { pub struct Dict {
dict: Vec<(DynRef, DynRef)>, dict: Vec<(DynRef, DynRef)>,
attrs: ObjRef<Attrs>, attrs: ObjRef<Attrs>,
marked: Cell<bool>,
} }
impl Dict { impl Dict {
@@ -14,9 +13,16 @@ impl Dict {
Dict { Dict {
dict: Default::default(), dict: Default::default(),
attrs, 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 { impl Obj for Dict {
@@ -27,4 +33,8 @@ impl Obj for Dict {
fn as_any(&self) -> &dyn Any { fn as_any(&self) -> &dyn Any {
self 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 { fn as_any(&self) -> &dyn std::any::Any {
self self
} }
fn accept(&self, _: &mut dyn VisitObj) {
todo!("visit NativeFun");
}
} }
pub struct Fun { pub struct Fun {
@@ -57,4 +61,8 @@ impl Obj for Fun {
fn as_any(&self) -> &dyn Any { fn as_any(&self) -> &dyn Any {
self self
} }
fn accept(&self, _: &mut dyn VisitObj) {
todo!("visit Fun");
}
} }

View File

@@ -20,6 +20,7 @@ pub mod ns {
} }
pub mod str; pub mod str;
pub mod sym; pub mod sym;
pub mod visit;
pub mod prelude { pub mod prelude {
pub use crate::{ pub use crate::{
@@ -30,7 +31,7 @@ pub mod prelude {
}, },
obj::{ obj::{
Attrs, AttrsRef, Dict, DictRef, Fun, NameId, NativeFun, Ns, Obj, ObjCtx, Ss, Str, 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}, ns::{Ns, Ss},
str::{Str, StrRef}, str::{Str, StrRef},
sym::Sym, sym::Sym,
visit::VisitObj,
}; };
use crate::mem::ptr::ObjRef; use crate::mem::ptr::ObjRef;
use crate::visit::*;
use std::any::Any; use std::any::Any;
pub trait Obj { pub trait Obj {
fn attrs(&self) -> ObjRef<Attrs>; fn attrs(&self) -> ObjRef<Attrs>;
fn as_any(&self) -> &dyn Any; 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 derivative::Derivative;
use std::{any::Any, cell::Cell}; use std::any::Any;
pub type StrRef = ObjRef<Str>; pub type StrRef = ObjRef<Str>;
@@ -11,18 +11,11 @@ pub struct Str {
attrs: AttrsRef, attrs: AttrsRef,
contents: String, contents: String,
#[derivative(PartialEq = "ignore", PartialOrd = "ignore", Ord = "ignore")]
marked: Cell<bool>,
} }
impl Str { impl Str {
pub fn new<G: Gc>(attrs: AttrsRef, contents: String) -> Self { pub fn new<G: Gc>(attrs: AttrsRef, contents: String) -> Self {
Str { Str { attrs, contents }
attrs,
contents,
marked: Cell::new(false),
}
} }
pub fn contents(&self) -> &String { pub fn contents(&self) -> &String {
@@ -38,4 +31,8 @@ impl Obj for Str {
fn as_any(&self) -> &dyn Any { fn as_any(&self) -> &dyn Any {
self 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);
}