Changes all around - objects and GC
Signed-off-by: Alek Ratzloff <alekratz@gmail.com>
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
#![allow(dead_code)]
|
||||
#![feature(new_uninit)]
|
||||
#![feature(unsize, coerce_unsized, new_uninit)]
|
||||
|
||||
mod compile;
|
||||
mod syn;
|
||||
|
||||
@@ -2,17 +2,15 @@ use crate::{
|
||||
mem::{
|
||||
gc::Gc,
|
||||
intern::Intern,
|
||||
ptr::{DynRef, ObjCell, ObjRef},
|
||||
ptr::ObjCell,
|
||||
},
|
||||
obj::{ctx::ObjCtx, Obj, Str, Sym},
|
||||
obj::prelude::*,
|
||||
};
|
||||
use std::{collections::HashMap, ptr::NonNull};
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct BasicGc {
|
||||
objects: Vec<Box<ObjCell<dyn Obj>>>,
|
||||
strs: HashMap<String, ObjRef<Str>>,
|
||||
syms: HashMap<String, Sym>,
|
||||
}
|
||||
|
||||
impl Gc for BasicGc {
|
||||
@@ -23,7 +21,7 @@ impl Gc for BasicGc {
|
||||
ObjRef::new(NonNull::new(obj_ptr).unwrap())
|
||||
}
|
||||
|
||||
fn add_obj<O: Obj + 'static>(&mut self, owned: Box<ObjCell<O>>) {
|
||||
fn add_obj(&mut self, owned: Box<ObjCell<dyn Obj>>) {
|
||||
self.objects.push(owned);
|
||||
}
|
||||
|
||||
@@ -47,24 +45,23 @@ impl Gc for BasicGc {
|
||||
}
|
||||
}
|
||||
|
||||
impl Intern for BasicGc {
|
||||
fn get_str(&self, s: &str) -> Option<ObjRef<Str>> {
|
||||
self.strs.get(s).copied()
|
||||
pub struct BasicIntern {
|
||||
strs: HashMap<String, ObjRef<Str>>,
|
||||
syms: HashMap<String, Sym>,
|
||||
}
|
||||
|
||||
impl Intern for BasicIntern {
|
||||
fn intern_str<G: Gc>(&mut self, gc: &mut G, s: &str) -> StrRef {
|
||||
if let Some(obj_ref) = self.strs.get(s) {
|
||||
*obj_ref
|
||||
} else {
|
||||
todo!("TODO(obj) intern strings - need attrs somehow")
|
||||
//let s = Str::new(&mut ctx, s.to_string());
|
||||
//ctx.gc_mut().alloc(s)
|
||||
}
|
||||
}
|
||||
|
||||
fn add_str(&mut self, ctx: &mut ObjCtx, s: &str) -> ObjRef<Str> {
|
||||
*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<Sym> {
|
||||
self.syms.get(s).copied()
|
||||
}
|
||||
|
||||
fn add_sym(&mut self, s: &str) -> Sym {
|
||||
fn intern_sym(&mut self, s: &str) -> Sym {
|
||||
let len = self.syms.len();
|
||||
*self.syms.entry(s.to_string())
|
||||
.or_insert_with(|| len)
|
||||
|
||||
@@ -2,14 +2,13 @@ use crate::{
|
||||
obj::prelude::*,
|
||||
mem::{
|
||||
ptr::ObjCell,
|
||||
intern::Intern,
|
||||
}
|
||||
};
|
||||
|
||||
pub trait Gc: Intern {
|
||||
pub trait Gc {
|
||||
fn alloc<O: Obj + 'static>(&mut self, obj: O) -> ObjRef<O>;
|
||||
|
||||
fn add_obj<O: Obj + 'static>(&mut self, owned: Box<ObjCell<O>>);
|
||||
fn add_obj(&mut self, owned: Box<ObjCell<dyn Obj>>);
|
||||
|
||||
fn mark(&mut self, alive: &[DynRef]);
|
||||
|
||||
|
||||
@@ -1,15 +1,7 @@
|
||||
use crate::{
|
||||
mem::ptr::ObjRef,
|
||||
obj::{
|
||||
ctx::ObjCtx,
|
||||
Str, Sym,
|
||||
},
|
||||
};
|
||||
use crate::obj::prelude::*;
|
||||
|
||||
pub trait Intern {
|
||||
fn get_str(&self, s: &str) -> Option<ObjRef<Str>>;
|
||||
fn add_str(&mut self, ctx: &mut ObjCtx, s: &str) -> ObjRef<Str>;
|
||||
fn intern_str<G: Gc>(&mut self, gc: &mut G, s: &str) -> StrRef;
|
||||
|
||||
fn get_sym(&self, s: &str) -> Option<Sym>;
|
||||
fn add_sym(&mut self, s: &str) -> Sym;
|
||||
fn intern_sym(&mut self, s: &str) -> Sym;
|
||||
}
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
mod basic;
|
||||
pub mod intern;
|
||||
pub mod basic;
|
||||
pub mod gc;
|
||||
pub mod intern;
|
||||
pub mod ptr;
|
||||
|
||||
pub use self::basic::BasicGc;
|
||||
pub use basic::BasicGc;
|
||||
|
||||
/*
|
||||
pub mod prelude {
|
||||
pub use crate::mem::{
|
||||
alloc::Alloc,
|
||||
BasicGc,
|
||||
gc::Gc,
|
||||
ptr::*
|
||||
}
|
||||
intern::Intern,
|
||||
ptr::{DynRef, ObjRef},
|
||||
};
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
use crate::obj::Obj;
|
||||
use std::{
|
||||
any::{self, Any},
|
||||
any,
|
||||
cell::RefCell,
|
||||
fmt::{self, Debug, Formatter},
|
||||
ops::Deref,
|
||||
marker::Unsize,
|
||||
ops::{CoerceUnsized, Deref},
|
||||
ptr::NonNull,
|
||||
};
|
||||
|
||||
@@ -124,6 +125,16 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, U> CoerceUnsized<ObjRef<U>> for ObjRef<T>
|
||||
where T: Obj + Unsize<U> + ?Sized,
|
||||
U: Obj + ?Sized
|
||||
{}
|
||||
|
||||
impl<T, U> CoerceUnsized<ObjCell<U>> for ObjCell<T>
|
||||
where T: CoerceUnsized<U> + Obj,
|
||||
U: Obj
|
||||
{}
|
||||
|
||||
//
|
||||
// ObjCell
|
||||
//
|
||||
|
||||
@@ -4,28 +4,27 @@ use crate::{
|
||||
};
|
||||
use std::{
|
||||
cell::Cell,
|
||||
collections::BTreeMap,
|
||||
mem::MaybeUninit,
|
||||
ptr::{self, NonNull},
|
||||
};
|
||||
|
||||
pub type AttrsMap = BTreeMap<Sym, DynRef>;
|
||||
pub type AttrsRef = ObjRef<Attrs>;
|
||||
|
||||
pub struct Attrs {
|
||||
attrs: AttrsMap,
|
||||
attrs: Ns,
|
||||
marked: Cell<bool>,
|
||||
this: ObjRef<Attrs>,
|
||||
}
|
||||
|
||||
impl Attrs {
|
||||
pub fn new(ctx: &mut ObjCtx, attrs: BTreeMap<Sym, DynRef>) -> ObjRef<Self> {
|
||||
pub fn new<G: Gc>(gc: &mut G, attrs: Ns) -> ObjRef<Self> {
|
||||
let obj: Box<ObjCell<Attrs>> = unsafe {
|
||||
let mut obj: Box<MaybeUninit<ObjCell<Attrs>>> = 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<Attrs>;
|
||||
|
||||
obj.as_mut_ptr().write(ObjCell::new(Attrs {
|
||||
attrs: Default::default(),
|
||||
attrs,
|
||||
marked: Cell::new(false),
|
||||
this: ObjRef::new(NonNull::new(this as *mut _).unwrap()),
|
||||
}));
|
||||
@@ -43,7 +42,7 @@ impl Attrs {
|
||||
};
|
||||
|
||||
// Add the object to the allocator pool
|
||||
ctx.gc_mut().add_obj(obj);
|
||||
gc.add_obj(obj);
|
||||
obj_ref
|
||||
}
|
||||
|
||||
@@ -87,25 +86,25 @@ impl Obj for Attrs {
|
||||
}
|
||||
}
|
||||
|
||||
pub struct AttrsBuilder<'ctx> {
|
||||
ctx: &'ctx mut ObjCtx,
|
||||
attrs: AttrsMap,
|
||||
pub struct AttrsBuilder<'i, I: Intern> {
|
||||
intern: &'i mut I,
|
||||
attrs: Ns,
|
||||
}
|
||||
|
||||
impl<'ctx> AttrsBuilder<'ctx> {
|
||||
pub fn new(ctx: &'ctx mut ObjCtx) -> Self {
|
||||
Self::with_base(ctx, Default::default())
|
||||
impl<'i, I: Intern> AttrsBuilder<'i, I> {
|
||||
pub fn new(intern: &'i mut I) -> Self {
|
||||
Self::with_base(intern, Default::default())
|
||||
}
|
||||
|
||||
pub fn with_base(ctx: &'ctx mut ObjCtx, attrs: AttrsMap) -> Self {
|
||||
pub fn with_base(intern: &'i mut I, attrs: Ns) -> Self {
|
||||
AttrsBuilder {
|
||||
attrs,
|
||||
ctx,
|
||||
intern,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn attr(self, symbol_name: &str, value: DynRef) -> Self {
|
||||
let sym = self.ctx.gc_mut().add_sym(symbol_name);
|
||||
let sym = self.intern.intern_sym(symbol_name);
|
||||
self.attr_sym(sym, value)
|
||||
}
|
||||
|
||||
@@ -114,9 +113,9 @@ impl<'ctx> AttrsBuilder<'ctx> {
|
||||
self
|
||||
}
|
||||
|
||||
pub fn finish(self) -> ObjRef<Attrs> {
|
||||
let Self { ctx, attrs } = self;
|
||||
Attrs::new(ctx, attrs)
|
||||
pub fn finish<G: Gc>(self, gc: &mut G) -> ObjRef<Attrs> {
|
||||
let Self { intern: _, attrs } = self;
|
||||
Attrs::new(gc, attrs)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -124,13 +123,13 @@ impl<'ctx> AttrsBuilder<'ctx> {
|
||||
fn test_attrs_new() {
|
||||
use crate::mem::BasicGc;
|
||||
|
||||
let mut ctx = ObjCtx::new(BasicGc::default());
|
||||
let mut gc = BasicGc::default();
|
||||
|
||||
let attrs_ref = Attrs::new(&mut ctx, Default::default());
|
||||
let attrs_ref = Attrs::new(&mut gc, Default::default());
|
||||
|
||||
{
|
||||
let mut attrs = attrs_ref.borrow_mut();
|
||||
let sym = ctx.gc_mut().add_sym("symbol");
|
||||
let sym = gc.add_sym("symbol");
|
||||
attrs.insert(sym, attrs_ref.as_dyn());
|
||||
|
||||
assert!(
|
||||
|
||||
@@ -1,40 +1,31 @@
|
||||
use crate::{
|
||||
mem::{gc::Gc, ptr::DynRef, BasicGc},
|
||||
obj::Sym,
|
||||
mem::{gc::Gc, BasicGc},
|
||||
obj::prelude::*,
|
||||
};
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
pub type DefaultGc = BasicGc;
|
||||
|
||||
pub struct ObjCtx<G = DefaultGc>
|
||||
pub struct ObjCtx<'g, 'n, G>
|
||||
where
|
||||
G: Gc,
|
||||
G: Gc + 'g,
|
||||
{
|
||||
gc: G,
|
||||
globals: BTreeMap<Sym, DynRef>,
|
||||
gc: &'g mut G,
|
||||
ns: &'n mut Ns,
|
||||
}
|
||||
|
||||
impl<G> ObjCtx<G>
|
||||
impl<'g, 'n, G> ObjCtx<'g, 'n, G>
|
||||
where
|
||||
G: Gc,
|
||||
G: Gc + 'g,
|
||||
{
|
||||
pub fn new(gc: G) -> Self {
|
||||
ObjCtx { gc, globals: Default::default() }
|
||||
pub fn new(gc: &'g mut G, ns: &'n mut Ns) -> Self {
|
||||
ObjCtx { gc, ns }
|
||||
}
|
||||
|
||||
pub fn gc(&self) -> &G {
|
||||
&self.gc
|
||||
pub fn gc_mut(&'g mut self) -> &'g mut G {
|
||||
self.gc
|
||||
}
|
||||
|
||||
pub fn gc_mut(&mut self) -> &mut G {
|
||||
&mut self.gc
|
||||
}
|
||||
|
||||
pub fn globals(&self) -> &BTreeMap<Sym, DynRef> {
|
||||
&self.globals
|
||||
}
|
||||
|
||||
pub fn globals_mut(&mut self) -> &mut BTreeMap<Sym, DynRef> {
|
||||
&mut self.globals
|
||||
pub fn ns_mut(&'n mut self) -> &'n mut Ns {
|
||||
self.ns
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,19 +10,12 @@ pub struct Dict {
|
||||
}
|
||||
|
||||
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!()
|
||||
/*
|
||||
pub fn new(attrs: AttrsRef) -> Self {
|
||||
Dict {
|
||||
dict: Default::default(),
|
||||
attrs: Attrs::new(ctx),
|
||||
attrs,
|
||||
marked: Cell::new(false),
|
||||
}
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -4,13 +4,13 @@ use std::{any::Any, cell::Cell, rc::Rc};
|
||||
pub type NativeFunPtr = fn(argv: Vec<DynRef>);
|
||||
|
||||
pub struct NativeFun {
|
||||
attrs: ObjRef<Attrs>,
|
||||
attrs: AttrsRef,
|
||||
fn_ptr: NativeFunPtr,
|
||||
}
|
||||
|
||||
impl NativeFun {
|
||||
pub fn new(ctx: &mut ObjCtx, name: StrRef, fn_ptr: NativeFunPtr) -> Self {
|
||||
let attrs = Attrs::new(ctx, Default::default());
|
||||
pub fn new(attrs: AttrsRef, name: StrRef, fn_ptr: NativeFunPtr) -> Self {
|
||||
// TODO : clone attrs, add name
|
||||
NativeFun {
|
||||
attrs,
|
||||
fn_ptr,
|
||||
|
||||
@@ -4,6 +4,13 @@ pub mod dict;
|
||||
pub mod error;
|
||||
pub mod fun;
|
||||
//pub mod num;
|
||||
pub mod ns {
|
||||
use crate::{mem::ptr::DynRef, obj::Sym};
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
/// A namespace
|
||||
pub type Ns = BTreeMap<Sym, DynRef>;
|
||||
}
|
||||
pub mod str;
|
||||
pub mod sym {
|
||||
pub type Sym = usize;
|
||||
@@ -12,22 +19,21 @@ pub mod sym {
|
||||
|
||||
pub mod prelude {
|
||||
pub use crate::{
|
||||
obj::{
|
||||
Attrs, Dict, DictRef, Fun, NativeFun, Str, StrRef, Sym, ObjCtx, Obj,
|
||||
},
|
||||
mem::{
|
||||
ptr::{ObjRef, DynRef},
|
||||
intern::Intern,
|
||||
gc::Gc,
|
||||
}
|
||||
intern::Intern,
|
||||
ptr::{DynRef, ObjRef},
|
||||
},
|
||||
obj::{Attrs, AttrsRef, Dict, DictRef, Fun, NativeFun, Ns, Obj, ObjCtx, Str, StrRef, Sym},
|
||||
};
|
||||
}
|
||||
|
||||
pub use self::{
|
||||
attrs::Attrs,
|
||||
attrs::{Attrs, AttrsBuilder, AttrsRef},
|
||||
ctx::ObjCtx,
|
||||
dict::{Dict, DictRef},
|
||||
fun::{NativeFun, Fun},
|
||||
fun::{Fun, NativeFun},
|
||||
ns::Ns,
|
||||
str::{Str, StrRef},
|
||||
sym::Sym,
|
||||
};
|
||||
|
||||
@@ -8,7 +8,7 @@ pub type StrRef = ObjRef<Str>;
|
||||
#[derivative(PartialEq, PartialOrd, Ord, Eq)]
|
||||
pub struct Str {
|
||||
#[derivative(PartialEq = "ignore", PartialOrd = "ignore", Ord = "ignore")]
|
||||
attrs: ObjRef<Attrs>,
|
||||
attrs: AttrsRef,
|
||||
|
||||
contents: String,
|
||||
|
||||
@@ -17,20 +17,14 @@ pub struct Str {
|
||||
}
|
||||
|
||||
impl Str {
|
||||
pub fn new(ctx: &mut ObjCtx, contents: String) -> Self {
|
||||
pub fn new<G: Gc>(attrs: AttrsRef, contents: String) -> Self {
|
||||
Str {
|
||||
attrs: Self::type_attrs(ctx),
|
||||
attrs,
|
||||
contents,
|
||||
marked: Cell::new(false),
|
||||
}
|
||||
}
|
||||
|
||||
fn type_attrs(ctx: &mut ObjCtx) -> ObjRef<Attrs> {
|
||||
// TODO need global namespace
|
||||
// TODO need upcast from dyn to static
|
||||
todo!()
|
||||
}
|
||||
|
||||
pub fn contents(&self) -> &String {
|
||||
&self.contents
|
||||
}
|
||||
|
||||
@@ -1,17 +1,26 @@
|
||||
use crate::obj::prelude::*;
|
||||
use std::collections::BTreeMap;
|
||||
use crate::{
|
||||
obj::prelude::*,
|
||||
vm::op::Op,
|
||||
};
|
||||
use std::rc::Rc;
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct Frame {
|
||||
stack: Vec<DynRef>,
|
||||
ip: usize,
|
||||
return_value: Option<DynRef>,
|
||||
locals: BTreeMap<Sym, DynRef>,
|
||||
locals: Ns,
|
||||
ops: Rc<Vec<Op>>,
|
||||
}
|
||||
|
||||
impl Frame {
|
||||
pub fn new() -> Self {
|
||||
Default::default()
|
||||
pub fn new(ops: Rc<Vec<Op>>) -> Self {
|
||||
Frame {
|
||||
stack: Default::default(),
|
||||
ip: 0,
|
||||
return_value: None,
|
||||
locals: Default::default(),
|
||||
ops,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn push(&mut self, obj_ref: DynRef) {
|
||||
@@ -45,5 +54,9 @@ impl Frame {
|
||||
pub fn set_local(&mut self, sym: Sym, obj_ref: DynRef) -> Option<DynRef> {
|
||||
self.locals.insert(sym, obj_ref)
|
||||
}
|
||||
|
||||
pub fn ops(&self) -> &Rc<Vec<Op>> {
|
||||
&self.ops
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
180
src/vm/mod.rs
180
src/vm/mod.rs
@@ -3,6 +3,7 @@ pub mod frame;
|
||||
|
||||
use crate::{
|
||||
obj::prelude::*,
|
||||
mem::gc::Gc,
|
||||
vm::{
|
||||
op::Op,
|
||||
frame::Frame,
|
||||
@@ -10,122 +11,145 @@ use crate::{
|
||||
};
|
||||
use std::rc::Rc;
|
||||
|
||||
pub struct State {
|
||||
fn root_ns<I: Intern, G: Gc>(intern: &mut I, gc: &mut G) -> Ns {
|
||||
let mut ns: Ns = Default::default();
|
||||
ns.insert(intern.intern_sym("Unit"), Attrs::new(gc, Default::default()));
|
||||
ns
|
||||
}
|
||||
|
||||
pub struct State<I: Intern, G: Gc> {
|
||||
intern: I,
|
||||
gc: G,
|
||||
root_ns: Ns,
|
||||
frames: Vec<Frame>,
|
||||
}
|
||||
|
||||
impl State {
|
||||
pub fn new() -> Self {
|
||||
State { frames: Default::default(), }
|
||||
impl<I: Intern, G: Gc> State<I, G> {
|
||||
pub fn new(mut intern: I, mut gc: G) -> Self {
|
||||
let root_ns = root_ns(&mut intern, &mut gc);
|
||||
State { intern, gc, root_ns, frames: Default::default(), }
|
||||
}
|
||||
|
||||
fn frame(&self) -> &Frame {
|
||||
pub fn frames(&self) -> &Vec<Frame> {
|
||||
&self.frames
|
||||
}
|
||||
|
||||
pub fn frames_mut(&mut self) -> &mut Vec<Frame> {
|
||||
&mut self.frames
|
||||
}
|
||||
|
||||
pub fn frame(&self) -> &Frame {
|
||||
self.frames
|
||||
.last()
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
fn frame_mut(&mut self) -> &mut Frame {
|
||||
pub fn frame_mut(&mut self) -> &mut Frame {
|
||||
self.frames
|
||||
.last_mut()
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
fn push_stack(&mut self, value: DynRef) {
|
||||
pub fn push_stack(&mut self, value: DynRef) {
|
||||
self.frame_mut()
|
||||
.push(value);
|
||||
}
|
||||
|
||||
fn pop_stack(&mut self) -> Option<DynRef> {
|
||||
pub fn pop_stack(&mut self) -> Option<DynRef> {
|
||||
self.frame_mut()
|
||||
.pop()
|
||||
}
|
||||
|
||||
fn ip(&self) -> usize {
|
||||
pub fn ip(&self) -> usize {
|
||||
self.frame().ip()
|
||||
}
|
||||
|
||||
fn set_ip(&mut self, ip: usize) {
|
||||
pub fn set_ip(&mut self, ip: usize) {
|
||||
self.frame_mut().set_ip(ip);
|
||||
}
|
||||
|
||||
fn get_local(&self, sym: Sym) -> Option<DynRef> {
|
||||
pub fn get_local(&self, sym: Sym) -> Option<DynRef> {
|
||||
self.frame().get_local(sym)
|
||||
}
|
||||
|
||||
fn set_local(&mut self, sym: Sym, obj_ref: DynRef) -> Option<DynRef> {
|
||||
pub fn set_local(&mut self, sym: Sym, obj_ref: DynRef) -> Option<DynRef> {
|
||||
self.frame_mut().set_local(sym, obj_ref)
|
||||
}
|
||||
|
||||
pub fn run(&mut self, ops: Rc<Vec<Op>>) {
|
||||
self.frames.push(Default::default());
|
||||
while self.ip() < ops.len() {
|
||||
let mut next_ip = self.ip() + 1;
|
||||
match &ops[self.ip()] {
|
||||
Op::Push(sym) => {
|
||||
// TODO - local not found
|
||||
let obj_ref = self.get_local(*sym)
|
||||
.expect("TODO - local not found");
|
||||
self.push_stack(obj_ref);
|
||||
}
|
||||
Op::Pop(sym) => {
|
||||
// stack should not underflow
|
||||
let obj_ref = self.pop_stack()
|
||||
.expect("misaligned stack for pop");
|
||||
if let Some(sym) = *sym {
|
||||
self.set_local(sym, obj_ref);
|
||||
}
|
||||
}
|
||||
Op::GetAttr(sym) => {
|
||||
let top = self.pop_stack()
|
||||
.expect("misaligned stack for getattrs");
|
||||
let obj_ref = {
|
||||
let top_ref = top.borrow();
|
||||
let attrs = top_ref.attrs();
|
||||
let attrs_ref = attrs.borrow();
|
||||
// TODO - local not found
|
||||
attrs_ref.get(*sym)
|
||||
.expect("TODO - local not found")
|
||||
};
|
||||
self.push_stack(obj_ref);
|
||||
}
|
||||
Op::Call(argc) => {
|
||||
let fun = self.pop_stack()
|
||||
.expect("misaligned stack for function call");
|
||||
let mut argv = Vec::with_capacity(*argc);
|
||||
for i in 0 .. *argc {
|
||||
let arg = self.pop_stack()
|
||||
.expect("misaligned stack for argv");
|
||||
argv.push(arg);
|
||||
}
|
||||
// reverse since arguments are pushed in order of being passed
|
||||
argv.reverse();
|
||||
pub fn ops(&self) -> &Rc<Vec<Op>> {
|
||||
self.frame().ops()
|
||||
}
|
||||
|
||||
// call function
|
||||
// TODO - call the function indirectly?
|
||||
//
|
||||
// problem: downcast_ref returns a reference bound by the lifetime of the
|
||||
// function (because of the ref cell). This keeps the fun object borrowed,
|
||||
// which means any attempts to modify the function while it is running will
|
||||
// cause the VM to panic.
|
||||
//
|
||||
// possible solution:
|
||||
// pop the function object, and then determine which function to call on the
|
||||
// object (possibly after downcasting?)
|
||||
//
|
||||
// TODO
|
||||
// Figure out a way to either call a native function with NativeFun::call, or
|
||||
// call a user function with Fun::code()
|
||||
if let Some(fun) = fun.borrow().as_any().downcast_ref::<Fun>() {
|
||||
} else if let Some(fun) = fun.borrow().as_any().downcast_ref::<NativeFun>() {
|
||||
} else {
|
||||
todo!("TODO - not a function")
|
||||
}
|
||||
todo!()
|
||||
pub fn resume(&mut self) {
|
||||
while !self.frames().is_empty() {
|
||||
self.resume_fun();
|
||||
let _frame = self.frames_mut().pop().unwrap();
|
||||
// Push return value?
|
||||
}
|
||||
}
|
||||
|
||||
pub fn resume_fun(&mut self) {
|
||||
while self.ip() < self.ops().len() {
|
||||
self.step();
|
||||
}
|
||||
}
|
||||
|
||||
pub fn step(&mut self) {
|
||||
let mut next_ip = self.ip() + 1;
|
||||
match self.ops()[self.ip()] {
|
||||
Op::Push(sym) => {
|
||||
// TODO - local not found
|
||||
let obj_ref = self.get_local(sym)
|
||||
.expect("TODO - local not found");
|
||||
self.push_stack(obj_ref);
|
||||
}
|
||||
Op::Pop(sym) => {
|
||||
// stack should not underflow
|
||||
let obj_ref = self.pop_stack()
|
||||
.expect("misaligned stack for pop");
|
||||
if let Some(sym) = sym {
|
||||
self.set_local(sym, obj_ref);
|
||||
}
|
||||
}
|
||||
self.set_ip(next_ip);
|
||||
Op::GetAttr(sym) => {
|
||||
let top = self.pop_stack()
|
||||
.expect("misaligned stack for getattrs");
|
||||
let obj_ref = {
|
||||
let top_ref = top.borrow();
|
||||
let attrs = top_ref.attrs();
|
||||
let attrs_ref = attrs.borrow();
|
||||
// TODO - local not found
|
||||
attrs_ref.get(sym)
|
||||
.expect("TODO - local not found")
|
||||
};
|
||||
self.push_stack(obj_ref);
|
||||
}
|
||||
Op::Call(argc) => {
|
||||
let fun = self.pop_stack()
|
||||
.expect("misaligned stack for function call");
|
||||
let mut argv = Vec::with_capacity(argc);
|
||||
for _ in 0 .. argc {
|
||||
let arg = self.pop_stack()
|
||||
.expect("misaligned stack for argv");
|
||||
argv.push(arg);
|
||||
}
|
||||
// reverse since arguments are pushed in order of being passed
|
||||
argv.reverse();
|
||||
|
||||
// TODO
|
||||
// move ops pointer to the stack frame
|
||||
if let Some(_fun) = fun.borrow().as_any().downcast_ref::<Fun>() {
|
||||
self.set_ip(next_ip);
|
||||
next_ip = 0;
|
||||
todo!("New stack frame");
|
||||
} else if let Some(_fun) = fun.borrow().as_any().downcast_ref::<NativeFun>() {
|
||||
todo!();
|
||||
} else {
|
||||
todo!("TODO - not a function");
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
self.frames.pop();
|
||||
self.set_ip(next_ip);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ use crate::obj::Sym;
|
||||
// * ops deal with symbols directly
|
||||
// * stack values are either obj references or symbols
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub enum Op {
|
||||
/// Push a value from a symbol
|
||||
Push(Sym),
|
||||
|
||||
Reference in New Issue
Block a user