Changes all around - objects and GC
Signed-off-by: Alek Ratzloff <alekratz@gmail.com>
This commit is contained in:
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);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user