2020-09-14 14:09:29 -07:00
|
|
|
pub mod consts;
|
2020-09-14 16:32:00 -07:00
|
|
|
pub mod error;
|
|
|
|
|
pub mod frame;
|
|
|
|
|
pub mod inst;
|
2020-09-01 17:32:48 -07:00
|
|
|
|
2020-09-14 16:32:00 -07:00
|
|
|
use crate::{
|
2020-09-18 13:57:51 -07:00
|
|
|
obj::{reserved::*, prelude::*},
|
2020-09-14 16:32:00 -07:00
|
|
|
vm::{consts::*, error::*, frame::*, inst::*},
|
|
|
|
|
};
|
|
|
|
|
use shredder::{GcSafe, Scanner, Scan};
|
2020-09-01 17:32:48 -07:00
|
|
|
|
|
|
|
|
#[derive(Debug)]
|
2020-09-14 16:32:00 -07:00
|
|
|
pub struct Vm<'c> {
|
2020-09-01 17:32:48 -07:00
|
|
|
stack: Vec<ObjRef>,
|
|
|
|
|
frames: Vec<Frame>,
|
|
|
|
|
pc: usize,
|
|
|
|
|
condition: bool,
|
2020-09-14 16:32:00 -07:00
|
|
|
const_pool: &'c ConstPool,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
unsafe impl Scan for Vm<'_> {
|
|
|
|
|
fn scan(&self, scanner: &mut Scanner) {
|
|
|
|
|
scanner.scan(&self.stack);
|
|
|
|
|
scanner.scan(&self.frames);
|
|
|
|
|
}
|
2020-09-01 17:32:48 -07:00
|
|
|
}
|
|
|
|
|
|
2020-09-14 16:32:00 -07:00
|
|
|
unsafe impl GcSafe for Vm<'_> {}
|
|
|
|
|
|
|
|
|
|
impl<'c> Vm<'c> {
|
|
|
|
|
pub fn new(const_pool: &'c ConstPool) -> Self {
|
2020-09-01 17:32:48 -07:00
|
|
|
Self {
|
|
|
|
|
stack: Default::default(),
|
2020-09-14 16:32:00 -07:00
|
|
|
frames: vec![],
|
2020-09-01 17:32:48 -07:00
|
|
|
pc: 0,
|
|
|
|
|
condition: false,
|
2020-09-14 16:32:00 -07:00
|
|
|
const_pool,
|
2020-09-01 17:32:48 -07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-09-14 16:32:00 -07:00
|
|
|
/// Gets the current stack frame, if any.
|
|
|
|
|
pub fn frame(&self) -> Option<&Frame> {
|
|
|
|
|
self.frames.last()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Gets the current stack frame mutably, if any.
|
|
|
|
|
pub fn frame_mut(&mut self) -> Option<&mut Frame> {
|
|
|
|
|
self.frames.last_mut()
|
|
|
|
|
}
|
|
|
|
|
|
2020-09-14 16:37:16 -07:00
|
|
|
/// Gets the list of stack frames.
|
|
|
|
|
pub fn frames(&self) -> &Vec<Frame> {
|
|
|
|
|
&self.frames
|
|
|
|
|
}
|
|
|
|
|
|
2020-09-14 16:32:00 -07:00
|
|
|
/// Gets the stack.
|
2020-09-01 17:32:48 -07:00
|
|
|
pub fn stack(&self) -> &Vec<ObjRef> {
|
|
|
|
|
&self.stack
|
|
|
|
|
}
|
|
|
|
|
|
2020-09-14 16:32:00 -07:00
|
|
|
/// Gets the stack, mutably.
|
2020-09-01 17:32:48 -07:00
|
|
|
pub fn stack_mut(&mut self) -> &mut Vec<ObjRef> {
|
|
|
|
|
&mut self.stack
|
|
|
|
|
}
|
|
|
|
|
|
2020-09-14 16:32:00 -07:00
|
|
|
/// Pushes a value to the stack.
|
2020-09-01 17:32:48 -07:00
|
|
|
pub fn push(&mut self, value: ObjRef) {
|
|
|
|
|
self.stack_mut().push(value);
|
|
|
|
|
}
|
|
|
|
|
|
2020-09-14 16:32:00 -07:00
|
|
|
/// Pops a value from the stack.
|
2020-09-01 17:32:48 -07:00
|
|
|
pub fn pop(&mut self) -> Option<ObjRef> {
|
|
|
|
|
self.stack_mut().pop()
|
|
|
|
|
}
|
|
|
|
|
|
2020-09-14 16:32:00 -07:00
|
|
|
/// Gets the current program counter address.
|
2020-09-01 17:32:48 -07:00
|
|
|
pub fn pc(&self) -> usize {
|
|
|
|
|
self.pc
|
|
|
|
|
}
|
|
|
|
|
|
2020-09-14 16:32:00 -07:00
|
|
|
/// Set the next program counter value.
|
|
|
|
|
///
|
|
|
|
|
/// This may cause the running program to crash. Handle with care.
|
|
|
|
|
pub fn set_pc(&mut self, pc: usize) {
|
|
|
|
|
self.pc = pc;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Gets whether the condition flag has been set or not.
|
2020-09-01 17:32:48 -07:00
|
|
|
pub fn condition(&self) -> bool {
|
|
|
|
|
self.condition
|
|
|
|
|
}
|
|
|
|
|
|
2020-09-14 16:32:00 -07:00
|
|
|
/// Sets the condition flag to the specified value.
|
|
|
|
|
pub fn set_condition(&mut self, condition: bool) {
|
|
|
|
|
self.condition = condition;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Run a single instruction.
|
|
|
|
|
pub fn tick(&mut self) -> Result<()> {
|
|
|
|
|
self.do_tick()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Gets the current instruction.
|
|
|
|
|
#[inline(always)]
|
|
|
|
|
fn load_inst(&self) -> Inst {
|
|
|
|
|
if let FrameKind::User { fun, .. } = self.frame().expect("frame").kind() {
|
|
|
|
|
read_obj!(let fun = fun);
|
|
|
|
|
fun.code()[self.pc()]
|
|
|
|
|
} else {
|
|
|
|
|
panic!("invalid stack frame");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Run a single instruction - inlined version.
|
|
|
|
|
///
|
|
|
|
|
/// Since this is inlined, it is probably a bad idea to allow users to use it everywhere. The
|
|
|
|
|
/// exposed API function `tick()` calls this function, but does not inline itself (unless the
|
|
|
|
|
/// optimizer thinks it's a good idea to do so).
|
|
|
|
|
#[inline]
|
|
|
|
|
fn do_tick(&mut self) -> Result<()> {
|
|
|
|
|
let inst = self.load_inst();
|
|
|
|
|
let mut next_pc = self.pc() + 1;
|
|
|
|
|
match inst {
|
|
|
|
|
Inst::PushSym(sym) => {
|
|
|
|
|
let sym_ref = global_sym_ref(sym);
|
|
|
|
|
self.push(sym_ref);
|
|
|
|
|
}
|
|
|
|
|
Inst::PushConst(hdl) => {
|
|
|
|
|
let obj_ref = self.const_pool.get(hdl).clone();
|
|
|
|
|
self.push(obj_ref);
|
|
|
|
|
}
|
2020-09-18 13:57:51 -07:00
|
|
|
Inst::LoadName(_sym) => todo!(),
|
2020-09-14 16:32:00 -07:00
|
|
|
Inst::Pop(Some(_sym)) => todo!(),
|
|
|
|
|
Inst::Pop(None) => todo!(),
|
|
|
|
|
Inst::GetAttr(sym) => {
|
|
|
|
|
let obj_ref = self.pop().expect("getattr object");
|
|
|
|
|
read_obj!(let obj = obj_ref);
|
|
|
|
|
let attr = obj
|
|
|
|
|
.get_attr(sym)
|
|
|
|
|
.unwrap_or_else(|| global_sym_ref(NIL_NAME.sym));
|
|
|
|
|
self.push(attr);
|
|
|
|
|
}
|
|
|
|
|
Inst::SetAttr(_sym) => todo!(),
|
|
|
|
|
Inst::Jump(addr) => {
|
|
|
|
|
next_pc = addr;
|
|
|
|
|
}
|
|
|
|
|
Inst::JumpTrue(addr) => {
|
|
|
|
|
if self.condition {
|
|
|
|
|
next_pc = addr;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
Inst::Call(_argc) => todo!(),
|
|
|
|
|
Inst::Index => todo!(),
|
|
|
|
|
Inst::Return => todo!(),
|
|
|
|
|
Inst::UnNeg => todo!(),
|
|
|
|
|
Inst::UnPos => todo!(),
|
|
|
|
|
Inst::BinPlus => todo!(),
|
|
|
|
|
Inst::BinMinus => todo!(),
|
|
|
|
|
Inst::BinMul => todo!(),
|
|
|
|
|
Inst::BinDiv => todo!(),
|
|
|
|
|
Inst::BinEq => todo!(),
|
|
|
|
|
Inst::BinNeq => todo!(),
|
|
|
|
|
Inst::BinLt => todo!(),
|
|
|
|
|
Inst::BinLe => todo!(),
|
|
|
|
|
Inst::BinGt => todo!(),
|
|
|
|
|
Inst::BinGe => todo!(),
|
|
|
|
|
Inst::BinAnd => todo!(),
|
|
|
|
|
Inst::BinOr => todo!(),
|
|
|
|
|
}
|
|
|
|
|
self.set_pc(next_pc);
|
|
|
|
|
//let mut next_index = self.
|
|
|
|
|
Ok(())
|
|
|
|
|
}
|
2020-09-01 17:32:48 -07:00
|
|
|
}
|