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:
47
src/obj/builtin.rs
Normal file
47
src/obj/builtin.rs
Normal file
@@ -0,0 +1,47 @@
|
||||
use crate::{obj::{prelude::*, reserved::*}, vm::signal::*};
|
||||
use maplit::btreemap;
|
||||
use once_cell::sync::Lazy;
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
pub static PRINTLN_BUILTIN_FUN: Lazy<NativeFunRef> = Lazy::new(|| NativeFun::new_obj(|_, vm, args| {
|
||||
// TODO : use __get_attr__ when it gets added
|
||||
let to_string = {
|
||||
let obj_ref = &args[0];
|
||||
read_obj!(let obj = obj_ref);
|
||||
obj.get_attr(STR_MEMBER_NAME.sym)
|
||||
.or_else(|| obj.get_attr(REPR_MEMBER_NAME.sym))
|
||||
.expect("no __str__ or __repr__ member")
|
||||
};
|
||||
let return_value = vm.call(to_string, vec![]);
|
||||
let str_ref: &StrRef = std::any::Any::downcast_ref(&return_value).expect("to_string to return str value");
|
||||
{
|
||||
read_obj!(let str_obj = str_ref);
|
||||
println!("{}", str_obj.value());
|
||||
}
|
||||
|
||||
Signal::Return
|
||||
}));
|
||||
|
||||
pub static PRINT_BUILTIN_FUN: Lazy<NativeFunRef> = Lazy::new(|| NativeFun::new_obj(|_, vm, args| {
|
||||
// TODO : use __get_attr__ when it gets added
|
||||
let to_string = {
|
||||
let obj_ref = &args[0];
|
||||
read_obj!(let obj = obj_ref);
|
||||
obj.get_attr(STR_MEMBER_NAME.sym)
|
||||
.or_else(|| obj.get_attr(REPR_MEMBER_NAME.sym))
|
||||
.expect("no __str__ or __repr__ member")
|
||||
};
|
||||
let return_value = vm.call(to_string, vec![]);
|
||||
let str_ref: &StrRef = std::any::Any::downcast_ref(&return_value).expect("to_string to return str value");
|
||||
{
|
||||
read_obj!(let str_obj = str_ref);
|
||||
print!("{}", str_obj.value());
|
||||
}
|
||||
|
||||
Signal::Return
|
||||
}));
|
||||
|
||||
pub static BUILTIN_OBJS: Lazy<BTreeMap<Sym, ObjRef>> = Lazy::new(|| btreemap! {
|
||||
PRINTLN_BUILTIN_NAME.sym => PRINTLN_BUILTIN_FUN.clone() as _,
|
||||
PRINT_BUILTIN_NAME.sym => PRINT_BUILTIN_FUN.clone() as _,
|
||||
});
|
||||
@@ -2,6 +2,7 @@
|
||||
mod macros;
|
||||
|
||||
pub mod attrs;
|
||||
pub mod builtin;
|
||||
pub mod fun;
|
||||
pub mod int;
|
||||
pub mod intern;
|
||||
|
||||
@@ -43,6 +43,8 @@ name!(GET_ATTR_MEMBER_NAME, "__get_attr__");
|
||||
name!(SET_ATTR_MEMBER_NAME, "__set_attr__");
|
||||
name!(SELF_MEMBER_NAME, "__self__");
|
||||
name!(FUNC_MEMBER_NAME, "__func__");
|
||||
name!(STR_MEMBER_NAME, "__str__");
|
||||
name!(REPR_MEMBER_NAME, "__repr__");
|
||||
|
||||
//
|
||||
// Predefined VM-aware symbols
|
||||
@@ -55,6 +57,8 @@ name!(FUNC_MEMBER_NAME, "__func__");
|
||||
//name!(REPR_FUN_NAME, REPR_FUN_SYM, "repr");
|
||||
//name!(GET_LOCAL_FUN_NAME, GET_LOCAL_FUN_SYM, "get_local");
|
||||
//name!(SET_LOCAL_FUN_NAME, SET_LOCAL_FUN_SYM, "set_local");
|
||||
name!(PRINTLN_BUILTIN_NAME, "println");
|
||||
name!(PRINT_BUILTIN_NAME, "print");
|
||||
|
||||
//
|
||||
// Builtin constants
|
||||
|
||||
@@ -166,7 +166,7 @@ fn flatten<T>(head: Result<Vec<T>>, tail: Result<T>) -> Result<Vec<T>> {
|
||||
|
||||
fn parse_string(input: &str) -> String {
|
||||
let mut s = String::new();
|
||||
let input = &input[1..input.bytes().len() - 1];
|
||||
let input = &input[..input.bytes().len() - 1];
|
||||
let mut chars = input.chars();
|
||||
while let Some(c) = chars.next() {
|
||||
if c == '\\' {
|
||||
|
||||
@@ -93,6 +93,10 @@ impl NativeFrame {
|
||||
&self.fun_ptr
|
||||
}
|
||||
|
||||
pub fn args(&self) -> &Vec<ObjRef> {
|
||||
&self.args
|
||||
}
|
||||
|
||||
pub fn callee(&self) -> &ObjRef {
|
||||
&self.callee
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user