aboutsummaryrefslogtreecommitdiff
path: root/crates/sloth_vm/src/vm.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/sloth_vm/src/vm.rs')
-rw-r--r--crates/sloth_vm/src/vm.rs104
1 files changed, 95 insertions, 9 deletions
diff --git a/crates/sloth_vm/src/vm.rs b/crates/sloth_vm/src/vm.rs
index 300e22e..2d58c3d 100644
--- a/crates/sloth_vm/src/vm.rs
+++ b/crates/sloth_vm/src/vm.rs
@@ -3,7 +3,7 @@ use std::mem::MaybeUninit;
use sloth_bytecode::Opcode;
use crate::value::{Function, Object, ObjectType, Primitive};
-use crate::{ObjectMap, Stack};
+use crate::{native, ObjectMap, Stack};
#[derive(Clone, Copy)]
pub struct CallFrame {
@@ -238,18 +238,47 @@ impl VM {
while self.step() {}
}
- fn call(&mut self, ptr: usize) {
+ pub fn call(&mut self, ptr: usize) {
let Some(obj) = self.objects.get(ptr) else {
panic!("Pointer referenced nothing");
};
- let ObjectType::Function(function) = &obj.typ else {
- panic!("Object was not a function");
- };
+ match &obj.typ {
+ ObjectType::Function(function) => {
+ // Add a callstack entry for the function
+ let offset = self.stack.top - (function.arity as usize);
+ self.call_stack.push(CallFrame::new(offset, function));
+ }
+ ObjectType::NativeFunction(function) => {
+ let mut args = Vec::with_capacity(function.arity as usize);
+ for _ in 0..function.arity {
+ args.push(self.stack.pop());
+ }
- // Add a callstack entry for the function
- let offset = self.stack.top - (function.arity as usize);
- self.call_stack.push(CallFrame::new(offset, function));
+ let name = function.name;
+ let returns_value = function.returns_value;
+
+ let internal = function.function;
+ let result = internal(self, &args);
+
+ match result {
+ Ok(value) => {
+ if returns_value {
+ self.stack.push(value);
+ }
+ }
+ Err(error) => match error {
+ native::Error::InvalidArgument => {
+ panic!("Invalid argument provided to '{name}'");
+ }
+ native::Error::Unknown(msg) => {
+ panic!("Native function '{name}' failed due to '{msg}'");
+ }
+ },
+ }
+ }
+ _ => panic!("Object was not a function"),
+ }
}
fn call_return(&mut self) {
@@ -295,12 +324,22 @@ impl VM {
((bytes.0 as u16) << 8) + (bytes.1 as u16)
}
+
+ #[inline(always)]
+ pub fn objects(&self) -> &ObjectMap {
+ &self.objects
+ }
+
+ #[inline(always)]
+ pub fn objects_mut(&mut self) -> &mut ObjectMap {
+ &mut self.objects
+ }
}
#[cfg(test)]
mod tests {
use crate::value::{Function, Object, ObjectType, Primitive};
- use crate::{Chunk, ObjectMap, VM};
+ use crate::{sloth_std, Chunk, ObjectMap, VM};
#[test]
fn arithmetic_ops() {
@@ -355,6 +394,8 @@ mod tests {
Primitive::Integer(6),
Primitive::Integer(3),
Primitive::Object(0),
+ Primitive::Object(1),
+ Primitive::Object(2),
],
code: vec![
0x00, 0, 0, // Load first function parameter from 0
@@ -371,6 +412,51 @@ mod tests {
}
#[test]
+ fn native_function() {
+ let mut vm = VM::new(
+ ObjectMap::from(vec![
+ Object::new(ObjectType::NativeFunction(sloth_std::rand::GEN_FUNCTION)),
+ Object::new(ObjectType::NativeFunction(
+ sloth_std::rand::GEN_RANGE_FUNCTION,
+ )),
+ ]),
+ Function::root(Chunk {
+ constants: vec![
+ Primitive::Object(0),
+ Primitive::Object(1),
+ Primitive::Integer(5),
+ Primitive::Integer(10),
+ ],
+ code: vec![
+ // First part
+ 0x00, 0, 0, //
+ 0x50, //
+ 0xE0, //
+ // Second part
+ 0x00, 0, 3, //
+ 0x00, 0, 2, //
+ 0x00, 0, 1, //
+ 0x50, //
+ ],
+ }),
+ );
+
+ vm.run();
+
+ assert!({
+ let Primitive::Float(i) = vm.stack.peek() else { panic!(); };
+ (0.0..=1.0).contains(&i)
+ });
+
+ vm.run();
+
+ assert!({
+ let Primitive::Integer(i) = vm.stack.peek() else { panic!(); };
+ (5..10).contains(&i)
+ });
+ }
+
+ #[test]
fn fibonacci() {
#[rustfmt::skip]
let mut vm = VM::new(