Add a couple of builtin functions, and the Vm::call() method

* Builtin functions print and println have been added
* If a global lookup fails, the VM will attempt to look up a builtin
* Vm::call(fun, args) allows interrupting the current execution state
  and starting a new function instead. It will return the value left on
  top of the stack.

Signed-off-by: Alek Ratzloff <alekratz@gmail.com>
This commit is contained in:
2020-10-07 17:21:01 -07:00
parent 76d0e6723f
commit 16063d50f8
6 changed files with 81 additions and 5 deletions

View File

@@ -93,6 +93,10 @@ impl NativeFrame {
&self.fun_ptr
}
pub fn args(&self) -> &Vec<ObjRef> {
&self.args
}
pub fn callee(&self) -> &ObjRef {
&self.callee
}

View File

@@ -1,11 +1,11 @@
pub mod consts;
pub mod error; // TODO : not needed?
pub mod error;
pub mod frame;
pub mod inst;
pub mod signal;
use crate::{
obj::{reserved::*, prelude::*},
obj::{builtin::BUILTIN_OBJS, reserved::*, prelude::*},
vm::{consts::ConstPool, frame::*, inst::*, signal::*},
};
@@ -91,6 +91,13 @@ impl<'c> Vm<'c> {
self.condition = condition;
}
/// Calls a function.
pub fn call(&mut self, fun: ObjRef, args: Vec<ObjRef>) -> ObjRef {
self.handle_signal(Signal::Call(fun, args));
self.resume_until_return();
self.pop().expect("return value")
}
/// Resumes execution of the current program.
pub fn resume(&mut self) {
while !self.frames().is_empty() {
@@ -111,7 +118,8 @@ impl<'c> Vm<'c> {
let signal = match frame {
Frame::Native(fun) => {
let callee = fun.callee().clone();
(*fun.fun_ptr())(callee, self, vec![])
let args = fun.args().clone();
(*fun.fun_ptr())(callee, self, args)
}
Frame::User(_) => {
self.resume_user_fun()
@@ -200,6 +208,7 @@ impl<'c> Vm<'c> {
}
Inst::LoadGlobal(global) => {
let value = self.get_global(global)
.or_else(|| self.get_builtin(global))
.expect("TODO: throw error for missing global");
self.push(value);
}
@@ -332,7 +341,7 @@ impl<'c> Vm<'c> {
}
fn get_global(&self, name: Name) -> Option<ObjRef> {
self.frames
self.frames()
.first()?
.user_frame()?
.bindings()
@@ -349,4 +358,15 @@ impl<'c> Vm<'c> {
let bindings = frame.bindings_mut();
bindings.insert(name.index(), value);
}
fn get_builtin(&self, name: Name) -> Option<ObjRef> {
read_obj!(let fun = self.frames()
.first()?
.user_frame()?
.callee()
);
let fun: &UserFun = std::any::Any::downcast_ref(fun.as_any()).unwrap();
let sym = fun.locals()[name.index()];
BUILTIN_OBJS.get(&sym).cloned()
}
}