use smallvec::SmallVec;
use std::fmt;
use std::sync::Arc;
pub type Fields = SmallVec<[Value; 2]>;
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
pub struct GcRef(pub(crate) u32);
#[derive(Clone, Copy, Debug)]
pub enum Value {
Int(i64),
Float(f64),
Bool(bool),
Char(char),
Unit,
Heap(GcRef),
Builtin(u16),
}
#[derive(Debug)]
pub enum HeapObject {
String(String),
Tuple(Fields),
Data {
tag: u16,
fields: Fields,
},
Closure {
proto_idx: usize,
captures: Arc<[Value]>,
},
Bytes(Vec<u8>),
Rng {
state: u64,
inc: u64,
},
Continuation {
saved_frames: Vec<SavedFrame>,
saved_stack: Vec<Value>,
saved_handler: Option<SavedHandler>,
},
}
#[derive(Clone, Debug)]
pub struct SavedHandler {
pub clauses: Vec<(u16, usize)>,
pub proto_idx: usize,
pub captures: Arc<[Value]>,
pub locals_offset: usize, pub handler_count_before: usize, }
#[derive(Clone, Debug)]
pub struct SavedFrame {
pub proto_idx: usize,
pub ip: usize,
pub base_offset: usize,
pub captures: Arc<[Value]>,
}
impl HeapObject {
pub fn for_each_gc_ref(&self, mut f: impl FnMut(GcRef)) {
let visit = |values: &[Value], f: &mut dyn FnMut(GcRef)| {
for v in values {
if let Value::Heap(r) = v {
f(*r);
}
}
};
match self {
HeapObject::String(_) | HeapObject::Bytes(_) | HeapObject::Rng { .. } => {}
HeapObject::Tuple(elems) => visit(elems, &mut f),
HeapObject::Data { fields, .. } => visit(fields, &mut f),
HeapObject::Closure { captures, .. } => visit(captures, &mut f),
HeapObject::Continuation {
saved_stack,
saved_frames,
..
} => {
visit(saved_stack, &mut f);
for frame in saved_frames {
visit(&frame.captures, &mut f);
}
}
}
}
}
pub struct BuiltinEntry {
pub name: &'static str,
pub func: BuiltinFn,
}
pub type BuiltinFn = fn(&[Value], &mut crate::heap::Heap) -> Result<Value, String>;
impl Value {
pub fn is_heap(&self) -> bool {
matches!(self, Value::Heap(_))
}
}
impl fmt::Display for Value {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Value::Int(n) => write!(f, "{n}"),
Value::Float(n) => write!(f, "{n}"),
Value::Bool(b) => write!(f, "{b}"),
Value::Char(c) => write!(f, "{c}"),
Value::Unit => write!(f, "()"),
Value::Heap(_) => write!(f, "<heap>"),
Value::Builtin(id) => write!(f, "<builtin:{id}>"),
}
}
}