♻️ refactor: extract value module

main
_ 2023-09-26 14:41:10 -05:00
parent 693efa47bd
commit e12d749c7c
4 changed files with 111 additions and 104 deletions

View File

@ -1,5 +1,6 @@
mod loader;
mod state;
mod value;
#[cfg (test)]
mod tests;

View File

@ -1,6 +1,8 @@
use std::{
collections::BTreeMap,
rc::Rc,
use std::collections::BTreeMap;
use crate::value::{
BogusClosure,
Value,
};
#[derive (Debug, PartialEq)]
@ -65,106 +67,6 @@ pub enum Instruction {
VarArgPrep (i32),
}
#[derive (Clone, Debug, Hash, PartialEq)]
pub struct BogusClosure {
idx: usize,
upvalues: Vec <Value>,
}
#[derive (Clone, Debug, PartialEq)]
pub enum Value {
Nil,
Boolean (bool),
Float (f64),
Integer (i64),
String (Rc <String>),
// These are all bogus, I haven't figured out how to implement
// tables and function pointers yet
BogusArg (Rc <Vec <String>>),
BogusClosure (Rc <BogusClosure>),
BogusEnv (Rc <BTreeMap <String, Value>>),
BogusPrint,
}
impl Default for Value {
fn default () -> Self {
Self::Nil
}
}
impl From <String> for Value {
fn from (x: String) -> Self {
Self::String (x.into ())
}
}
impl From <&str> for Value {
fn from (x: &str) -> Self {
Self::from (String::from (x))
}
}
impl From <i32> for Value {
fn from (x: i32) -> Self {
Self::Integer (i64::try_from (x).unwrap ())
}
}
impl From <f64> for Value {
fn from (x: f64) -> Self {
Self::Float (x)
}
}
impl std::hash::Hash for Value {
fn hash <H: std::hash::Hasher> (&self, state: &mut H) {
// Per https://doc.rust-lang.org/std/hash/trait.Hash.html#prefix-collisions
[0xff].hash (state);
match self {
// TODO: Weaken to a Lua error
Self::Nil => panic! ("can't hash a nil value"),
Self::Boolean (x) => x.hash (state),
Self::Float (x) => x.to_ne_bytes ().hash (state),
Self::Integer (x) => x.hash (state),
Self::String (x) => x.as_ptr ().hash (state),
Self::BogusArg (_) => panic! ("can't hash Bogus values"),
Self::BogusClosure (_) => panic! ("can't hash Bogus values"),
Self::BogusEnv (_) => panic! ("can't hash Bogus values"),
Self::BogusPrint => panic! ("can't hash Bogus values"),
}
}
}
impl Value {
fn as_float (&self) -> Option <f64> {
match self {
Self::Float (x) => Some (*x),
// FloatToInt isn't stable yet, so only ints in i32 space can practically be used for now
Self::Integer (x) => f64::try_from (i32::try_from (*x).ok ()?).ok (),
_ => None,
}
}
fn is_truthy (&self) -> bool {
// And this is something Lua does better than JS and Python.
match self {
Value::Nil => false,
Value::Boolean (false) => false,
_ => true,
}
}
fn take (&mut self) -> Self {
let mut x = Value::Nil;
std::mem::swap (self, &mut x);
x
}
}
pub struct Block {
pub instructions: Vec <Instruction>,
pub constants: Vec <Value>,

View File

@ -222,7 +222,7 @@ fn value_size () {
let expected = 16;
assert! (sz <= expected, "{sz} > {expected}");
let sz = size_of::<crate::state::Value> ();
let sz = size_of::<crate::value::Value> ();
let expected = 16;
assert! (sz <= expected, "{sz} > {expected}");
}

104
src/value.rs Normal file
View File

@ -0,0 +1,104 @@
use std::{
collections::BTreeMap,
rc::Rc,
};
#[derive (Clone, Debug, Hash, PartialEq)]
pub struct BogusClosure {
pub idx: usize,
pub upvalues: Vec <Value>,
}
#[derive (Clone, Debug, PartialEq)]
pub enum Value {
Nil,
Boolean (bool),
Float (f64),
Integer (i64),
String (Rc <String>),
// These are all bogus, I haven't figured out how to implement
// tables and function pointers yet
BogusArg (Rc <Vec <String>>),
BogusClosure (Rc <BogusClosure>),
BogusEnv (Rc <BTreeMap <String, Value>>),
BogusPrint,
}
impl Default for Value {
fn default () -> Self {
Self::Nil
}
}
impl From <String> for Value {
fn from (x: String) -> Self {
Self::String (x.into ())
}
}
impl From <&str> for Value {
fn from (x: &str) -> Self {
Self::from (String::from (x))
}
}
impl From <i32> for Value {
fn from (x: i32) -> Self {
Self::Integer (i64::try_from (x).unwrap ())
}
}
impl From <f64> for Value {
fn from (x: f64) -> Self {
Self::Float (x)
}
}
impl std::hash::Hash for Value {
fn hash <H: std::hash::Hasher> (&self, state: &mut H) {
// Per https://doc.rust-lang.org/std/hash/trait.Hash.html#prefix-collisions
[0xff].hash (state);
match self {
// TODO: Weaken to a Lua error
Self::Nil => panic! ("can't hash a nil value"),
Self::Boolean (x) => x.hash (state),
Self::Float (x) => x.to_ne_bytes ().hash (state),
Self::Integer (x) => x.hash (state),
Self::String (x) => x.as_ptr ().hash (state),
Self::BogusArg (_) => panic! ("can't hash Bogus values"),
Self::BogusClosure (_) => panic! ("can't hash Bogus values"),
Self::BogusEnv (_) => panic! ("can't hash Bogus values"),
Self::BogusPrint => panic! ("can't hash Bogus values"),
}
}
}
impl Value {
pub fn as_float (&self) -> Option <f64> {
match self {
Self::Float (x) => Some (*x),
// FloatToInt isn't stable yet, so only ints in i32 space can practically be used for now
Self::Integer (x) => f64::try_from (i32::try_from (*x).ok ()?).ok (),
_ => None,
}
}
pub fn is_truthy (&self) -> bool {
// And this is something Lua does better than JS and Python.
match self {
Value::Nil => false,
Value::Boolean (false) => false,
_ => true,
}
}
pub fn take (&mut self) -> Self {
let mut x = Value::Nil;
std::mem::swap (self, &mut x);
x
}
}