Files
sybil/src/vm/builtins.rs

137 lines
4.6 KiB
Rust
Raw Normal View History

use crate::object::{BuiltinExit, Obj, StrObj};
use crate::vm::{error::RuntimeError, machine::MachineBuilder};
impl MachineBuilder {
/// Registers all builtins for calling on the machine.
pub(super) fn register_builtins(&mut self) {
self.scope_stack.push_scope();
//
// panic
//
self.register_builtin_fun("panic", |machine, _| {
println!("!!! panic");
println!("!!! top of stack");
for (i, value) in machine.stack().iter().enumerate().rev() {
println!("!!! {}. {:?}", i, value);
}
println!("!!! bottom of stack");
panic!();
});
/*
//
// if
//
self.register_builtin_fun("if", |machine, _| {
let if_false = machine.stack_pop()?;
let if_true = machine.stack_pop()?;
let condition = machine.stack_pop()?;
let value = if condition.is_truthy() {
if_true
} else {
if_false
};
if let Value::Quote(quote) = value {
Ok(BuiltinExit::Call(quote))
} else {
return Err(RuntimeError::CannotCall(
"if statement requires quote value".to_string(),
)
.into());
}
});
*/
//
// print
//
self.register_builtin_fun("print", |machine, reentry| {
const CALL_STR: usize = 1;
if reentry == 0 {
let obj = machine
.stack_peek()
.ok_or_else(|| RuntimeError::StackUnderflow)?;
// Push the value's __str__ value, call it, and then print it.
let str_fun = obj
.get("__str__")
.ok_or_else(|| RuntimeError::UnsetWord("__str__".to_string()))?;
let call_site = machine.call_stack().last().unwrap().call_site().cloned();
str_fun.call(call_site, machine)?;
Ok(BuiltinExit::Resume(CALL_STR))
} else if reentry == CALL_STR {
let obj_ptr = machine.stack_pop()?;
let str_obj: &(dyn Obj + 'static) = &*obj_ptr;
if let Some(string) = str_obj.as_any().downcast_ref::<StrObj>() {
print!("{}", string.value());
Ok(BuiltinExit::Return)
} else {
panic!(
"expected StrObj from __str__ function but got {:?} instead",
str_obj
);
}
} else {
unreachable!()
}
});
//
// println
//
self.register_builtin_fun("println", |machine, reentry| {
const CALL_STR: usize = 1;
if reentry == 0 {
let obj = machine
.stack_peek()
.ok_or_else(|| RuntimeError::StackUnderflow)?;
// Push the value's __str__ value, call it, and then print it.
let str_fun = obj
.get("__str__")
.ok_or_else(|| RuntimeError::UnsetWord("__str__".to_string()))?;
let call_site = machine.call_stack().last().unwrap().call_site().cloned();
str_fun.call(call_site, machine)?;
Ok(BuiltinExit::Resume(CALL_STR))
} else if reentry == CALL_STR {
let obj_ptr = machine.stack_pop()?;
let str_obj: &(dyn Obj + 'static) = &*obj_ptr;
if let Some(string) = str_obj.as_any().downcast_ref::<StrObj>() {
println!("{}", string.value());
Ok(BuiltinExit::Return)
} else {
panic!(
"expected StrObj from __str__ function but got {:?} instead",
str_obj
);
}
} else {
unreachable!()
}
});
/*
//
// ==
//
self.register_builtin_fun("==", |machine, _| {
let rhs = machine.stack_pop()?;
let lhs = machine.stack_pop()?;
machine.stack_push(Value::Int((lhs == rhs) as Int))?;
Ok(BuiltinExit::Return)
});
//
// ~=
//
self.register_builtin_fun("~=", |machine, _| {
let rhs = machine.stack_pop()?;
let lhs = machine.stack_pop()?;
machine.stack_push(Value::Int((lhs != rhs) as Int))?;
Ok(BuiltinExit::Return)
});
*/
}
}