aboutsummaryrefslogtreecommitdiff
path: root/crates/sloth_vm/src/lib.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/sloth_vm/src/lib.rs')
-rw-r--r--crates/sloth_vm/src/lib.rs146
1 files changed, 135 insertions, 11 deletions
diff --git a/crates/sloth_vm/src/lib.rs b/crates/sloth_vm/src/lib.rs
index 1dfb191..295827d 100644
--- a/crates/sloth_vm/src/lib.rs
+++ b/crates/sloth_vm/src/lib.rs
@@ -7,24 +7,148 @@
unused_lifetimes
)]
-const STACK_SIZE: usize = 1024;
+pub mod native;
+pub mod sloth_std;
+pub mod value;
+pub mod vm;
+
+use std::ops::{Index, IndexMut};
+
+use value::{Object, ObjectType};
+
+use crate::value::Primitive;
+pub use crate::vm::VM;
pub struct Chunk {
+ constants: Vec<Primitive>,
code: Vec<u8>,
- constants: Vec<u64>,
}
-pub struct VM {
- stack: [u8; STACK_SIZE],
- constants: Vec<u8>,
+const STACK_SIZE: usize = 1024;
+
+#[derive(Debug)]
+pub struct Stack {
+ stack: [Primitive; STACK_SIZE],
+ top: usize,
+}
+
+impl Default for Stack {
+ fn default() -> Self {
+ Self {
+ top: Default::default(),
+ stack: [Primitive::Empty; STACK_SIZE],
+ }
+ }
}
-impl VM {
- //
+impl Stack {
+ #[inline(always)]
+ pub fn push(&mut self, value: Primitive) {
+ if self.top >= STACK_SIZE {
+ panic!("Stack overflow");
+ }
+
+ self.stack[self.top] = value;
+ self.top += 1;
+ }
+
+ #[inline(always)]
+ pub fn pop(&mut self) -> Primitive {
+ if self.top == 0 {
+ panic!("Stack underflow");
+ }
+
+ self.top -= 1;
+ self.stack[self.top]
+ }
+
+ #[inline(always)]
+ pub fn pop2(&mut self) -> (Primitive, Primitive) {
+ (self.pop(), self.pop())
+ }
+
+ #[inline(always)]
+ pub fn peek(&self) -> Primitive {
+ self.stack[self.top - 1]
+ }
+
+ #[inline(always)]
+ pub fn peek_nth(&self, nth: usize) -> Primitive {
+ self.stack[self.top - 1 - nth]
+ }
+}
+
+impl Index<usize> for Stack {
+ type Output = Primitive;
+
+ fn index(&self, index: usize) -> &Self::Output {
+ &self.stack[index]
+ }
}
-#[cfg(test)]
-mod tests {
- #[test]
- fn add_program() {}
+impl IndexMut<usize> for Stack {
+ fn index_mut(&mut self, index: usize) -> &mut Self::Output {
+ &mut self.stack[index]
+ }
+}
+
+pub struct ObjectMap {
+ free: usize,
+ heap: Vec<Object>,
+}
+
+impl Default for ObjectMap {
+ fn default() -> Self {
+ Self::with_capacity(32)
+ }
+}
+
+impl From<Vec<Object>> for ObjectMap {
+ fn from(heap: Vec<Object>) -> Self {
+ let mut free = heap.len();
+ for (idx, obj) in heap.iter().enumerate() {
+ if let ObjectType::Free { .. } = obj.typ {
+ free = idx;
+ break;
+ }
+ }
+
+ Self { free, heap }
+ }
+}
+
+impl ObjectMap {
+ pub fn with_capacity(capacity: usize) -> Self {
+ let mut heap = Vec::with_capacity(capacity);
+ for i in 0..capacity {
+ heap.push(Object::new(ObjectType::Free { next: i + 1 }));
+ }
+
+ Self { free: 0, heap }
+ }
+
+ pub fn allocate(&mut self, object: Object) -> usize {
+ let current = self.free;
+ if current >= self.heap.len() {
+ self.heap
+ .push(Object::new(ObjectType::Free { next: current + 1 }))
+ }
+
+ let ObjectType::Free { next } = self.heap[current].typ else {
+ panic!("Allocation failed: Expected free location wasn't free");
+ };
+
+ self.heap[current] = object;
+ self.free = next;
+
+ current
+ }
+
+ pub fn get(&self, idx: usize) -> Option<&Object> {
+ self.heap.get(idx)
+ }
+
+ pub fn get_mut(&mut self, idx: usize) -> Option<&mut Object> {
+ self.heap.get_mut(idx)
+ }
}