From 056fbf7e7dc727d020ba54e439f2b47411c58e76 Mon Sep 17 00:00:00 2001 From: Rose Hogenson Date: Thu, 3 Mar 2022 13:48:19 -0800 Subject: Start the garbage collector. I don't think we finished it, but I wrote this code a while ago and I'm just trying to get it committed. --- bytecode/src/data.rs | 225 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 225 insertions(+) create mode 100644 bytecode/src/data.rs (limited to 'bytecode/src/data.rs') diff --git a/bytecode/src/data.rs b/bytecode/src/data.rs new file mode 100644 index 0000000..9735fa9 --- /dev/null +++ b/bytecode/src/data.rs @@ -0,0 +1,225 @@ +// The data representations of values of different types are given below. +// - Nil is represented as 0. +// - Pointers are 64 bit unsigned (positive) ints which are +// word-aligned, i.e. 0 mod 8. All types not listed below are +// allocated on the heap behind a pointer. +// - Int: +// < 63-bit signed int > 1 +// Ints are a 63 bit int with a 1 in the low bit. +// - Booleans are 2 mod 8: +// - True is 0xA +// - False is 0x2 +// - A char's low 4 bytes are always 0x4, and the high 4 bytes are a +// unicode code point value. +// +// n.b. 6 mod 8 is unused. + +#[derive(PartialEq, Eq, Debug, Hash, Clone, Copy)] +pub struct Pointer(pub usize); + +impl Pointer { + pub fn offset(self, i: i64) -> Self { + let Pointer(u) = self; + if i > 0 { + return Pointer(u + usize::try_from(i).unwrap()); + } + return Pointer(u - usize::try_from(-i).unwrap()); + } +} + +#[derive(PartialEq, Eq, Debug, Clone, Copy)] +pub struct Value(pub u64); + +impl Value { + pub fn is_nil(self) -> bool { + let Value(stack_representation) = self; + return stack_representation == 0; + } + + pub fn is_pointer(self) -> bool { + let Value(stack_representation) = self; + return stack_representation & 0x7 == 0; + } + + pub fn from_pointer(p: Pointer) -> Self { + let Pointer(x) = p; + return Value(u64::try_from(x).unwrap()); + } + + pub fn to_pointer(self) -> Result { + let Value(stack_representation) = self; + if !self.is_pointer() { + return Err(format!("value {:x} is not a pointer", stack_representation)); + } + return Ok(Pointer(usize::try_from(stack_representation).unwrap())); + } + + pub fn is_int(self) -> bool { + let Value(stack_representation) = self; + return stack_representation & 0x1 == 1; + } + + pub fn from_int(i: i64) -> Self { + return Value((i as u64) << 1 | 1); + } + + pub fn to_int(self) -> Result { + let Value(stack_representation) = self; + if !self.is_int() { + return Err(format!("value {:x} is not an int", stack_representation)); + } + return Ok(stack_representation as i64 >> 1); + } + + pub fn is_bool(self) -> bool { + let Value(stack_representation) = self; + return stack_representation == 0xa || stack_representation == 0x2; + } + + pub fn from_bool(b: bool) -> Self { + if b { + return Value(0xa); + } + return Value(0x2); + } + + pub fn to_bool(self) -> Result { + let Value(stack_representation) = self; + if !self.is_bool() { + return Err(format!("value {:x} is not a boolean", stack_representation)); + } + return Ok(stack_representation == 0xa); + } + + pub fn is_char(self) -> bool { + let Value(stack_representation) = self; + return stack_representation & 0x7 == 4; + } + + pub fn from_char(c: char) -> Self { + return Value(u64::from(c) << 32 | 0x4); + } + + pub fn to_char(self) -> Result { + let Value(stack_representation) = self; + if !self.is_char() { + return Err(format!("value {:x} is not a char", stack_representation)); + } + return Ok( + char::from_u32((stack_representation >> 32) as u32).ok_or(format!( + "value {:x} is not a valid char", + stack_representation >> 32 + ))?, + ); + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn is_nil() { + assert_eq!(true, Value(0).is_nil()); + } + + #[test] + fn is_not_nil() { + assert_eq!(false, Value(1).is_nil()); + } + + #[test] + fn is_pointer() { + assert_eq!(true, Value(0xf8).is_pointer()); + } + + #[test] + fn is_not_pointer() { + assert_eq!(false, Value(1).is_pointer()); + } + + #[test] + fn from_pointer() { + assert_eq!(Value(0xf8), Value::from_pointer(Pointer(0xf8))); + } + + #[test] + fn to_pointer() { + assert_eq!(Ok(Pointer(0xf8)), Value(0xf8).to_pointer()); + } + + #[test] + fn is_int() { + assert_eq!(true, Value(1).is_int()); + } + + #[test] + fn is_not_int() { + assert_eq!(false, Value(0).is_int()); + } + + #[test] + fn from_int() { + assert_eq!(Value(0xb), Value::from_int(5)); + } + + #[test] + fn to_int() { + assert_eq!(Ok(5), Value(0xb).to_int()); + } + + #[test] + fn true_is_bool() { + assert_eq!(true, Value(0xa).is_bool()); + } + + #[test] + fn false_is_bool() { + assert_eq!(true, Value(2).is_bool()); + } + + #[test] + fn is_not_bool() { + assert_eq!(false, Value(0).is_bool()); + } + + #[test] + fn true_from_bool() { + assert_eq!(Value(0xa), Value::from_bool(true)); + } + + #[test] + fn false_from_bool() { + assert_eq!(Value(2), Value::from_bool(false)); + } + + #[test] + fn true_to_bool() { + assert_eq!(Ok(true), Value(0xa).to_bool()); + } + + #[test] + fn false_to_bool() { + assert_eq!(Ok(false), Value(2).to_bool()); + } + + #[test] + fn is_char() { + assert_eq!(true, Value(0x6100000004).is_char()); + } + + #[test] + fn is_not_char() { + assert_eq!(false, Value(0).is_char()); + } + + #[test] + fn from_char() { + assert_eq!(Value(0x5800000004), Value::from_char('X')); + } + + #[test] + fn to_char() { + assert_eq!(Ok('😂'), Value(0x1f60200000004).to_char()); + } +} -- cgit v1.3.1