Skip to main content

qanglang_core/backend/
value.rs

1use crate::{
2    BoundIntrinsicHandle, BoundMethodHandle, ClassHandle, HashMapHandle, HeapAllocator,
3    InstanceHandle, NativeFunctionHandle,
4    arena::Index,
5    memory::{ArrayHandle, ClosureHandle, FunctionHandle, StringHandle},
6};
7use rustc_hash::FxHasher;
8use std::hash::{Hash, Hasher};
9
10// keywords
11pub const NIL_TYPE_STRING: &str = "nil";
12pub const BOOLEAN_TYPE_STRING: &str = "boolean";
13pub const NUMBER_TYPE_STRING: &str = "number";
14pub const STRING_TYPE_STRING: &str = "string";
15pub const FUNCTION_TYPE_STRING: &str = "function";
16pub const CLASS_TYPE_STRING: &str = "class";
17pub const OBJECT_TYPE_STRING: &str = "object";
18pub const ARRAY_TYPE_STRING: &str = "array";
19pub const MODULE_TYPE_STRING: &str = "module";
20
21const NAN_BASE: u64 = 0x7FF8_0000_0000_0000;
22const TYPE_MASK: u64 = 0x0000_F000_0000_0000; // 4 bits for type
23const PAYLOAD_MASK: u64 = 0x0000_0FFF_FFFF_FFFF; // 44 bits for data
24
25// Type tags (in the high nibble of mantissa)
26const NIL_TAG: u64 = 0x0000_1000_0000_0000;
27const BOOL_TAG: u64 = 0x0000_2000_0000_0000; // +1 for false, +2 for true
28const STRING_TAG: u64 = 0x0000_3000_0000_0000;
29const CLOSURE_TAG: u64 = 0x0000_4000_0000_0000;
30const NATIVE_TAG: u64 = 0x0000_5000_0000_0000;
31const FUNC_TAG: u64 = 0x0000_6000_0000_0000;
32const CLASS_TAG: u64 = 0x0000_7000_0000_0000;
33const INSTANCE_TAG: u64 = 0x0000_8000_0000_0000;
34const BOUND_METHOD_TAG: u64 = 0x0000_9000_0000_0000;
35const BOUND_INTRINSIC_TAG: u64 = 0x0000_A000_0000_0000;
36const ARRAY_TAG: u64 = 0x0000_B000_0000_0000;
37const OBJECT_TAG: u64 = 0x0000_C000_0000_0000;
38const MODULE_TAG: u64 = 0x0000_D000_0000_0000;
39// Tags E and F still available
40
41// Usage
42const NIL_NAN: u64 = NAN_BASE | NIL_TAG | 1;
43const TRUE_NAN: u64 = NAN_BASE | BOOL_TAG | 2;
44const FALSE_NAN: u64 = NAN_BASE | BOOL_TAG | 1;
45
46#[derive(Debug, Clone, Copy, PartialEq)]
47pub enum ValueKind {
48    Nil,
49    True,
50    False,
51    Number(f64),
52    String(u32),
53    Closure(Index),
54    NativeFunction(u32),
55    FunctionDecl(u32),
56    Class(Index),
57    Instance(Index),
58    BoundMethod(Index),
59    BoundIntrinsic(Index),
60    Array(Index),
61    ObjectLiteral(Index),
62    Module(Index),
63}
64
65#[derive(Debug, Clone, Copy)]
66pub struct Value(f64);
67
68impl Value {
69    pub fn nil() -> Self {
70        Self(f64::from_bits(NIL_NAN))
71    }
72
73    pub fn is_nil(&self) -> bool {
74        self.0.to_bits() == NIL_NAN
75    }
76
77    pub fn boolean(value: bool) -> Self {
78        Self(f64::from_bits(if value { TRUE_NAN } else { FALSE_NAN }))
79    }
80
81    pub fn as_boolean(&self) -> Option<bool> {
82        match self.0.to_bits() {
83            TRUE_NAN => Some(true),
84            FALSE_NAN => Some(false),
85            _ => None,
86        }
87    }
88
89    pub fn number(value: f64) -> Self {
90        Self(value)
91    }
92
93    pub fn as_number(&self) -> Option<f64> {
94        if !self.0.is_nan() { Some(self.0) } else { None }
95    }
96
97    pub fn string(handle: StringHandle) -> Self {
98        let bits = NAN_BASE | STRING_TAG | (handle as u64 & PAYLOAD_MASK);
99        Self(f64::from_bits(bits))
100    }
101
102    pub fn as_string(&self) -> Option<StringHandle> {
103        let bits = self.0.to_bits();
104        if bits & TYPE_MASK == STRING_TAG {
105            Some((bits & PAYLOAD_MASK) as u32)
106        } else {
107            None
108        }
109    }
110
111    pub fn function(handle: FunctionHandle) -> Self {
112        let bits = NAN_BASE | FUNC_TAG | (handle as u64 & PAYLOAD_MASK);
113        Self(f64::from_bits(bits))
114    }
115
116    pub fn as_function(&self) -> Option<FunctionHandle> {
117        let bits = self.0.to_bits();
118        if bits & TYPE_MASK == FUNC_TAG {
119            Some((bits & PAYLOAD_MASK) as u32)
120        } else {
121            None
122        }
123    }
124
125    pub fn native_function(handle: NativeFunctionHandle) -> Self {
126        let bits = NAN_BASE | NATIVE_TAG | (handle as u64 & PAYLOAD_MASK);
127        Self(f64::from_bits(bits))
128    }
129
130    pub fn as_native_function(&self) -> Option<NativeFunctionHandle> {
131        let bits = self.0.to_bits();
132        if bits & TYPE_MASK == NATIVE_TAG {
133            Some((bits & PAYLOAD_MASK) as u32)
134        } else {
135            None
136        }
137    }
138
139    pub fn closure(handle: ClosureHandle) -> Self {
140        let packed = handle.pack_for_nan();
141        let bits = NAN_BASE | CLOSURE_TAG | (packed & PAYLOAD_MASK);
142        Self(f64::from_bits(bits))
143    }
144
145    pub fn as_closure(&self) -> Option<ClosureHandle> {
146        let bits = self.0.to_bits();
147        if (bits & TYPE_MASK) == CLOSURE_TAG {
148            let packed = bits & PAYLOAD_MASK;
149            Some(Index::unpack_from_nan(packed))
150        } else {
151            None
152        }
153    }
154
155    pub fn class(handle: ClassHandle) -> Self {
156        let packed = handle.pack_for_nan();
157        let bits = NAN_BASE | CLASS_TAG | (packed & PAYLOAD_MASK);
158        Self(f64::from_bits(bits))
159    }
160
161    pub fn as_class(&self) -> Option<ClassHandle> {
162        let bits = self.0.to_bits();
163        if (bits & TYPE_MASK) == CLASS_TAG {
164            let packed = bits & PAYLOAD_MASK;
165            Some(Index::unpack_from_nan(packed))
166        } else {
167            None
168        }
169    }
170
171    pub fn instance(handle: InstanceHandle) -> Self {
172        let packed = handle.pack_for_nan();
173        let bits = NAN_BASE | INSTANCE_TAG | (packed & PAYLOAD_MASK);
174        Self(f64::from_bits(bits))
175    }
176
177    pub fn as_instance(&self) -> Option<InstanceHandle> {
178        let bits = self.0.to_bits();
179        if (bits & TYPE_MASK) == INSTANCE_TAG {
180            let packed = bits & PAYLOAD_MASK;
181            Some(Index::unpack_from_nan(packed))
182        } else {
183            None
184        }
185    }
186
187    pub fn bound_method(handle: BoundMethodHandle) -> Self {
188        let packed = handle.pack_for_nan();
189        let bits = NAN_BASE | BOUND_METHOD_TAG | (packed & PAYLOAD_MASK);
190        Self(f64::from_bits(bits))
191    }
192
193    pub fn as_bound_method(&self) -> Option<BoundMethodHandle> {
194        let bits = self.0.to_bits();
195        if (bits & TYPE_MASK) == BOUND_METHOD_TAG {
196            let packed = bits & PAYLOAD_MASK;
197            Some(Index::unpack_from_nan(packed))
198        } else {
199            None
200        }
201    }
202
203    pub fn bound_intrinsic(handle: BoundIntrinsicHandle) -> Self {
204        let packed = handle.pack_for_nan();
205        let bits = NAN_BASE | BOUND_INTRINSIC_TAG | (packed & PAYLOAD_MASK);
206        Self(f64::from_bits(bits))
207    }
208
209    pub fn as_bound_intrinsic(&self) -> Option<BoundIntrinsicHandle> {
210        let bits = self.0.to_bits();
211        if (bits & TYPE_MASK) == BOUND_INTRINSIC_TAG {
212            let packed = bits & PAYLOAD_MASK;
213            Some(Index::unpack_from_nan(packed))
214        } else {
215            None
216        }
217    }
218
219    pub fn array(handle: ArrayHandle) -> Self {
220        let packed = handle.pack_for_nan();
221        let bits = NAN_BASE | ARRAY_TAG | (packed & PAYLOAD_MASK);
222        Self(f64::from_bits(bits))
223    }
224
225    pub fn as_array(&self) -> Option<ArrayHandle> {
226        let bits = self.0.to_bits();
227        if (bits & TYPE_MASK) == ARRAY_TAG {
228            let packed = bits & PAYLOAD_MASK;
229            Some(Index::unpack_from_nan(packed))
230        } else {
231            None
232        }
233    }
234
235    pub fn object_literal(handle: HashMapHandle) -> Self {
236        let packed = handle.pack_for_nan();
237        let bits = NAN_BASE | OBJECT_TAG | (packed & PAYLOAD_MASK);
238        Self(f64::from_bits(bits))
239    }
240
241    pub fn as_object_literal(&self) -> Option<HashMapHandle> {
242        let bits = self.0.to_bits();
243        if (bits & TYPE_MASK) == OBJECT_TAG {
244            let packed = bits & PAYLOAD_MASK;
245            Some(Index::unpack_from_nan(packed))
246        } else {
247            None
248        }
249    }
250
251    pub fn module(handle: HashMapHandle) -> Self {
252        let packed = handle.pack_for_nan();
253        let bits = NAN_BASE | MODULE_TAG | (packed & PAYLOAD_MASK);
254        Self(f64::from_bits(bits))
255    }
256
257    pub fn as_module(&self) -> Option<HashMapHandle> {
258        let bits = self.0.to_bits();
259        if (bits & TYPE_MASK) == MODULE_TAG {
260            let packed = bits & PAYLOAD_MASK;
261            Some(Index::unpack_from_nan(packed))
262        } else {
263            None
264        }
265    }
266
267    pub fn kind(self) -> ValueKind {
268        if !self.0.is_nan() {
269            return ValueKind::Number(self.0);
270        }
271
272        let bits = self.0.to_bits();
273        match bits & TYPE_MASK {
274            NIL_TAG => ValueKind::Nil,
275            BOOL_TAG => {
276                let payload = bits & PAYLOAD_MASK;
277                if payload == 2 {
278                    ValueKind::True
279                } else {
280                    ValueKind::False
281                }
282            }
283            STRING_TAG => {
284                let handle = (bits & PAYLOAD_MASK) as u32;
285                ValueKind::String(handle)
286            }
287            FUNC_TAG => {
288                let handle = (bits & PAYLOAD_MASK) as u32;
289                ValueKind::FunctionDecl(handle)
290            }
291            NATIVE_TAG => {
292                let handle = (bits & PAYLOAD_MASK) as u32;
293                ValueKind::NativeFunction(handle)
294            }
295            CLOSURE_TAG => {
296                let packed = bits & PAYLOAD_MASK;
297                let index = Index::unpack_from_nan(packed);
298                ValueKind::Closure(index)
299            }
300            CLASS_TAG => {
301                let packed = bits & PAYLOAD_MASK;
302                let index = Index::unpack_from_nan(packed);
303                ValueKind::Class(index)
304            }
305            INSTANCE_TAG => {
306                let packed = bits & PAYLOAD_MASK;
307                let index = Index::unpack_from_nan(packed);
308                ValueKind::Instance(index)
309            }
310            BOUND_METHOD_TAG => {
311                let packed = bits & PAYLOAD_MASK;
312                let index = Index::unpack_from_nan(packed);
313                ValueKind::BoundMethod(index)
314            }
315            BOUND_INTRINSIC_TAG => {
316                let packed = bits & PAYLOAD_MASK;
317                let index = Index::unpack_from_nan(packed);
318                ValueKind::BoundIntrinsic(index)
319            }
320            ARRAY_TAG => {
321                let packed = bits & PAYLOAD_MASK;
322                let index = Index::unpack_from_nan(packed);
323                ValueKind::Array(index)
324            }
325            OBJECT_TAG => {
326                let packed = bits & PAYLOAD_MASK;
327                let index = Index::unpack_from_nan(packed);
328                ValueKind::ObjectLiteral(index)
329            }
330            MODULE_TAG => {
331                let packed = bits & PAYLOAD_MASK;
332                let index = Index::unpack_from_nan(packed);
333                ValueKind::Module(index)
334            }
335            _ => unreachable!("Invalid NaN pattern"),
336        }
337    }
338
339    pub fn is_truthy(&self) -> bool {
340        match self.as_boolean() {
341            Some(b) => b,
342            None => !self.is_nil(), // Everything except nil and false is truthy
343        }
344    }
345
346    pub fn print(&self, allocator: &HeapAllocator) {
347        print!("{}", self.to_display_string(allocator));
348    }
349
350    pub fn to_display_string(&self, allocator: &HeapAllocator) -> String {
351        match self.kind() {
352            ValueKind::Nil => "nil".to_string(),
353            ValueKind::Number(number) => number.to_string(),
354            ValueKind::String(handle) => allocator.strings.get(handle).to_string(),
355            ValueKind::True => "true".to_string(),
356            ValueKind::False => "false".to_string(),
357            ValueKind::FunctionDecl(function_handle) => {
358                let function = allocator.get_function(function_handle);
359                let identifier = allocator.strings.get(function.name);
360                format!("{}<function>", identifier)
361            }
362            ValueKind::Closure(handle) => {
363                let closure = allocator.closures.get_closure(handle);
364                let function = allocator.get_function(closure.function);
365                let identifier = allocator.strings.get(function.name);
366                format!("{}<function>", identifier)
367            }
368            ValueKind::NativeFunction(handle) => {
369                let function = allocator.get_native_function(handle);
370                let identifier = allocator.strings.get(function.name_handle);
371                format!("{}<function>", identifier)
372            }
373            ValueKind::Class(handle) => {
374                let clazz = allocator.get_class(handle);
375                let identifier = allocator.strings.get(clazz.name);
376                format!("{}<class>", identifier)
377            }
378            ValueKind::Instance(handle) => {
379                let instance = allocator.get_instance(handle);
380                let clazz = allocator.get_class(instance.clazz);
381                let identifier = allocator.strings.get(clazz.name);
382                format!("instanceof {}", identifier)
383            }
384            ValueKind::BoundMethod(handle) => {
385                let method_binding = allocator.get_bound_method(handle);
386                format!(
387                    "{}.{}",
388                    method_binding.receiver.to_display_string(allocator),
389                    Value::closure(method_binding.closure).to_display_string(allocator)
390                )
391            }
392            ValueKind::BoundIntrinsic(handle) => {
393                let intrinsic_binding = allocator.get_bound_intrinsic(handle);
394                format!(
395                    "{}.{}",
396                    intrinsic_binding.receiver.to_type_string(),
397                    Value::string(intrinsic_binding.name_handle).to_display_string(allocator)
398                )
399            }
400            ValueKind::Array(handle) => {
401                let mut string = String::from("[");
402                for item in allocator.arrays.iter(handle) {
403                    string.push_str(&item.to_display_string(allocator));
404                    string.push(',');
405                }
406                string.push(']');
407                string
408            }
409            ValueKind::ObjectLiteral(handle) => {
410                let mut string = String::from("{{");
411                for (key, value) in allocator.tables.iter(handle) {
412                    string.push(' ');
413                    string.push_str(&key.to_display_string(allocator));
414                    string.push('=');
415                    string.push_str(&value.to_display_string(allocator));
416                    string.push(',');
417                    string.push(' ');
418                }
419                string.push_str("}}");
420                string
421            }
422            ValueKind::Module(handle) => {
423                format!("module#{}", handle)
424            }
425        }
426    }
427
428    pub fn to_type_string(&self) -> &'static str {
429        match self.kind() {
430            ValueKind::Nil => NIL_TYPE_STRING,
431            ValueKind::True => BOOLEAN_TYPE_STRING,
432            ValueKind::False => BOOLEAN_TYPE_STRING,
433            ValueKind::Number(_) => NUMBER_TYPE_STRING,
434            ValueKind::String(_) => STRING_TYPE_STRING,
435            ValueKind::Closure(_) => FUNCTION_TYPE_STRING,
436            ValueKind::NativeFunction(_) => FUNCTION_TYPE_STRING,
437            ValueKind::FunctionDecl(_) => FUNCTION_TYPE_STRING,
438            ValueKind::Class(_) => CLASS_TYPE_STRING,
439            ValueKind::Instance(_) => OBJECT_TYPE_STRING,
440            ValueKind::BoundMethod(_) => FUNCTION_TYPE_STRING,
441            ValueKind::BoundIntrinsic(_) => FUNCTION_TYPE_STRING,
442            ValueKind::Array(_) => ARRAY_TYPE_STRING,
443            ValueKind::ObjectLiteral(_) => OBJECT_TYPE_STRING,
444            ValueKind::Module(_) => MODULE_TYPE_STRING,
445        }
446    }
447
448    pub fn hash(&self) -> u64 {
449        let mut hasher = FxHasher::default();
450
451        self.0.to_bits().hash(&mut hasher);
452
453        hasher.finish()
454    }
455}
456
457impl From<f64> for Value {
458    fn from(num: f64) -> Self {
459        Value::number(num)
460    }
461}
462
463impl From<u64> for Value {
464    fn from(num: u64) -> Self {
465        Value::number(num as f64)
466    }
467}
468
469impl From<usize> for Value {
470    fn from(num: usize) -> Self {
471        Value::number(num as f64)
472    }
473}
474
475impl From<bool> for Value {
476    fn from(value: bool) -> Self {
477        Value::boolean(value)
478    }
479}
480
481impl PartialEq for Value {
482    fn eq(&self, other: &Self) -> bool {
483        if !self.0.is_nan() && !other.0.is_nan() {
484            return self.0 == other.0;
485        }
486
487        self.0.to_bits() == other.0.to_bits()
488    }
489}
490
491impl Eq for Value {}
492
493impl Hash for Value {
494    fn hash<H: Hasher>(&self, state: &mut H) {
495        self.0.to_bits().hash(state);
496    }
497}
498
499impl Default for Value {
500    fn default() -> Self {
501        Value::nil()
502    }
503}
504
505impl std::fmt::Display for Index {
506    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
507        write!(f, "{}", self.index)
508    }
509}