@@ -8,7 +8,7 @@ pub struct ConstPool {
|
||||
}
|
||||
|
||||
// Constant pools are constant, and live for the lifetime of the entire program.
|
||||
impl shredder::EmptyScan for ConstPool { }
|
||||
impl shredder::EmptyScan for ConstPool {}
|
||||
|
||||
impl ConstPool {
|
||||
pub fn new() -> Self {
|
||||
|
||||
@@ -4,20 +4,17 @@ use snafu::Snafu;
|
||||
#[derive(Debug, Snafu)]
|
||||
pub enum Error {
|
||||
#[snafu(display("missing attribute: {}", global_sym_lookup(*attr).unwrap()))]
|
||||
MissingAttr {
|
||||
attr: Sym,
|
||||
},
|
||||
MissingAttr { attr: Sym },
|
||||
|
||||
#[snafu(display("{}", error))]
|
||||
ValueError {
|
||||
error: String,
|
||||
},
|
||||
ValueError { error: String },
|
||||
|
||||
#[snafu(display("incorrect function arity; expected {} but got {} instead", expected, got))]
|
||||
ArityError {
|
||||
expected: usize,
|
||||
got: usize,
|
||||
},
|
||||
#[snafu(display(
|
||||
"incorrect function arity; expected {} but got {} instead",
|
||||
expected,
|
||||
got
|
||||
))]
|
||||
ArityError { expected: usize, got: usize },
|
||||
}
|
||||
|
||||
pub type Result<T, E = Error> = std::result::Result<T, E>;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use crate::{obj::prelude::*, vm::inst::Inst};
|
||||
use std::fmt::{self, Debug, Formatter};
|
||||
use std::{collections::BTreeMap, sync::Arc};
|
||||
use std::fmt::{self, Formatter, Debug};
|
||||
|
||||
pub type FrameBindings = BTreeMap<usize, ObjRef>;
|
||||
|
||||
@@ -53,8 +53,18 @@ pub struct UserFrame {
|
||||
}
|
||||
|
||||
impl UserFrame {
|
||||
pub fn new(callee: ObjRef, bindings: FrameBindings, last_pc: usize, code: Arc<Vec<Inst>>) -> Self {
|
||||
Self { callee, bindings, last_pc, code, }
|
||||
pub fn new(
|
||||
callee: ObjRef,
|
||||
bindings: FrameBindings,
|
||||
last_pc: usize,
|
||||
code: Arc<Vec<Inst>>,
|
||||
) -> Self {
|
||||
Self {
|
||||
callee,
|
||||
bindings,
|
||||
last_pc,
|
||||
code,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn bindings(&self) -> &FrameBindings {
|
||||
@@ -86,7 +96,11 @@ pub struct NativeFrame {
|
||||
|
||||
impl NativeFrame {
|
||||
pub fn new(callee: ObjRef, fun_ptr: NativeFunPtr, args: Vec<ObjRef>) -> Self {
|
||||
Self { callee, fun_ptr, args }
|
||||
Self {
|
||||
callee,
|
||||
fun_ptr,
|
||||
args,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn fun_ptr(&self) -> &NativeFunPtr {
|
||||
@@ -105,7 +119,10 @@ impl NativeFrame {
|
||||
impl Debug for NativeFrame {
|
||||
fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
|
||||
fmt.debug_struct("NativeFrame")
|
||||
.field("fun_ptr", &format!("{:#x}", &self.fun_ptr as *const _ as usize))
|
||||
.field(
|
||||
"fun_ptr",
|
||||
&format!("{:#x}", &self.fun_ptr as *const _ as usize),
|
||||
)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -154,4 +154,4 @@ impl Inst {
|
||||
}
|
||||
}
|
||||
|
||||
impl EmptyScan for Inst { }
|
||||
impl EmptyScan for Inst {}
|
||||
|
||||
@@ -5,7 +5,7 @@ pub mod inst;
|
||||
pub mod signal;
|
||||
|
||||
use crate::{
|
||||
obj::{builtin::BUILTIN_OBJS, reserved::*, prelude::*},
|
||||
obj::{builtin::BUILTIN_OBJS, prelude::*, reserved::*},
|
||||
vm::{consts::ConstPool, error::*, frame::*, inst::*, signal::*},
|
||||
};
|
||||
|
||||
@@ -19,7 +19,7 @@ pub struct Vm<'c> {
|
||||
}
|
||||
|
||||
impl<'c> Vm<'c> {
|
||||
pub fn new(const_pool: &'c ConstPool,) -> Self {
|
||||
pub fn new(const_pool: &'c ConstPool) -> Self {
|
||||
Self {
|
||||
stack: Default::default(),
|
||||
frames: vec![],
|
||||
@@ -122,9 +122,7 @@ impl<'c> Vm<'c> {
|
||||
let args = fun.args().clone();
|
||||
(*fun.fun_ptr())(callee, self, args)?
|
||||
}
|
||||
Frame::User(_) => {
|
||||
self.resume_user_fun()
|
||||
}
|
||||
Frame::User(_) => self.resume_user_fun(),
|
||||
};
|
||||
self.handle_signal(signal)?;
|
||||
}
|
||||
@@ -148,8 +146,11 @@ impl<'c> Vm<'c> {
|
||||
match signal {
|
||||
Signal::Call(callee, args) => {
|
||||
read_obj!(let callee_obj = callee);
|
||||
let frame = callee_obj.as_fun()
|
||||
.ok_or_else(|| Error::ValueError { error: "cannot call this object".to_string() })?
|
||||
let frame = callee_obj
|
||||
.as_fun()
|
||||
.ok_or_else(|| Error::ValueError {
|
||||
error: "cannot call this object".to_string(),
|
||||
})?
|
||||
.create_frame(callee.clone(), self, args)?;
|
||||
// Jump to the first address of the new function call if it's a user function
|
||||
if let Frame::User(_) = &frame {
|
||||
@@ -207,19 +208,20 @@ impl<'c> Vm<'c> {
|
||||
self.push(obj_ref);
|
||||
}
|
||||
Inst::LoadLocal(local) => {
|
||||
let value = self.get_local(local)
|
||||
let value = self
|
||||
.get_local(local)
|
||||
.expect("TODO: throw error for missing local");
|
||||
self.push(value);
|
||||
}
|
||||
Inst::LoadGlobal(global) => {
|
||||
let value = self.get_global(global)
|
||||
let value = self
|
||||
.get_global(global)
|
||||
.or_else(|| self.get_builtin(global))
|
||||
.expect("TODO: throw error for missing global");
|
||||
self.push(value);
|
||||
}
|
||||
Inst::PopLocal(name) => {
|
||||
let tos = self.pop()
|
||||
.expect("stack underflow");
|
||||
let tos = self.pop().expect("stack underflow");
|
||||
// pop into name
|
||||
if let Some(name) = name {
|
||||
self.set_local(name, tos);
|
||||
@@ -227,8 +229,7 @@ impl<'c> Vm<'c> {
|
||||
// else discard
|
||||
}
|
||||
Inst::PopGlobal(name) => {
|
||||
let tos = self.pop()
|
||||
.expect("stack underflow");
|
||||
let tos = self.pop().expect("stack underflow");
|
||||
// pop into name
|
||||
if let Some(name) = name {
|
||||
self.set_global(name, tos);
|
||||
@@ -244,10 +245,8 @@ impl<'c> Vm<'c> {
|
||||
self.push(attr);
|
||||
}
|
||||
Inst::SetAttr(sym) => {
|
||||
let target = self.pop()
|
||||
.expect("no target available for SetAttr");
|
||||
let source = self.pop()
|
||||
.expect("no source available for SetAttr");
|
||||
let target = self.pop().expect("no target available for SetAttr");
|
||||
let source = self.pop().expect("no source available for SetAttr");
|
||||
write_obj!(let target = target);
|
||||
if let Some(attrs) = target.attrs_mut() {
|
||||
attrs.insert(sym, source);
|
||||
@@ -266,15 +265,17 @@ impl<'c> Vm<'c> {
|
||||
Inst::Call(argc) => {
|
||||
let stack_top = self.stack.len() - argc;
|
||||
let args = self.stack.split_off(stack_top);
|
||||
let tos = self.pop()
|
||||
.expect("stack underflow");
|
||||
let tos = self.pop().expect("stack underflow");
|
||||
read_obj!(let tos = tos);
|
||||
let callee = tos.get_call()
|
||||
let callee = tos
|
||||
.get_call()
|
||||
.expect("TODO: throw an error for missing __call__ attr");
|
||||
signal = Some(Signal::Call(callee, args));
|
||||
}
|
||||
Inst::Index => todo!(),
|
||||
Inst::Return => { signal = Some(Signal::Return); }
|
||||
Inst::Return => {
|
||||
signal = Some(Signal::Return);
|
||||
}
|
||||
Inst::UnNeg => todo!(),
|
||||
Inst::UnPos => todo!(),
|
||||
Inst::BinPlus => {
|
||||
@@ -282,7 +283,8 @@ impl<'c> Vm<'c> {
|
||||
let lhs = self.pop().unwrap();
|
||||
let fun = {
|
||||
read_obj!(let lhs = lhs);
|
||||
lhs.get_plus().expect("TODO: throw an error for missing __add__ attr")
|
||||
lhs.get_plus()
|
||||
.expect("TODO: throw an error for missing __add__ attr")
|
||||
};
|
||||
signal = Some(Signal::Call(fun, vec![rhs]));
|
||||
}
|
||||
@@ -291,7 +293,8 @@ impl<'c> Vm<'c> {
|
||||
let lhs = self.pop().unwrap();
|
||||
let fun = {
|
||||
read_obj!(let lhs = lhs);
|
||||
lhs.get_minus().expect("TODO: throw an error for missing __sub__ attr")
|
||||
lhs.get_minus()
|
||||
.expect("TODO: throw an error for missing __sub__ attr")
|
||||
};
|
||||
signal = Some(Signal::Call(fun, vec![rhs]));
|
||||
}
|
||||
@@ -300,7 +303,8 @@ impl<'c> Vm<'c> {
|
||||
let lhs = self.pop().unwrap();
|
||||
let fun = {
|
||||
read_obj!(let lhs = lhs);
|
||||
lhs.get_mul().expect("TODO: throw an error for missing __mul__ attr")
|
||||
lhs.get_mul()
|
||||
.expect("TODO: throw an error for missing __mul__ attr")
|
||||
};
|
||||
signal = Some(Signal::Call(fun, vec![rhs]));
|
||||
}
|
||||
@@ -309,7 +313,8 @@ impl<'c> Vm<'c> {
|
||||
let lhs = self.pop().unwrap();
|
||||
let fun = {
|
||||
read_obj!(let lhs = lhs);
|
||||
lhs.get_div().expect("TODO: throw an error for missing __div__ attr")
|
||||
lhs.get_div()
|
||||
.expect("TODO: throw an error for missing __div__ attr")
|
||||
};
|
||||
signal = Some(Signal::Call(fun, vec![rhs]));
|
||||
}
|
||||
@@ -318,7 +323,8 @@ impl<'c> Vm<'c> {
|
||||
let lhs = self.pop().unwrap();
|
||||
let fun = {
|
||||
read_obj!(let lhs = lhs);
|
||||
lhs.get_eq().expect("TODO: throw an error for missing __eq__ attr")
|
||||
lhs.get_eq()
|
||||
.expect("TODO: throw an error for missing __eq__ attr")
|
||||
};
|
||||
signal = Some(Signal::Call(fun, vec![rhs]));
|
||||
}
|
||||
@@ -342,7 +348,7 @@ impl<'c> Vm<'c> {
|
||||
.get(&name.index())
|
||||
.cloned()
|
||||
}
|
||||
|
||||
|
||||
fn set_local(&mut self, name: Name, value: ObjRef) {
|
||||
let frame = self
|
||||
.frame_mut()
|
||||
@@ -363,7 +369,8 @@ impl<'c> Vm<'c> {
|
||||
}
|
||||
|
||||
fn set_global(&mut self, name: Name, value: ObjRef) {
|
||||
let frame = self.frames_mut()
|
||||
let frame = self
|
||||
.frames_mut()
|
||||
.first_mut()
|
||||
.expect("global stack frame")
|
||||
.user_frame_mut()
|
||||
|
||||
@@ -6,4 +6,3 @@ pub enum Signal {
|
||||
Call(ObjRef, Vec<ObjRef>),
|
||||
Return,
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user