Update how visitors work, add NameId type
* Visitors are now defined on a per-type level, allowing for greater flexibility in combining and re-using behavior * NameId is used for namespaces, which are used to index locally scoped variables. Syms are used for free namespaces, specifically in objects. All NameIDs are symbols, while not all symbols are NameIDs. Signed-off-by: Alek Ratzloff <alekratz@gmail.com>
This commit is contained in:
@@ -2,13 +2,13 @@ use crate::{
|
||||
obj::prelude::*,
|
||||
vm::op::Op,
|
||||
};
|
||||
use std::rc::Rc;
|
||||
use std::{collections::BTreeMap, rc::Rc};
|
||||
|
||||
pub struct Frame {
|
||||
stack: Vec<DynRef>,
|
||||
ip: usize,
|
||||
return_value: Option<DynRef>,
|
||||
locals: Ns,
|
||||
locals: BTreeMap<NameId, DynRef>,
|
||||
ops: Rc<Vec<Op>>,
|
||||
}
|
||||
|
||||
@@ -47,11 +47,11 @@ impl Frame {
|
||||
self.return_value = Some(obj_ref);
|
||||
}
|
||||
|
||||
pub fn get_local(&self, sym: Sym) -> Option<DynRef> {
|
||||
self.locals.get(&sym).copied()
|
||||
pub fn get_local(&self, name: NameId) -> Option<DynRef> {
|
||||
self.locals.get(&name).copied()
|
||||
}
|
||||
|
||||
pub fn set_local(&mut self, sym: Sym, obj_ref: DynRef) -> Option<DynRef> {
|
||||
pub fn set_local(&mut self, sym: NameId, obj_ref: DynRef) -> Option<DynRef> {
|
||||
self.locals.insert(sym, obj_ref)
|
||||
}
|
||||
|
||||
|
||||
@@ -1,21 +1,23 @@
|
||||
pub mod op;
|
||||
pub mod frame;
|
||||
pub mod op;
|
||||
|
||||
use crate::{
|
||||
obj::prelude::*,
|
||||
mem::gc::Gc,
|
||||
vm::{
|
||||
op::Op,
|
||||
frame::Frame,
|
||||
}
|
||||
obj::prelude::*,
|
||||
vm::{frame::Frame, op::Op},
|
||||
};
|
||||
use std::rc::Rc;
|
||||
|
||||
/*
|
||||
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.insert(
|
||||
intern.intern_sym("Unit"),
|
||||
Attrs::new(gc, Default::default()),
|
||||
);
|
||||
ns
|
||||
}
|
||||
*/
|
||||
|
||||
pub struct State<I: Intern, G: Gc> {
|
||||
intern: I,
|
||||
@@ -25,9 +27,14 @@ pub struct State<I: Intern, G: Gc> {
|
||||
}
|
||||
|
||||
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(), }
|
||||
pub fn new(intern: I, gc: G, root_ns: Ns) -> Self {
|
||||
//let root_ns = root_ns(&mut intern, &mut gc);
|
||||
State {
|
||||
intern,
|
||||
gc,
|
||||
root_ns,
|
||||
frames: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn frames(&self) -> &Vec<Frame> {
|
||||
@@ -39,25 +46,19 @@ impl<I: Intern, G: Gc> State<I, G> {
|
||||
}
|
||||
|
||||
pub fn frame(&self) -> &Frame {
|
||||
self.frames
|
||||
.last()
|
||||
.unwrap()
|
||||
self.frames.last().unwrap()
|
||||
}
|
||||
|
||||
pub fn frame_mut(&mut self) -> &mut Frame {
|
||||
self.frames
|
||||
.last_mut()
|
||||
.unwrap()
|
||||
self.frames.last_mut().unwrap()
|
||||
}
|
||||
|
||||
pub fn push_stack(&mut self, value: DynRef) {
|
||||
self.frame_mut()
|
||||
.push(value);
|
||||
self.frame_mut().push(value);
|
||||
}
|
||||
|
||||
pub fn pop_stack(&mut self) -> Option<DynRef> {
|
||||
self.frame_mut()
|
||||
.pop()
|
||||
self.frame_mut().pop()
|
||||
}
|
||||
|
||||
pub fn ip(&self) -> usize {
|
||||
@@ -68,12 +69,12 @@ impl<I: Intern, G: Gc> State<I, G> {
|
||||
self.frame_mut().set_ip(ip);
|
||||
}
|
||||
|
||||
pub fn get_local(&self, sym: Sym) -> Option<DynRef> {
|
||||
self.frame().get_local(sym)
|
||||
pub fn get_local(&self, name: NameId) -> Option<DynRef> {
|
||||
self.frame().get_local(name)
|
||||
}
|
||||
|
||||
pub fn set_local(&mut self, sym: Sym, obj_ref: DynRef) -> Option<DynRef> {
|
||||
self.frame_mut().set_local(sym, obj_ref)
|
||||
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>> {
|
||||
@@ -97,40 +98,36 @@ impl<I: Intern, G: Gc> State<I, G> {
|
||||
pub fn step(&mut self) {
|
||||
let mut next_ip = self.ip() + 1;
|
||||
match self.ops()[self.ip()] {
|
||||
Op::Push(sym) => {
|
||||
Op::Push(name) => {
|
||||
// TODO - local not found
|
||||
let obj_ref = self.get_local(sym)
|
||||
.expect("TODO - local not found");
|
||||
let obj_ref = self.get_local(name).expect("TODO - local not found");
|
||||
self.push_stack(obj_ref);
|
||||
}
|
||||
Op::Pop(sym) => {
|
||||
Op::Pop(name) => {
|
||||
// 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);
|
||||
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 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")
|
||||
attrs_ref.get(sym).expect("TODO - local not found")
|
||||
};
|
||||
self.push_stack(obj_ref);
|
||||
}
|
||||
Op::Call(argc) => {
|
||||
let fun = self.pop_stack()
|
||||
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");
|
||||
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
|
||||
@@ -147,7 +144,6 @@ impl<I: Intern, G: Gc> State<I, G> {
|
||||
} else {
|
||||
todo!("TODO - not a function");
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
self.set_ip(next_ip);
|
||||
|
||||
10
src/vm/op.rs
10
src/vm/op.rs
@@ -1,4 +1,4 @@
|
||||
use crate::obj::Sym;
|
||||
use crate::obj::{NameId, Sym};
|
||||
|
||||
// VM execution model:
|
||||
// * every function call has its own stack frame
|
||||
@@ -8,11 +8,11 @@ use crate::obj::Sym;
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub enum Op {
|
||||
/// Push a value from a symbol
|
||||
Push(Sym),
|
||||
/// Push a value from a name ID.
|
||||
Push(NameId),
|
||||
|
||||
/// Pop the top stack value into a local (if supplied)
|
||||
Pop(Option<Sym>),
|
||||
/// Pop the top stack value into a local name (if supplied)
|
||||
Pop(Option<NameId>),
|
||||
|
||||
/// Pop the top stack value, getting an attribute and replacing pushing that value to the
|
||||
/// stack.
|
||||
|
||||
Reference in New Issue
Block a user