pub mod op; pub mod frame; use crate::{ obj::prelude::*, mem::gc::Gc, vm::{ op::Op, frame::Frame, } }; use std::rc::Rc; fn root_ns(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 { intern: I, gc: G, root_ns: Ns, frames: Vec, } impl State { 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(), } } pub fn frames(&self) -> &Vec { &self.frames } pub fn frames_mut(&mut self) -> &mut Vec { &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 { 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, sym: Sym) -> Option { self.frame().get_local(sym) } pub fn set_local(&mut self, sym: Sym, obj_ref: DynRef) -> Option { self.frame_mut().set_local(sym, obj_ref) } pub fn ops(&self) -> &Rc> { 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(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 _ 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::() { self.set_ip(next_ip); next_ip = 0; todo!("New stack frame"); } else if let Some(_fun) = fun.borrow().as_any().downcast_ref::() { todo!(); } else { todo!("TODO - not a function"); } } } self.set_ip(next_ip); } }