136 lines
3.7 KiB
Rust
136 lines
3.7 KiB
Rust
pub mod frame;
|
|
pub mod op;
|
|
|
|
use crate::{
|
|
mem::gc::Gc,
|
|
obj::prelude::*,
|
|
vm::{frame::Frame, op::Op},
|
|
};
|
|
use std::rc::Rc;
|
|
|
|
pub struct State<G: Gc> {
|
|
gc: G,
|
|
frames: Vec<Frame>,
|
|
}
|
|
|
|
impl<G: Gc> State<G> {
|
|
pub fn new(gc: G) -> Self {
|
|
State {
|
|
gc,
|
|
frames: Default::default(),
|
|
}
|
|
}
|
|
|
|
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()
|
|
}
|
|
|
|
pub fn frame_mut(&mut self) -> &mut Frame {
|
|
self.frames.last_mut().unwrap()
|
|
}
|
|
|
|
pub fn push_stack(&mut self, value: DynRef) {
|
|
self.frame_mut().push(value);
|
|
}
|
|
|
|
pub fn pop_stack(&mut self) -> Option<DynRef> {
|
|
self.frame_mut().pop()
|
|
}
|
|
|
|
pub fn ip(&self) -> usize {
|
|
self.frame().ip()
|
|
}
|
|
|
|
pub fn set_ip(&mut self, ip: usize) {
|
|
self.frame_mut().set_ip(ip);
|
|
}
|
|
|
|
pub fn get_local(&self, name: NameId) -> Option<DynRef> {
|
|
self.frame().get_local(name)
|
|
}
|
|
|
|
pub fn set_local(&mut self, name: NameId, obj_ref: DynRef) -> Option<DynRef> {
|
|
self.frame_mut().set_local(name, obj_ref)
|
|
}
|
|
|
|
pub fn ops(&self) -> &Rc<Vec<Op>> {
|
|
self.frame().ops()
|
|
}
|
|
|
|
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(name) => {
|
|
// TODO - local not found
|
|
let obj_ref = self.get_local(name).expect("TODO - local not found");
|
|
self.push_stack(obj_ref);
|
|
}
|
|
Op::Pop(name) => {
|
|
// stack should not underflow
|
|
let obj_ref = self.pop_stack().expect("misaligned stack for pop");
|
|
if let Some(name) = name {
|
|
self.set_local(name, 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 _ 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.set_ip(next_ip);
|
|
}
|
|
}
|