silt_lua/
value.rs

1use std::{cell::RefCell, rc::Rc};
2
3use hashbrown::HashMap;
4
5use crate::{
6    error::{ErrorTypes, SiltError},
7    function::{Closure, FunctionObject, NativeObject},
8    lua::Lua,
9    table::Table,
10    token::Operator,
11    userdata::UserData,
12};
13
14/**
15 * Increment self by value and operand type, if increment op fails then use fallback, for instance += would fallback to +
16 * The fallback is used in scenarios where trying to adjust self would change the type, such as an integer to float
17 */
18macro_rules! binary_self_op {
19    ($l:ident, $op:tt, $fallback:tt, $r:ident, $opp:tt) => {
20        {
21            match(&mut *$l, $r){
22                (Value::Number(left), Value::Number(right))  => *left $op right,
23                (Value::Integer(left), Value::Integer(right)) =>*left $op right,
24                (Value::Number(left), Value::Integer(right)) => *left $op (*right as f64),
25                // (Value::Integer(left), Value::Number(right)) => Some(Value::Number((*left as f64) $fallback right)),
26                (Value::Integer(left), Value::Number(right)) =>  *$l= Value::Number((*left as f64) $fallback right),
27                // TODO
28                (ll,rr) => return Err(SiltError::ExpOpValueWithValue(ll.to_error(), Operator::$opp, rr.to_error()))
29            }
30            Ok(())
31        }
32    };
33}
34
35/** Lua value enum representing different data types within a VM */
36pub enum Value {
37    Nil,
38    Integer(i64),
39    Number(f64),
40    Bool(bool),
41    /** true for negative */
42    Infinity(bool),
43    // Bool(bool),
44    // TODO in most cases strings are just copied around on the heap, this is expensive but saves us from using GC here
45    // TODO 2 consider other encoding options for efficiency. Is having a seperate ASCII string type beneficial to only english speakers? how would other speaking languages handle ascii strings without needed glyphs?
46    String(Box<String>),
47    // List(Vec<Value>),
48    // Map(HashMap<String, Value>),
49    Table(Rc<RefCell<Table>>),
50    // Array // TODO lua 5 has an actual array type chosen contextually, how much faster can we make a table by using it?
51    // Boxed()
52    Function(Rc<FunctionObject>), // closure: Environment,
53    Closure(Rc<Closure>),
54    // Func(fn(Vec<Value>) -> Value)
55    NativeFunction(Rc<NativeObject>),
56    UserData(Rc<dyn UserData>),
57}
58
59pub enum ReferneceStore {
60    Table(HashMap<Value, Value>),
61}
62pub struct Reference<T> {
63    pub value: Rc<T>,
64    pub id: usize,
65}
66
67impl std::fmt::Display for Value {
68    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
69        match self {
70            Value::Integer(i) => write!(f, "{}", i),
71            Value::Number(n) => write!(f, "{}", n),
72            Value::Bool(b) => write!(f, "{}", b),
73            Value::Nil => write!(f, "nil"),
74            Value::String(s) => write!(f, "\"{}\"", s),
75            Value::Infinity(_) => write!(f, "inf"),
76            Value::NativeFunction(_) => write!(f, "native_function"),
77            Value::Closure(c) => write!(f, "=>({})", c.function),
78            Value::Function(ff) => write!(f, "{}", ff),
79            Value::Table(t) => write!(f, "{}", t.borrow().to_string()),
80            Value::UserData(u) => write!(f, "{}", u.to_string()),
81        }
82    }
83}
84
85impl core::fmt::Debug for Value {
86    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
87        write!(f, "{}", self)
88    }
89}
90
91impl Value {
92    /** Condense value into a tiny enum for passing to errors*/
93    pub fn to_error(&self) -> ErrorTypes {
94        match self {
95            Value::Integer(_) => ErrorTypes::Integer,
96            Value::Number(_) => ErrorTypes::Number,
97            Value::Bool(_) => ErrorTypes::Bool,
98            Value::Nil => ErrorTypes::Nil,
99            Value::String(_) => ErrorTypes::String,
100            Value::Infinity(_) => ErrorTypes::Infinity,
101            Value::NativeFunction(_) => ErrorTypes::NativeFunction,
102            Value::Function { .. } => ErrorTypes::Function,
103            Value::Closure(_) => ErrorTypes::Closure,
104            Value::Table(_) => ErrorTypes::Table,
105            Value::UserData(_) => ErrorTypes::UserData,
106        }
107    }
108
109    pub fn force_to_int(&mut self, n: i64) {
110        *self = Value::Integer(n);
111    }
112    pub fn force_to_float(&mut self, n: f64) {
113        *self = Value::Number(n);
114    }
115
116    pub fn increment(&mut self, value: &Value) -> Result<(), SiltError> {
117        binary_self_op!(self, +=,+, value, Add)
118        // match match (&mut *self, value) {
119        //     (Value::Number(left), Value::Number(right)) => {
120        //         *left += right;
121        //         None
122        //     }
123        //     (Value::Integer(left), Value::Number(right)) => {
124        //         Some(Value::Number((*left as f64) + right))
125        //         // self.force_to_float(left as f64 + right);
126        //     }
127
128        //     _ => unreachable!(),
129        // } {
130        //     Some(v) => *self = v,
131        //     None => {}
132        // }
133        // Ok(())
134    }
135}
136
137impl Clone for Value {
138    fn clone(&self) -> Self {
139        match self {
140            Value::Integer(i) => Value::Integer(*i),
141            Value::Number(n) => Value::Number(*n),
142            Value::Bool(b) => Value::Bool(*b),
143            Value::Nil => Value::Nil,
144            Value::String(s) => Value::String(s.clone()),
145            Value::Infinity(b) => Value::Infinity(*b),
146            Value::NativeFunction(f) => Value::NativeFunction(f.clone()),
147            // TODO: implement this
148            Value::Function(r) => Value::Function(Rc::clone(r)),
149            Value::Closure(c) => Value::Closure(Rc::clone(c)),
150            // Value::Table(t) => Value::Table(Reference {
151            //     value: Rc::clone(&t.value),
152            //     id: t.id,
153            // }),
154            Value::Table(t) => Value::Table(Rc::clone(t)),
155            Value::UserData(u) => Value::UserData(Rc::clone(u)),
156        }
157    }
158}
159
160impl PartialEq for Value {
161    fn eq(&self, other: &Self) -> bool {
162        match (self, other) {
163            (Value::Integer(i), Value::Integer(j)) => i == j,
164            (Value::Number(i), Value::Number(j)) => i == j,
165            (Value::Bool(i), Value::Bool(j)) => i == j,
166            (Value::Nil, Value::Nil) => true,
167            (Value::String(i), Value::String(j)) => i == j,
168            (Value::Infinity(i), Value::Infinity(j)) => i == j,
169            (Value::NativeFunction(i), Value::NativeFunction(j)) => {
170                i.function as *const fn(&mut Lua, Vec<Value>) -> Value
171                    == j.function as *const fn(&mut Lua, Vec<Value>) -> Value
172            }
173            (Value::Function(i), Value::Function(j)) => Rc::ptr_eq(i, j),
174            (Value::Table(i), Value::Table(j)) => Rc::ptr_eq(&i, &j),
175            _ => false,
176        }
177    }
178}
179
180impl Default for Value {
181    fn default() -> Self {
182        Value::Nil
183    }
184}
185
186impl core::hash::Hash for Value {
187    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
188        core::mem::discriminant(self).hash(state);
189    }
190}
191
192impl Eq for Value {}
193
194// impl Drop for Value {
195//     fn drop(&mut self) {
196//         println!("dropping value: {}", self);
197//     }
198// }