1use std::collections::{HashMap, HashSet};
2use std::fmt;
3use std::fmt::Write as _;
4use std::rc::Rc;
5
6use object::builtins::{BuiltIns, BuiltinId};
7use object::{Closure, CompiledFunction, Object};
8use serde::Serialize;
9
10use crate::header::GcObjectType;
11use crate::{GcHeap, GcObject, GcRef};
12
13#[derive(Debug, Clone, PartialEq)]
15pub enum Value {
16 Integer(i64),
17 Boolean(bool),
18 String(String),
19 Array(Vec<GcRef>),
20 Hash(HashMap<HashKey, GcRef>),
21 Null,
22 Error(String),
23 CompiledFunction(CompiledFunction),
24 Closure(GcClosure),
25 Builtin(BuiltinId),
26 Class(GcClass),
27 Instance(GcInstance),
28 BoundMethod(GcBoundMethod),
29}
30
31#[derive(Debug, Clone, PartialEq, Eq)]
32pub struct GcClosure {
33 pub func: GcRef,
34 pub free: Vec<GcRef>,
35}
36
37#[derive(Debug, Clone, PartialEq, Eq)]
38pub struct GcClass {
39 pub name: String,
40 pub constructor: Option<GcRef>,
41 pub methods: HashMap<String, GcRef>,
42}
43
44#[derive(Debug, Clone, PartialEq, Eq)]
45pub struct GcInstance {
46 pub class: GcRef,
47 pub fields: HashMap<String, GcRef>,
48}
49
50#[derive(Debug, Clone, PartialEq, Eq)]
51pub struct GcBoundMethod {
52 pub receiver: GcRef,
53 pub method: GcRef,
54 pub name: String,
55}
56
57#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize)]
58#[serde(rename_all = "camelCase")]
59pub enum ValueKind {
60 Class,
61 Instance,
62 BoundMethod,
63 Closure,
64 Array,
65 Hash,
66 Integer,
67 Boolean,
68 String,
69 Null,
70 Error,
71 CompiledFunction,
72 Builtin,
73 Other,
74}
75
76#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
78#[serde(tag = "kind", rename_all = "camelCase")]
79pub enum EdgeRelation {
80 ArrayElement {
81 index: usize,
82 },
83 HashValue {
84 #[serde(rename = "keyKind")]
85 key_kind: HashKeyKind,
86 key: String,
87 },
88 ClosureFunction,
89 ClosureFree {
90 index: usize,
91 },
92 ClassConstructor,
93 ClassMethod {
94 name: String,
95 },
96 InstanceClass,
97 InstanceField {
98 name: String,
99 },
100 BoundMethodReceiver,
101 BoundMethodFunction,
102 Unknown,
103}
104
105#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize)]
106#[serde(rename_all = "camelCase")]
107pub enum HashKeyKind {
108 Integer,
109 Boolean,
110 String,
111}
112
113pub const MAX_HASH_KEY_LABEL_LEN: usize = 64;
114
115pub fn format_hash_key_label(key: &HashKey) -> String {
116 match key {
117 HashKey::Integer(value) => value.to_string(),
118 HashKey::Boolean(value) => value.to_string(),
119 HashKey::String(value) => escape_and_truncate_key(value),
120 }
121}
122
123fn escape_and_truncate_key(value: &str) -> String {
124 let mut escaped = String::with_capacity(value.len().min(MAX_HASH_KEY_LABEL_LEN) + 3);
125 for ch in value.chars() {
126 let mut char_buffer = [0; 4];
127 let mut control_buffer = String::new();
128 let encoded = match ch {
129 '\\' => "\\\\",
130 '"' => "\\\"",
131 '\n' => "\\n",
132 '\r' => "\\r",
133 '\t' => "\\t",
134 c if c.is_control() => {
135 write!(&mut control_buffer, "\\u{:04x}", c as u32)
136 .expect("writing to a String cannot fail");
137 control_buffer.as_str()
138 }
139 c => c.encode_utf8(&mut char_buffer),
140 };
141 if escaped.len() + encoded.len() > MAX_HASH_KEY_LABEL_LEN {
142 escaped.push('…');
143 break;
144 }
145 escaped.push_str(encoded);
146 }
147 escaped
148}
149
150#[derive(Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
151pub enum HashKey {
152 Integer(i64),
153 Boolean(bool),
154 String(String),
155}
156
157impl HashKey {
158 pub fn kind(&self) -> HashKeyKind {
159 match self {
160 HashKey::Integer(_) => HashKeyKind::Integer,
161 HashKey::Boolean(_) => HashKeyKind::Boolean,
162 HashKey::String(_) => HashKeyKind::String,
163 }
164 }
165}
166
167pub struct ValueCell {
168 pub value: Value,
169}
170
171impl GcObject for ValueCell {
172 fn trace(&self, visit: &mut dyn FnMut(crate::GcId)) {
173 self.value.trace(&mut |reference| visit(reference.0));
174 }
175}
176
177impl Value {
178 pub fn kind(&self) -> ValueKind {
179 match self {
180 Value::Class(_) => ValueKind::Class,
181 Value::Instance(_) => ValueKind::Instance,
182 Value::BoundMethod(_) => ValueKind::BoundMethod,
183 Value::Closure(_) => ValueKind::Closure,
184 Value::Array(_) => ValueKind::Array,
185 Value::Hash(_) => ValueKind::Hash,
186 Value::Integer(_) => ValueKind::Integer,
187 Value::Boolean(_) => ValueKind::Boolean,
188 Value::String(_) => ValueKind::String,
189 Value::Null => ValueKind::Null,
190 Value::Error(_) => ValueKind::Error,
191 Value::CompiledFunction(_) => ValueKind::CompiledFunction,
192 Value::Builtin(_) => ValueKind::Builtin,
193 }
194 }
195
196 pub fn visit_edges(&self, mut visit: impl FnMut(EdgeRelation, GcRef)) {
202 match self {
203 Value::Array(items) => {
204 for (index, item) in items.iter().enumerate() {
205 visit(
206 EdgeRelation::ArrayElement {
207 index,
208 },
209 *item,
210 );
211 }
212 }
213 Value::Hash(map) => {
214 let mut entries = map.iter().collect::<Vec<_>>();
215 entries.sort_by(|(left, _), (right, _)| left.cmp(right));
216 for (key, value) in entries {
217 visit(
218 EdgeRelation::HashValue {
219 key_kind: key.kind(),
220 key: format_hash_key_label(key),
221 },
222 *value,
223 );
224 }
225 }
226 Value::Closure(closure) => {
227 visit(EdgeRelation::ClosureFunction, closure.func);
228 for (index, free) in closure.free.iter().enumerate() {
229 visit(
230 EdgeRelation::ClosureFree {
231 index,
232 },
233 *free,
234 );
235 }
236 }
237 Value::Class(class) => {
238 if let Some(constructor) = class.constructor {
239 visit(EdgeRelation::ClassConstructor, constructor);
240 }
241 let mut methods = class.methods.iter().collect::<Vec<_>>();
242 methods.sort_by(|(left, _), (right, _)| left.cmp(right));
243 for (name, method) in methods {
244 visit(
245 EdgeRelation::ClassMethod {
246 name: name.clone(),
247 },
248 *method,
249 );
250 }
251 }
252 Value::Instance(instance) => {
253 visit(EdgeRelation::InstanceClass, instance.class);
254 let mut fields = instance.fields.iter().collect::<Vec<_>>();
255 fields.sort_by(|(left, _), (right, _)| left.cmp(right));
256 for (name, value) in fields {
257 visit(
258 EdgeRelation::InstanceField {
259 name: name.clone(),
260 },
261 *value,
262 );
263 }
264 }
265 Value::BoundMethod(method) => {
266 visit(EdgeRelation::BoundMethodReceiver, method.receiver);
267 visit(EdgeRelation::BoundMethodFunction, method.method);
268 }
269 Value::Integer(_)
272 | Value::Boolean(_)
273 | Value::String(_)
274 | Value::Null
275 | Value::Error(_)
276 | Value::CompiledFunction(_)
277 | Value::Builtin(_) => {}
278 }
279 }
280
281 pub fn trace(&self, visit: &mut dyn FnMut(GcRef)) {
282 match self {
283 Value::Array(items) => {
284 for item in items {
285 visit(*item);
286 }
287 }
288 Value::Hash(map) => {
289 for value in map.values() {
290 visit(*value);
291 }
292 }
293 Value::Closure(closure) => {
294 visit(closure.func);
295 for free in &closure.free {
296 visit(*free);
297 }
298 }
299 Value::Class(class) => {
300 if let Some(constructor) = class.constructor {
301 visit(constructor);
302 }
303 for method in class.methods.values() {
304 visit(*method);
305 }
306 }
307 Value::Instance(instance) => {
308 visit(instance.class);
309 for field in instance.fields.values() {
310 visit(*field);
311 }
312 }
313 Value::BoundMethod(method) => {
314 visit(method.receiver);
315 visit(method.method);
316 }
317 Value::Integer(_)
320 | Value::Boolean(_)
321 | Value::String(_)
322 | Value::Null
323 | Value::Error(_)
324 | Value::CompiledFunction(_)
325 | Value::Builtin(_) => {}
326 }
327 }
328
329 pub fn with_owned_edges(self, heap: &mut GcHeap) -> Self {
330 match self {
331 Value::Array(items) => Value::Array(items.into_iter().map(|r| heap.dup(r)).collect()),
332 Value::Hash(map) => {
333 Value::Hash(map.into_iter().map(|(k, v)| (k, heap.dup(v))).collect())
334 }
335 Value::Closure(mut closure) => {
336 closure.func = heap.dup(closure.func);
337 closure.free = closure.free.into_iter().map(|r| heap.dup(r)).collect();
338 Value::Closure(closure)
339 }
340 Value::Class(mut class) => {
341 class.constructor = class.constructor.map(|r| heap.dup(r));
342 class.methods = class
343 .methods
344 .into_iter()
345 .map(|(name, method)| (name, heap.dup(method)))
346 .collect();
347 Value::Class(class)
348 }
349 Value::Instance(mut instance) => {
350 instance.class = heap.dup(instance.class);
351 instance.fields = instance
352 .fields
353 .into_iter()
354 .map(|(name, value)| (name, heap.dup(value)))
355 .collect();
356 Value::Instance(instance)
357 }
358 Value::BoundMethod(mut method) => {
359 method.receiver = heap.dup(method.receiver);
360 method.method = heap.dup(method.method);
361 Value::BoundMethod(method)
362 }
363 other => other,
364 }
365 }
366
367 pub fn edge_refs(&self) -> Vec<GcRef> {
368 let mut refs = Vec::new();
369 self.trace(&mut |reference| refs.push(reference));
370 refs
371 }
372}
373
374impl HashKey {
375 pub fn from_object(object: &Object) -> Option<HashKey> {
376 match object {
377 Object::Integer(i) => Some(HashKey::Integer(*i)),
378 Object::Boolean(b) => Some(HashKey::Boolean(*b)),
379 Object::String(s) => Some(HashKey::String(s.clone())),
380 _ => None,
381 }
382 }
383
384 pub fn from_value(value: &Value) -> Option<HashKey> {
385 match value {
386 Value::Integer(i) => Some(HashKey::Integer(*i)),
387 Value::Boolean(b) => Some(HashKey::Boolean(*b)),
388 Value::String(s) => Some(HashKey::String(s.clone())),
389 _ => None,
390 }
391 }
392
393 pub fn to_object(&self) -> Object {
394 match self {
395 HashKey::Integer(i) => Object::Integer(*i),
396 HashKey::Boolean(b) => Object::Boolean(*b),
397 HashKey::String(s) => Object::String(s.clone()),
398 }
399 }
400}
401
402pub fn alloc_value(heap: &mut GcHeap, value: Value) -> GcRef {
403 let value = value.with_owned_edges(heap);
404 heap.alloc(
405 ValueCell {
406 value,
407 },
408 GcObjectType::MonkeyObject,
409 )
410}
411
412pub fn get_value(heap: &GcHeap, reference: GcRef) -> &Value {
413 &heap
414 .runtime()
415 .object_downcast::<ValueCell>(reference.0)
416 .expect("invalid value reference")
417 .value
418}
419
420pub fn get_value_mut(heap: &mut GcHeap, reference: GcRef) -> &mut Value {
421 &mut heap
422 .runtime_mut()
423 .object_downcast_mut::<ValueCell>(reference.0)
424 .expect("invalid value reference")
425 .value
426}
427
428pub fn value_to_string(heap: &GcHeap, reference: GcRef) -> String {
429 format_reference(heap, reference, &mut HashSet::new())
430}
431
432fn format_reference(heap: &GcHeap, reference: GcRef, visited: &mut HashSet<usize>) -> String {
433 if !visited.insert(reference.0) {
434 return format!("[cycle #{}]", reference.0);
435 }
436 let formatted = format_value(heap, get_value(heap, reference), visited);
437 visited.remove(&reference.0);
438 formatted
439}
440
441fn format_value(heap: &GcHeap, value: &Value, visited: &mut HashSet<usize>) -> String {
442 match value {
443 Value::Integer(i) => i.to_string(),
444 Value::Boolean(b) => b.to_string(),
445 Value::String(s) => s.clone(),
446 Value::Null => "null".to_string(),
447 Value::Error(e) => e.clone(),
448 Value::Array(items) => {
449 let parts = items
450 .iter()
451 .map(|item| format_reference(heap, *item, visited))
452 .collect::<Vec<_>>()
453 .join(", ");
454 format!("[{}]", parts)
455 }
456 Value::Hash(map) => {
457 let parts = map
458 .iter()
459 .map(|(k, v)| {
460 format!("{}: {}", format_hash_key(k), format_reference(heap, *v, visited))
461 })
462 .collect::<Vec<_>>()
463 .join(", ");
464 format!("{{{}}}", parts)
465 }
466 Value::CompiledFunction(_) => "[compiled function]".to_string(),
467 Value::Closure(_) => "[closure function]".to_string(),
468 Value::Builtin(_) => "[builtin function]".to_string(),
469 Value::Class(class) => format!("[class {}]", class.name),
470 Value::Instance(instance) => {
471 format!("[object {}]", class_name(heap, instance.class))
472 }
473 Value::BoundMethod(method) => {
474 format!("[bound method {}.{}]", instance_class_name(heap, method.receiver), method.name)
475 }
476 }
477}
478
479fn class_name(heap: &GcHeap, class: GcRef) -> String {
480 match get_value(heap, class) {
481 Value::Class(class) => class.name.clone(),
482 _ => "<invalid class>".to_string(),
483 }
484}
485
486fn instance_class_name(heap: &GcHeap, instance: GcRef) -> String {
487 match get_value(heap, instance) {
488 Value::Instance(instance) => class_name(heap, instance.class),
489 _ => "<invalid receiver>".to_string(),
490 }
491}
492
493fn format_hash_key(key: &HashKey) -> String {
494 match key {
495 HashKey::Integer(i) => i.to_string(),
496 HashKey::Boolean(b) => b.to_string(),
497 HashKey::String(s) => s.clone(),
498 }
499}
500
501pub fn import_object(heap: &mut GcHeap, object: &Object) -> GcRef {
502 let value = match object {
503 Object::Integer(i) => Value::Integer(*i),
504 Object::Boolean(b) => Value::Boolean(*b),
505 Object::String(s) => Value::String(s.clone()),
506 Object::Null => Value::Null,
507 Object::Error(e) => Value::Error(e.clone()),
508 Object::Array(items) => {
509 Value::Array(items.iter().map(|item| import_object(heap, item)).collect())
510 }
511 Object::Hash(map) => Value::Hash(
512 map.iter()
513 .map(|(k, v)| {
514 (
515 HashKey::from_object(k).expect("hash key must be hashable"),
516 import_object(heap, v),
517 )
518 })
519 .collect(),
520 ),
521 Object::CompiledFunction(f) => Value::CompiledFunction(CompiledFunction {
522 name: f.name.clone(),
523 instructions: f.instructions.clone(),
524 num_locals: f.num_locals,
525 num_parameters: f.num_parameters,
526 }),
527 Object::ClosureObj(closure) => Value::Closure(GcClosure {
528 func: import_object(heap, &Object::CompiledFunction(Rc::clone(&closure.func))),
529 free: closure
530 .free
531 .iter()
532 .map(|item| import_object(heap, item))
533 .collect(),
534 }),
535 Object::Builtin(function) => {
536 let definition = BuiltIns
537 .iter()
538 .find(|definition| std::ptr::fn_addr_eq(definition.function, *function))
539 .expect("unknown builtin function");
540 Value::Builtin(definition.id)
541 }
542 Object::ReturnValue(inner) => return import_object(heap, inner),
543 Object::Function(_, _, _) => {
544 panic!("interpreter functions cannot be imported into the GC VM")
545 }
546 Object::Class(_) | Object::Instance(_) | Object::BoundMethod(_) => {
547 panic!("graph values cannot be imported into the GC VM")
548 }
549 };
550 let edge_refs = value.edge_refs();
551 let reference = alloc_value(heap, value);
552 for edge in edge_refs {
553 heap.free(edge);
554 }
555 reference
556}
557
558pub fn try_export_object(heap: &GcHeap, reference: GcRef) -> Result<Object, String> {
559 match get_value(heap, reference) {
560 Value::Integer(i) => Ok(Object::Integer(*i)),
561 Value::Boolean(b) => Ok(Object::Boolean(*b)),
562 Value::String(s) => Ok(Object::String(s.clone())),
563 Value::Null => Ok(Object::Null),
564 Value::Error(e) => Ok(Object::Error(e.clone())),
565 Value::Array(items) => {
566 let mut exported = Vec::with_capacity(items.len());
567 for item in items {
568 exported.push(Rc::new(try_export_object(heap, *item)?));
569 }
570 Ok(Object::Array(exported))
571 }
572 Value::Hash(map) => {
573 let mut exported = HashMap::with_capacity(map.len());
574 for (key, value) in map {
575 exported
576 .insert(Rc::new(key.to_object()), Rc::new(try_export_object(heap, *value)?));
577 }
578 Ok(Object::Hash(exported))
579 }
580 Value::CompiledFunction(f) => Ok(Object::CompiledFunction(Rc::new(f.clone()))),
581 Value::Closure(closure) => {
582 let func = match get_value(heap, closure.func) {
583 Value::CompiledFunction(f) => Rc::new(f.clone()),
584 _ => return Err("closure func must be compiled function".to_string()),
585 };
586 let mut free = Vec::with_capacity(closure.free.len());
587 for item in &closure.free {
588 free.push(Rc::new(try_export_object(heap, *item)?));
589 }
590 Ok(Object::ClosureObj(Closure {
591 func,
592 free,
593 }))
594 }
595 Value::Builtin(id) => {
596 let definition = BuiltIns
597 .iter()
598 .find(|definition| definition.id == *id)
599 .ok_or_else(|| "unknown builtin id".to_string())?;
600 Ok(Object::Builtin(definition.function))
601 }
602 Value::Class(_) | Value::Instance(_) | Value::BoundMethod(_) => {
603 Err("GC graph values cannot be exported as object::Object".to_string())
604 }
605 }
606}
607
608pub fn export_object(heap: &GcHeap, reference: GcRef) -> Object {
609 try_export_object(heap, reference).expect("value cannot be exported")
610}
611
612pub fn call_builtin(heap: &mut GcHeap, builtin: BuiltinId, args: &[GcRef], null: GcRef) -> GcRef {
613 match builtin {
614 BuiltinId::Len => {
615 if args.len() != 1 {
616 return alloc_value(
617 heap,
618 Value::Error(format!("builtin len expected 1 argument, got {}", args.len())),
619 );
620 }
621 match get_value(heap, args[0]) {
622 Value::String(value) => alloc_value(heap, Value::Integer(value.len() as i64)),
623 Value::Array(value) => alloc_value(heap, Value::Integer(value.len() as i64)),
624 _ => alloc_value(
625 heap,
626 Value::Error(format!(
627 "builtin len not supported for for type {}",
628 value_to_string(heap, args[0])
629 )),
630 ),
631 }
632 }
633 BuiltinId::Puts => {
634 for argument in args {
635 println!("{}", value_to_string(heap, *argument));
636 }
637 heap.dup(null)
638 }
639 BuiltinId::First | BuiltinId::Last | BuiltinId::Rest => {
640 let name = match builtin {
641 BuiltinId::First => "first",
642 BuiltinId::Last => "last",
643 BuiltinId::Rest => "rest",
644 _ => unreachable!(),
645 };
646 if args.len() != 1 {
647 return alloc_value(
648 heap,
649 Value::Error(format!(
650 "builtin {} expected 1 argument, got {}",
651 name,
652 args.len()
653 )),
654 );
655 }
656 let items = match get_value(heap, args[0]) {
657 Value::Array(items) => items.clone(),
658 _ => {
659 return alloc_value(
660 heap,
661 Value::Error(format!(
662 "builtin {} not supported for for type {}",
663 name,
664 value_to_string(heap, args[0])
665 )),
666 )
667 }
668 };
669 match builtin {
670 BuiltinId::First => items
671 .first()
672 .map(|item| heap.dup(*item))
673 .unwrap_or_else(|| heap.dup(null)),
674 BuiltinId::Last => items
675 .last()
676 .map(|item| heap.dup(*item))
677 .unwrap_or_else(|| heap.dup(null)),
678 BuiltinId::Rest => {
679 if items.is_empty() {
680 heap.dup(null)
681 } else {
682 alloc_value(heap, Value::Array(items[1..].to_vec()))
683 }
684 }
685 _ => unreachable!(),
686 }
687 }
688 BuiltinId::Push => {
689 if args.len() != 2 {
690 return alloc_value(
691 heap,
692 Value::Error(format!("builtin push expected 2 arguments, got {}", args.len())),
693 );
694 }
695 let mut items = match get_value(heap, args[0]) {
696 Value::Array(items) => items.clone(),
697 _ => {
698 return alloc_value(
699 heap,
700 Value::Error(format!(
701 "builtin push not supported for for type {}",
702 value_to_string(heap, args[0])
703 )),
704 )
705 }
706 };
707 items.push(args[1]);
708 alloc_value(heap, Value::Array(items))
709 }
710 }
711}
712
713impl fmt::Display for Value {
714 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
715 write!(f, "{:?}", self)
716 }
717}