105 lines
2.2 KiB
Rust
105 lines
2.2 KiB
Rust
|
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
|
||
|
}
|
||
|
}
|