qanglang_core/backend/
value.rs1use 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
10pub 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; const PAYLOAD_MASK: u64 = 0x0000_0FFF_FFFF_FFFF; const NIL_TAG: u64 = 0x0000_1000_0000_0000;
27const BOOL_TAG: u64 = 0x0000_2000_0000_0000; const 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;
39const 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(), }
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}