Add internal error handling to VM, plus function arity
* VM is able to handle basic runtime errors although there is no way to catch this in executing code currently * If a function is called with the wrong number of arguments (arity) it will invoke a runtime error. Signed-off-by: Alek Ratzloff <alekratz@gmail.com>
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
use crate::{obj::{reserved::*, prelude::*}, vm::{consts::ConstPool, frame::*, inst::Inst, signal::*, Vm}};
|
||||
use crate::{obj::{reserved::*, prelude::*}, vm::{consts::ConstPool, error::*, frame::*, inst::Inst, signal::*, Vm}};
|
||||
use once_cell::sync::Lazy;
|
||||
use shredder::{GcSafeWrapper, Scan};
|
||||
use std::{fmt::{Debug, Formatter, self}, io::{self, Write}, sync::Arc};
|
||||
@@ -8,7 +8,7 @@ pub type FunLocals = Vec<Sym>;
|
||||
/// A function object which can create a new stack frame.
|
||||
pub trait Fun {
|
||||
/// Creates a new `vm::Frame` from this function object.
|
||||
fn create_frame(&self, callee: ObjRef, vm: &Vm, _args: Vec<ObjRef>) -> Frame;
|
||||
fn create_frame(&self, callee: ObjRef, vm: &Vm, _args: Vec<ObjRef>) -> Result<Frame>;
|
||||
}
|
||||
|
||||
pub type MethodRef = ObjRef<Method>;
|
||||
@@ -55,7 +55,7 @@ impl Obj for Method {
|
||||
}
|
||||
|
||||
impl Fun for Method {
|
||||
fn create_frame(&self, _callee: ObjRef, vm: &Vm, mut args: Vec<ObjRef>) -> Frame {
|
||||
fn create_frame(&self, _callee: ObjRef, vm: &Vm, mut args: Vec<ObjRef>) -> Result<Frame> {
|
||||
// insert self argument
|
||||
args.insert(0, self.get_attr(SELF_MEMBER_NAME.sym).unwrap());
|
||||
// get function and use its create_frame method with the updated args
|
||||
@@ -82,16 +82,18 @@ pub struct UserFun {
|
||||
// Safe because this is just an interner that points to symbols, which aren't GC'd
|
||||
#[shredder(unsafe_skip)]
|
||||
locals: FunLocals,
|
||||
arity: usize,
|
||||
}
|
||||
|
||||
impl UserFun {
|
||||
pub fn new_obj(code: Vec<Inst>, locals: FunLocals) -> UserFunRef {
|
||||
pub fn new_obj(code: Vec<Inst>, locals: FunLocals, arity: usize) -> UserFunRef {
|
||||
self_referring_obj! (
|
||||
Self {
|
||||
vtable: Default::default(), // this is a placeholder for the real vtable
|
||||
attrs: Default::default(),
|
||||
code: Arc::new(code),
|
||||
locals,
|
||||
arity,
|
||||
},
|
||||
vtable: |obj_ref: ObjRef| vtable! {
|
||||
TY_MEMBER_NAME.sym => USER_FUN_TY.clone(),
|
||||
@@ -215,13 +217,19 @@ impl Obj for UserFun {
|
||||
}
|
||||
|
||||
impl Fun for UserFun {
|
||||
fn create_frame(&self, callee: ObjRef, vm: &Vm, args: Vec<ObjRef>) -> Frame {
|
||||
fn create_frame(&self, callee: ObjRef, vm: &Vm, args: Vec<ObjRef>) -> Result<Frame> {
|
||||
if args.len() != self.arity {
|
||||
return Err(Error::ArityError {
|
||||
expected: self.arity,
|
||||
got: args.len(),
|
||||
});
|
||||
}
|
||||
let bindings: FrameBindings = args.into_iter()
|
||||
.enumerate()
|
||||
.collect();
|
||||
Frame::User(
|
||||
Ok(Frame::User(
|
||||
UserFrame::new(callee, bindings, vm.pc(), Arc::clone(&self.code))
|
||||
)
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -241,7 +249,7 @@ pub static USER_FUN_TY: Lazy<ObjRef<Ty>> = Lazy::new(|| Ty::new_obj(USER_FUN_NAM
|
||||
// struct NativeFun
|
||||
//
|
||||
|
||||
pub type NativeFunPtr = fn(ObjRef, &mut Vm, Vec<ObjRef>) -> Signal;
|
||||
pub type NativeFunPtr = fn(ObjRef, &mut Vm, Vec<ObjRef>) -> Result<Signal>;
|
||||
pub type NativeFunRef = ObjRef<NativeFun>;
|
||||
|
||||
#[derive(Scan)]
|
||||
@@ -250,6 +258,7 @@ pub struct NativeFun {
|
||||
attrs: Attrs,
|
||||
#[shredder(skip)]
|
||||
fun: GcSafeWrapper<NativeFunPtr>,
|
||||
arity: usize,
|
||||
}
|
||||
|
||||
//
|
||||
@@ -257,12 +266,13 @@ pub struct NativeFun {
|
||||
//
|
||||
|
||||
impl NativeFun {
|
||||
pub fn new_obj(fun: NativeFunPtr) -> ObjRef<Self> {
|
||||
pub fn new_obj(arity: usize, fun: NativeFunPtr) -> ObjRef<Self> {
|
||||
self_referring_obj! (
|
||||
Self {
|
||||
vtable: Default::default(),
|
||||
attrs: Default::default(),
|
||||
fun: GcSafeWrapper::new(fun),
|
||||
arity,
|
||||
},
|
||||
vtable: |obj_ref: ObjRef| vtable! {
|
||||
TY_MEMBER_NAME.sym => NATIVE_FUN_TY.clone(),
|
||||
@@ -313,10 +323,16 @@ impl Obj for NativeFun {
|
||||
}
|
||||
|
||||
impl Fun for NativeFun {
|
||||
fn create_frame(&self, callee: ObjRef, _vm: &Vm, args: Vec<ObjRef>) -> Frame {
|
||||
Frame::Native(
|
||||
fn create_frame(&self, callee: ObjRef, _vm: &Vm, args: Vec<ObjRef>) -> Result<Frame> {
|
||||
if args.len() != self.arity {
|
||||
return Err(Error::ArityError {
|
||||
expected: self.arity,
|
||||
got: args.len(),
|
||||
});
|
||||
}
|
||||
Ok(Frame::Native(
|
||||
NativeFrame::new(callee, *self.fun, args)
|
||||
)
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user