♻️ refactor: extract value module
parent
693efa47bd
commit
e12d749c7c
|
@ -1,5 +1,6 @@
|
||||||
mod loader;
|
mod loader;
|
||||||
mod state;
|
mod state;
|
||||||
|
mod value;
|
||||||
|
|
||||||
#[cfg (test)]
|
#[cfg (test)]
|
||||||
mod tests;
|
mod tests;
|
||||||
|
|
108
src/state.rs
108
src/state.rs
|
@ -1,6 +1,8 @@
|
||||||
use std::{
|
use std::collections::BTreeMap;
|
||||||
collections::BTreeMap,
|
|
||||||
rc::Rc,
|
use crate::value::{
|
||||||
|
BogusClosure,
|
||||||
|
Value,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive (Debug, PartialEq)]
|
#[derive (Debug, PartialEq)]
|
||||||
|
@ -65,106 +67,6 @@ pub enum Instruction {
|
||||||
VarArgPrep (i32),
|
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 struct Block {
|
||||||
pub instructions: Vec <Instruction>,
|
pub instructions: Vec <Instruction>,
|
||||||
pub constants: Vec <Value>,
|
pub constants: Vec <Value>,
|
||||||
|
|
|
@ -222,7 +222,7 @@ fn value_size () {
|
||||||
let expected = 16;
|
let expected = 16;
|
||||||
assert! (sz <= expected, "{sz} > {expected}");
|
assert! (sz <= expected, "{sz} > {expected}");
|
||||||
|
|
||||||
let sz = size_of::<crate::state::Value> ();
|
let sz = size_of::<crate::value::Value> ();
|
||||||
let expected = 16;
|
let expected = 16;
|
||||||
assert! (sz <= expected, "{sz} > {expected}");
|
assert! (sz <= expected, "{sz} > {expected}");
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue