Add parser, vm, objects
Big ol thing. You should check it out sometime Signed-off-by: Alek Ratzloff <alekratz@gmail.com>
This commit is contained in:
198
src/object.rs
198
src/object.rs
@@ -1,36 +1,58 @@
|
||||
// TODO - remove this at some point.
|
||||
// I haven't gotten around to testing or working with this API yet and I don't
|
||||
// want it to clog the warnings yet.
|
||||
#![allow(dead_code)]
|
||||
|
||||
use crate::syn::ast::SpExpr;
|
||||
use std::cell::RefCell;
|
||||
use std::collections::{BTreeMap, HashMap, VecDeque};
|
||||
use std::collections::{BTreeMap, HashMap};
|
||||
use std::rc::{Rc, Weak};
|
||||
|
||||
pub type Str = String;
|
||||
pub type Int = i64;
|
||||
pub type Float = f64;
|
||||
pub type VTable = HashMap<String, Value>;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum Value {
|
||||
Array(Vec<Value>),
|
||||
Float(Float),
|
||||
Int(Int),
|
||||
Str(String),
|
||||
Obj(ObjPtr),
|
||||
Str(Str),
|
||||
Quote(Vec<SpExpr>),
|
||||
ObjPtr(ObjPtr),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct ObjPtr {
|
||||
arena: Weak<Arena>,
|
||||
arena: Weak<RefCell<Arena>>,
|
||||
slot: usize,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, Default)]
|
||||
pub struct Obj {
|
||||
vtable: HashMap<String, Value>,
|
||||
vtable: VTable,
|
||||
}
|
||||
|
||||
impl Obj {
|
||||
pub fn new(vtable: VTable) -> Self {
|
||||
Self { vtable }
|
||||
}
|
||||
|
||||
pub fn vtable(&self) -> &VTable {
|
||||
&self.vtable
|
||||
}
|
||||
|
||||
pub fn vtable_mut(&mut self) -> &mut VTable {
|
||||
&mut self.vtable
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Arena {
|
||||
slots: Vec<SlotRange>,
|
||||
slots_dirty: bool,
|
||||
objects: BTreeMap<usize, RefCell<Obj>>,
|
||||
objects: BTreeMap<usize, Obj>,
|
||||
max_size: Option<usize>,
|
||||
}
|
||||
|
||||
@@ -76,19 +98,26 @@ impl Arena {
|
||||
}
|
||||
}
|
||||
self.slots = slots;
|
||||
// Make sure to indicate that slots available are not dirty.
|
||||
self.slots_dirty = false;
|
||||
}
|
||||
|
||||
pub fn obj_new(self: &mut Rc<Self>, obj: Obj) -> Option<ObjPtr> {
|
||||
/// Creates a shared pointer for an Obj value, using the next available slot.
|
||||
///
|
||||
/// If no slot is available, None is returned.
|
||||
pub fn alloc_obj(self_rc: &Rc<RefCell<Self>>, obj: Obj) -> Option<ObjPtr> {
|
||||
use SlotRange::*;
|
||||
|
||||
let mut self_mut = self_rc
|
||||
.try_borrow_mut()
|
||||
.expect("could not get arena mutably from Rc pointer");
|
||||
// Compress if necessary
|
||||
if !self.slots_dirty {
|
||||
let self_mut = Rc::get_mut(self).expect("could not get arena mutably from Rc pointer");
|
||||
if self_mut.slots_dirty {
|
||||
self_mut.compress_slots();
|
||||
}
|
||||
if self
|
||||
if self_mut
|
||||
.max_size
|
||||
.map(|max_size| self.objects.len() >= max_size)
|
||||
.map(|max_size| self_mut.objects.len() >= max_size)
|
||||
.unwrap_or(false)
|
||||
{
|
||||
// TODO : return err instead of option
|
||||
@@ -97,7 +126,6 @@ impl Arena {
|
||||
}
|
||||
|
||||
// Get the next slot
|
||||
let self_mut = Rc::get_mut(self).expect("could not get arena mutably from Rc pointer");
|
||||
let slots = &mut self_mut.slots;
|
||||
let slot = match slots.first().copied().unwrap() {
|
||||
Range(start, end) => {
|
||||
@@ -113,68 +141,42 @@ impl Arena {
|
||||
index
|
||||
}
|
||||
};
|
||||
let previous = self_mut.objects.insert(slot, obj);
|
||||
assert!(
|
||||
previous.is_none(),
|
||||
"slot {} was allocated but is already in use",
|
||||
slot
|
||||
);
|
||||
Some(ObjPtr {
|
||||
arena: Rc::downgrade(self),
|
||||
arena: Rc::downgrade(self_rc),
|
||||
slot,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn free_obj(&mut self, obj_ptr: ObjPtr) {
|
||||
// Compress if necessary
|
||||
if !self.slots_dirty {
|
||||
if self.slots_dirty {
|
||||
self.compress_slots();
|
||||
}
|
||||
let value = self.objects.remove(&obj_ptr.slot);
|
||||
assert!(
|
||||
value.is_some(),
|
||||
"attempted to free object that was not tracked (slot {})",
|
||||
obj_ptr.slot
|
||||
);
|
||||
self.slots
|
||||
.push(SlotRange::Range(obj_ptr.slot, obj_ptr.slot));
|
||||
self.slots_dirty = true; // not my problem
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_arena_compress_slots() {
|
||||
use SlotRange::*;
|
||||
let tests = [
|
||||
(vec![Range(0, 4), Range(2, 6), Open(0)], vec![Open(0)]),
|
||||
(vec![Open(7), Range(0, 4), Range(2, 6)], vec![Open(0)]),
|
||||
(
|
||||
vec![Open(8), Range(0, 4), Range(2, 6)],
|
||||
vec![Range(0, 6), Open(8)],
|
||||
),
|
||||
(vec![Range(0, 4), Range(2, 6)], vec![Range(0, 6)]),
|
||||
(vec![Range(0, 4), Range(2, 6)], vec![Range(0, 6)]),
|
||||
(
|
||||
vec![Range(0, 1), Range(2, 2), Range(3, 4)],
|
||||
vec![Range(0, 4)],
|
||||
),
|
||||
(
|
||||
vec![Range(0, 4), Range(3, 4), Range(2, 2)],
|
||||
vec![Range(0, 4)],
|
||||
),
|
||||
(
|
||||
vec![Range(3, 6), Range(0, 4), Range(2, 2)],
|
||||
vec![Range(0, 6)],
|
||||
),
|
||||
(vec![Range(0, 6), Range(6, 6)], vec![Range(0, 6)]),
|
||||
(vec![Range(7, 6), Range(6, 6)], vec![Range(6, 6)]),
|
||||
];
|
||||
|
||||
for (slots, expected) in tests {
|
||||
let mut arena = Arena {
|
||||
slots,
|
||||
slots_dirty: true,
|
||||
objects: Default::default(),
|
||||
max_size: None,
|
||||
};
|
||||
arena.compress_slots();
|
||||
assert_eq!(arena.slots, expected);
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum SlotRange {
|
||||
/// A list of slots that are in a range, inclusive.
|
||||
/// A list of slots that are in a range, exclusive.
|
||||
///
|
||||
/// If the range start and end are equal, then it is a single opening.
|
||||
Range(usize, usize),
|
||||
/// Everything from here and onward is open
|
||||
/// Everything from here and onward is open.
|
||||
Open(usize),
|
||||
}
|
||||
|
||||
@@ -243,3 +245,85 @@ fn test_slot_range_merge() {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_arena_compress_slots() {
|
||||
use SlotRange::*;
|
||||
let tests = [
|
||||
(vec![Range(0, 4), Range(2, 6), Open(0)], vec![Open(0)]),
|
||||
(vec![Open(7), Range(0, 4), Range(2, 6)], vec![Open(0)]),
|
||||
(
|
||||
vec![Open(8), Range(0, 4), Range(2, 6)],
|
||||
vec![Range(0, 6), Open(8)],
|
||||
),
|
||||
(vec![Range(0, 4), Range(2, 6)], vec![Range(0, 6)]),
|
||||
(vec![Range(0, 4), Range(2, 6)], vec![Range(0, 6)]),
|
||||
(
|
||||
vec![Range(0, 1), Range(2, 2), Range(3, 4)],
|
||||
vec![Range(0, 4)],
|
||||
),
|
||||
(
|
||||
vec![Range(0, 4), Range(3, 4), Range(2, 2)],
|
||||
vec![Range(0, 4)],
|
||||
),
|
||||
(
|
||||
vec![Range(3, 6), Range(0, 4), Range(2, 2)],
|
||||
vec![Range(0, 6)],
|
||||
),
|
||||
(vec![Range(0, 6), Range(6, 6)], vec![Range(0, 6)]),
|
||||
(vec![Range(7, 6), Range(6, 6)], vec![Range(6, 6)]),
|
||||
(
|
||||
vec![Range(0, 0), Range(1, 1), Range(2, 2)],
|
||||
vec![Range(0, 2)],
|
||||
),
|
||||
(
|
||||
vec![Range(0, 0), Range(1, 1), Range(2, 2), Open(3)],
|
||||
vec![Open(0)],
|
||||
),
|
||||
];
|
||||
|
||||
for (slots, expected) in tests {
|
||||
let mut arena = Arena {
|
||||
slots,
|
||||
slots_dirty: true,
|
||||
objects: Default::default(),
|
||||
max_size: None,
|
||||
};
|
||||
arena.compress_slots();
|
||||
assert_eq!(arena.slots, expected);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_arena_obj_lifetime() {
|
||||
let arena = Rc::new(RefCell::new(Arena::new(None)));
|
||||
|
||||
let p1 = Arena::alloc_obj(&arena, Obj::default()).unwrap();
|
||||
assert_eq!(arena.borrow().slots, vec![SlotRange::Open(1)]);
|
||||
let p2 = Arena::alloc_obj(&arena, Obj::default()).unwrap();
|
||||
assert_eq!(arena.borrow().slots, vec![SlotRange::Open(2)]);
|
||||
let p3 = Arena::alloc_obj(&arena, Obj::default()).unwrap();
|
||||
assert_eq!(arena.borrow().slots, vec![SlotRange::Open(3)]);
|
||||
|
||||
{
|
||||
let mut arena_mut = arena.borrow_mut();
|
||||
arena_mut.free_obj(p2);
|
||||
arena_mut.compress_slots();
|
||||
assert_eq!(
|
||||
arena_mut.slots,
|
||||
vec![SlotRange::Range(1, 1), SlotRange::Open(3)]
|
||||
);
|
||||
}
|
||||
|
||||
let p4 = Arena::alloc_obj(&arena, Obj::default()).unwrap();
|
||||
assert_eq!(arena.borrow().slots, vec![SlotRange::Open(3)]);
|
||||
|
||||
{
|
||||
let mut arena_mut = arena.borrow_mut();
|
||||
arena_mut.free_obj(p1);
|
||||
arena_mut.free_obj(p3);
|
||||
arena_mut.free_obj(p4);
|
||||
arena_mut.compress_slots();
|
||||
assert_eq!(arena_mut.slots, vec![SlotRange::Open(0)],);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user