1use std::collections::HashMap;
2use std::hash::{Hash, Hasher};
3
4use crate::chunk::ModuleChunk;
5use serde::{Deserialize, Serialize};
6
7use crate::native::native_functions::NativeFn;
8use crate::native::native_methods::NativeMethod;
9use crate::vm::{VMState, VM};
10
11#[derive(Debug, Clone, Serialize, Deserialize, Default)]
12pub enum Value {
13 Float(f32),
14 Long(i64),
15 Bool(bool),
16 #[default]
17 Nil,
18 PhoenixString(String),
21 PhoenixFunction(usize),
23 #[serde(skip)]
24 NativeFunction(Option<usize>, NativeFn),
25 #[serde(skip)]
26 NativeMethod(Option<usize>, NativeMethod),
27 PhoenixClass(usize),
28 PhoenixModule(usize),
30 PhoenixPointer(usize),
32 PhoenixBoundMethod(ObjBoundMethod),
33}
34
35impl Hash for Value {
37 fn hash<H: Hasher>(&self, state: &mut H) {
38 match self {
39 Value::Float(x) => x.to_bits().hash(state),
40 Value::Long(x) => x.hash(state),
41 Value::Bool(x) => x.hash(state),
42 Value::Nil => 0.hash(state),
43 Value::PhoenixString(x) => x.hash(state),
44 Value::PhoenixFunction(x) => x.hash(state),
45 Value::NativeFunction(x, _) => x.hash(state),
46 Value::NativeMethod(x, _) => x.hash(state),
47 Value::PhoenixClass(x) => x.hash(state),
48 Value::PhoenixModule(x) => x.hash(state),
49 Value::PhoenixPointer(x) => x.hash(state),
50 Value::PhoenixBoundMethod(x) => x.hash(state),
51 }
52 }
53}
54
55impl Eq for Value {}
56
57impl PartialEq for Value {
58 fn eq(&self, other: &Self) -> bool {
59 values_equal((self, other))
60 }
61}
62
63#[derive(Debug, Clone, Serialize, Deserialize, Default)]
64pub struct ValueArray {
65 pub values: Vec<Value>,
66}
67
68impl ValueArray {
69 pub fn new() -> ValueArray {
70 ValueArray { values: Vec::new() }
71 }
72
73 pub fn write(&mut self, value: Value) {
74 self.values.push(value);
75 }
76
77 pub fn free(&mut self) {
78 self.values.clear();
79 }
80}
81
82impl Value {
83 pub fn to_string(&self, vm: &VM, state: &VMState, modules: &Vec<ModuleChunk>) -> String {
85 match self {
86 Value::Float(x) => format!("{}", x),
87 Value::Long(x) => format!("{}", x),
88 Value::Bool(x) => format!("{}", x),
89 Value::PhoenixString(x) => x.to_string(),
90 Value::Nil => String::from("nil"),
91 Value::PhoenixFunction(x) => format!(
92 "<fn {}>",
93 &modules[state.current_frame.module]
94 .functions
95 .get(*x)
96 .unwrap()
97 .name
98 .as_ref()
99 .unwrap()
100 ),
101 Value::NativeFunction(_x, _) => "<native_fn>".to_string(),
102 Value::NativeMethod(_x, _) => "<native_method>".to_string(),
103 Value::PhoenixClass(class) => format!("<class {}>", class),
104 Value::PhoenixPointer(pointer) => {
105 if let HeapObjVal::PhoenixList(_) = &state.deref(*pointer).obj {
107 state.deref(*pointer).to_string(vm, state, modules)
108 } else if let HeapObjVal::PhoenixString(_) = &state.deref(*pointer).obj {
109 state.deref(*pointer).to_string(vm, state, modules)
110 } else if let HeapObjVal::PhoenixHashMap(_) = &state.deref(*pointer).obj {
111 state.deref(*pointer).to_string(vm, state, modules)
112 } else {
113 format!(
114 "<pointer {}> to {}",
115 pointer,
116 state.deref(*pointer).to_string(vm, state, modules)
117 )
118 }
119 } Value::PhoenixBoundMethod(method) => format!(
121 "<method {} from {}",
122 &modules[state.current_frame.module]
123 .functions
124 .get(method.method)
125 .unwrap()
126 .name
127 .as_ref()
128 .unwrap(),
129 state.deref(method.pointer).to_string(vm, state, modules)
130 ),
131 Value::PhoenixModule(module) => format!("<module {}>", module),
132 }
133 }
134
135 pub fn as_float(&self) -> Option<f32> {
136 if let Value::Float(val) = self {
137 Some(*val)
138 } else if let Value::Long(val) = self {
139 Some(*val as f32)
140 } else {
141 None
142 }
143 }
144
145 pub fn as_long(&self) -> Option<i64> {
146 if let Value::Long(val) = self {
147 Some(*val)
148 } else if let Value::Float(val) = self {
149 Some(*val as i64)
150 } else {
151 None
152 }
153 }
154
155 pub fn as_bool(&self) -> Option<bool> {
156 match self {
157 Value::Bool(val) => Some(*val),
158 Value::Long(val) => Some(*val != 0),
159 Value::Float(val) => Some(*val != 0.0),
160 _ => None,
161 }
162 }
163
164 pub fn as_string<'a>(&'a self, state: &'a VMState) -> Option<&String> {
165 if let Value::PhoenixPointer(x) = self {
166 Some(&state.deref_string(*x).value)
167 } else {
168 None
169 }
170 }
171
172 pub const fn get_type(&self) -> &str {
173 match self {
174 Value::Float(_) => "float",
175 Value::Long(_) => "long",
176 Value::Bool(_) => "bool",
177 Value::Nil => "nil",
178 Value::PhoenixFunction(_) => "function",
179 Value::PhoenixClass(_) => "class",
180 Value::NativeFunction(_, _) => "native_function",
181 Value::PhoenixPointer(_) => "pointer",
182 Value::PhoenixBoundMethod(_) => "bound_method",
183 _ => "unknown (Please report this bug)",
184 }
185 }
186
187 pub fn as_pointer(&self) -> usize {
189 if let Value::PhoenixPointer(ptr) = self {
190 *ptr
191 } else {
192 panic!(
193 "VM panic! Failed to cast value to a pointer. Found {:?} instead",
194 self
195 )
196 }
197 }
198
199 pub fn to_float(&self) -> Result<f32, String> {
201 match self.as_float() {
202 Some(num) => {
203 if num.is_nan() {
204 return Err("Invalid argument: expected number, got NaN".to_string());
205 }
206 Ok(num)
207 }
208 None => Err(format!(
209 "Invalid argument: expected number: instead got {}",
210 self.get_type()
211 )),
212 }
213 }
214
215 pub fn to_long(&self) -> Result<i64, String> {
217 match self.as_long() {
218 Some(num) => Ok(num),
219 None => Err(format!(
220 "Invalid argument: expected number: instead got {}",
221 self.get_type()
222 )),
223 }
224 }
225
226 pub fn to_bool(&self) -> Result<bool, String> {
228 match self.as_bool() {
229 Some(val) => Ok(val),
230 None => Err(format!(
231 "Invalid argument: expected boolean: instead got {}",
232 self.get_type()
233 )),
234 }
235 }
236
237 pub fn to_list(&self, state: &VMState) -> Result<Vec<Value>, String> {
239 if let Value::PhoenixPointer(p) = self {
240 if let HeapObjVal::PhoenixList(_) = &state.deref(*p).obj {
241 return Ok(state.deref(*p).obj.as_list().values.clone());
242 }
243 }
244 Err(format!(
245 "Invalid argument: expected list: instead got {}",
246 self.get_type()
247 ))
248 }
249
250 pub fn to_class<'a>(&self, state: &'a VMState) -> Result<&'a ObjInstance, String> {
252 if let Value::PhoenixPointer(p) = self {
253 if let HeapObjVal::PhoenixInstance(_) = &state.deref(*p).obj {
254 return Ok(state.deref(*p).obj.as_instance());
255 }
256 }
257 Err(format!(
258 "Invalid argument: expected class: instead got {}",
259 self.get_type()
260 ))
261 }
262}
263
264pub fn is_falsey(val: &Value) -> bool {
265 matches!(val, Value::Bool(false) | Value::Nil)
266}
267
268pub fn values_equal(t: (&Value, &Value)) -> bool {
269 match t {
270 (Value::Float(x), Value::Float(y)) => x == y,
271 (Value::Long(x), Value::Long(y)) => x == y,
272 (Value::Bool(x), Value::Bool(y)) => x == y,
273 (Value::Nil, Value::Nil) => true,
274 (Value::PhoenixString(x), Value::PhoenixString(y)) => x.eq(y),
275 (Value::PhoenixPointer(x), Value::PhoenixPointer(y)) => x == y,
276 (Value::PhoenixClass(x), Value::PhoenixClass(y)) => x == y,
277 (Value::PhoenixFunction(x), Value::PhoenixFunction(y)) => x == y,
278 (Value::NativeFunction(x, x2), Value::NativeFunction(y, y2)) => x == y && x2 == y2,
279 (Value::PhoenixBoundMethod(x), Value::PhoenixBoundMethod(y)) => x == y,
280 _ => false,
281 }
282}
283
284#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize, Ord, PartialOrd, Eq, Hash)]
285pub struct ObjBoundMethod {
286 pub method: usize,
287 pub pointer: usize, }
290
291#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
296pub enum HeapObjType {
297 HeapPlaceholder,
298 PhoenixInstance,
299 PhoenixClosure,
300 PhoenixList,
301 PhoenixString,
302 PhoenixHashMap,
303}
304
305#[derive(Debug, PartialEq, Serialize, Deserialize, Clone)]
306pub struct HeapObj {
307 pub obj: HeapObjVal,
308 pub obj_type: HeapObjType,
309 pub is_marked: bool,
310}
311
312impl HeapObj {
313 fn to_string(&self, vm: &VM, state: &VMState, modules: &Vec<ModuleChunk>) -> String {
314 self.obj.to_string(vm, state, modules)
315 }
316
317 pub fn new_instance(val: ObjInstance) -> HeapObj {
318 HeapObj {
319 obj: HeapObjVal::PhoenixInstance(val),
320 obj_type: HeapObjType::PhoenixInstance,
321 is_marked: false,
322 }
323 }
324
325 pub fn new_closure(val: ObjClosure) -> HeapObj {
326 HeapObj {
327 obj: HeapObjVal::PhoenixClosure(val),
328 obj_type: HeapObjType::PhoenixClosure,
329 is_marked: false,
330 }
331 }
332
333 pub fn new_placeholder() -> HeapObj {
334 HeapObj {
335 obj: HeapObjVal::HeapPlaceholder,
336 obj_type: HeapObjType::HeapPlaceholder,
337 is_marked: false,
338 }
339 }
340
341 pub fn new_list(val: ObjList) -> HeapObj {
342 HeapObj {
343 obj: HeapObjVal::PhoenixList(val),
344 obj_type: HeapObjType::PhoenixList,
345 is_marked: false,
346 }
347 }
348
349 pub fn new_string(val: ObjString) -> HeapObj {
350 HeapObj {
351 obj: HeapObjVal::PhoenixString(val),
352 obj_type: HeapObjType::PhoenixString,
353 is_marked: false,
354 }
355 }
356
357 pub fn new_hashmap(map: ObjHashMap) -> HeapObj {
358 HeapObj {
359 obj: HeapObjVal::PhoenixHashMap(map),
360 obj_type: HeapObjType::PhoenixHashMap,
361 is_marked: false,
362 }
363 }
364}
365
366#[derive(Debug, PartialEq, Serialize, Deserialize, Clone)]
368pub enum HeapObjVal {
369 HeapPlaceholder,
370 PhoenixInstance(ObjInstance),
371 PhoenixClosure(ObjClosure),
372 PhoenixString(ObjString),
373 PhoenixList(ObjList),
374 PhoenixHashMap(ObjHashMap),
375}
376
377impl HeapObjVal {
378 fn to_string(&self, vm: &VM, state: &VMState, modules: &Vec<ModuleChunk>) -> String {
379 match self {
380 HeapObjVal::PhoenixClosure(closure) => format!(
381 "<fn {} | {:?}>",
382 &modules[state.current_frame.module]
383 .functions
384 .get(closure.function)
385 .unwrap()
386 .name
387 .as_ref()
388 .unwrap(),
389 closure
390 ),
391 HeapObjVal::PhoenixInstance(instance) => format!(
392 "<instance {}>",
393 &modules[state.current_frame.module]
394 .classes
395 .get(instance.class)
396 .unwrap()
397 .name
398 ),
399 HeapObjVal::PhoenixList(list) => format!(
400 "[{}]",
401 list.values
402 .iter()
403 .map(|x| x.to_string(vm, state, modules))
404 .collect::<Vec<String>>()
405 .join(", ")
406 ),
407 HeapObjVal::HeapPlaceholder => {
408 panic!("VM panic! How did a placeholder value get here?")
409 }
410 HeapObjVal::PhoenixString(string) => string.value.clone(),
411 HeapObjVal::PhoenixHashMap(map) => format!(
412 "{{{}}}",
413 map.map
414 .iter()
415 .map(|(k, v)| format!(
416 "{}: {}",
417 k.to_string(vm, state, modules),
418 v.to_string(vm, state, modules)
419 ))
420 .collect::<Vec<String>>()
421 .join(", ")
422 ),
423 }
424 }
425
426 pub fn as_closure(&self) -> &ObjClosure {
427 if let HeapObjVal::PhoenixClosure(closure) = self {
428 closure
429 } else {
430 panic!("VM panic!")
431 }
432 }
433
434 pub fn as_closure_mut(&mut self) -> &mut ObjClosure {
435 if let HeapObjVal::PhoenixClosure(closure) = self {
436 closure
437 } else {
438 panic!("VM panic!")
439 }
440 }
441
442 pub fn as_instance(&self) -> &ObjInstance {
443 if let HeapObjVal::PhoenixInstance(instance) = self {
444 instance
445 } else {
446 panic!("VM panic!")
447 }
448 }
449
450 pub fn as_instance_mut(&mut self) -> &mut ObjInstance {
451 if let HeapObjVal::PhoenixInstance(instance) = self {
452 instance
453 } else {
454 panic!("VM panic!")
455 }
456 }
457
458 pub fn as_list(&self) -> &ObjList {
459 if let HeapObjVal::PhoenixList(list) = self {
460 list
461 } else {
462 panic!("VM panic!")
463 }
464 }
465
466 pub fn as_list_mut(&mut self) -> &mut ObjList {
467 if let HeapObjVal::PhoenixList(list) = self {
468 list
469 } else {
470 panic!("VM panic!")
471 }
472 }
473
474 pub fn as_string(&self) -> &ObjString {
475 if let HeapObjVal::PhoenixString(string) = self {
476 string
477 } else {
478 panic!("VM panic!")
479 }
480 }
481
482 pub fn as_string_mut(&mut self) -> &mut ObjString {
483 if let HeapObjVal::PhoenixString(string) = self {
484 string
485 } else {
486 panic!("VM panic!")
487 }
488 }
489
490 pub fn as_hashmap(&self) -> &ObjHashMap {
491 if let HeapObjVal::PhoenixHashMap(map) = self {
492 map
493 } else {
494 panic!("VM panic!")
495 }
496 }
497}
498
499
500impl TryFrom<Value> for f32 {
502 type Error = String;
503
504 fn try_from(value: Value) -> Result<Self, Self::Error> {
505 match value {
506 Value::Float(f) => Ok(f),
507 Value::Long(l) => Ok(l as f32),
508 _ => Err(format!("Could not convert {} to float!", value.get_type())),
509 }
510 }
511}
512
513impl TryFrom<Value> for i64 {
514 type Error = String;
515
516 fn try_from(value: Value) -> Result<Self, Self::Error> {
517 match value {
518 Value::Long(l) => Ok(l),
519 Value::Float(f) => Ok(f as i64),
520 _ => Err(format!("Could not convert {} to int!", value.get_type())),
521 }
522 }
523}
524
525impl TryFrom<Value> for i32 {
526 type Error = String;
527
528 fn try_from(value: Value) -> Result<Self, Self::Error> {
529 match value {
530 Value::Long(l) => Ok(l as i32),
531 Value::Float(f) => Ok(f as i32),
532 _ => Err(format!("Could not convert {} to int!", value.get_type())),
533 }
534 }
535}
536
537impl TryFrom<Value> for bool {
538 type Error = String;
539
540 fn try_from(value: Value) -> Result<Self, Self::Error> {
541 match value {
542 Value::Bool(b) => Ok(b),
543 _ => Err(format!("Could not convert {} to bool!", value.get_type())),
544 }
545 }
546}
547
548impl TryFrom<Value> for String {
549 type Error = String;
550
551 fn try_from(value: Value) -> Result<Self, Self::Error> {
552 match value {
553 Value::PhoenixString(s) => Ok(s),
554 _ => Err(format!("Could not convert {} to string!", value.get_type())),
555 }
556 }
557}
558
559
560
561#[derive(Debug, PartialEq, Serialize, Deserialize, Clone)]
563pub struct ObjInstance {
564 pub class: usize,
565 pub fields: HashMap<usize, Value>, }
568
569impl ObjInstance {
570 pub fn new(class: usize) -> ObjInstance {
571 ObjInstance {
572 class,
573 fields: HashMap::new(),
574 }
575 }
576}
577
578#[derive(Debug, PartialEq, Serialize, Deserialize, Clone)]
580pub struct ObjClosure {
581 pub function: usize,
582 pub values: Vec<Value>, }
584
585impl ObjClosure {
586 pub fn new(function: usize) -> ObjClosure {
587 ObjClosure {
588 function,
589 values: Vec::new(),
590 }
591 }
592}
593
594#[derive(Debug, PartialEq, Serialize, Deserialize, Clone)]
596pub struct ObjList {
597 pub values: Vec<Value>,
598}
599
600impl ObjList {
601 pub fn new(v: Vec<Value>) -> ObjList {
602 ObjList { values: v }
603 }
604}
605
606#[derive(Debug, PartialEq, Serialize, Deserialize, Clone)]
608pub struct ObjString {
609 pub value: String,
610}
611
612impl ObjString {
613 pub fn new(value: String) -> ObjString {
614 ObjString { value }
615 }
616}
617
618#[derive(Debug, PartialEq, Serialize, Deserialize, Clone, Default)]
620pub struct ObjHashMap {
621 pub map: HashMap<Value, Value>,
622}
623
624impl ObjHashMap {
625 pub fn new(map: HashMap<Value, Value>) -> ObjHashMap {
626 ObjHashMap { map }
627 }
628}