@@ -413,8 +413,159 @@ object* parse(pvm* vm, object* cookie, object* inst_type) {
413
413
return errors ? vm->sym (" error" ) : nil;
414
414
}
415
415
416
+ // ------------------------- HASHMAPS (OBJECTS) -------------------------------
417
+
418
+ // Returns the found node or nil if the hash is not found.
419
+ static object* hashmap_find (pvm* vm, object* map, uint64_t hash) {
420
+ // Each hashmap node is a 4-cons tree ((hash . (key . value)) . (left . right))
421
+ uint64_t hh = hash;
422
+ DBG (" Searching hashmap for hash %" PRId64 " {" , hash);
423
+ recurse:
424
+ if (!map) {
425
+ DBG (" Node is nil -- not found. }" );
426
+ return nil;
427
+ }
428
+ object* hash_pair = car (map);
429
+ if (hash_pair) {
430
+ printf (" hash_pair = " );
431
+ vm->dump (hash_pair);
432
+ putchar (' ' );
433
+ vm->dump (car (hash_pair));
434
+ int64_t this_hash = vm->intof (car (hash_pair));
435
+ if (this_hash == hash) {
436
+ DBG (" Found matching key for hash %" PRId64, hash);
437
+ return map;
438
+ }
439
+ }
440
+ bool ll = hh & 1 ;
441
+ object* children = cdr (map);
442
+ if (!children) {
443
+ DBG (" Reached node with no children -- Not found. }" );
444
+ return nil;
445
+ }
446
+ if (ll) map = car (children);
447
+ else map = cdr (children);
448
+ hh >>= 1 ;
449
+ DBG (" Recursing on %s" , ll ? " LEFT" : " RIGHT" );
450
+ goto recurse;
451
+ }
452
+
453
+ // Returns the new node, *map is updated to point to the root node if it changed.
454
+ static object* hashmap_set (pvm* vm, object** map, object* key, uint64_t hash, object* val) {
455
+ DBG (" Setting hash %" PRId64 " on hashmap. {" , hash);
456
+ uint64_t hh = hash;
457
+ recurse:
458
+ if (*map == nil) {
459
+ DBG (" Tree is terminated -- add new node. }" );
460
+ *map = vm->cons (vm->cons (vm->integer (hash), vm->cons (key, val)), nil);
461
+ return *map;
462
+ }
463
+ // Map is not empty at this level. Check to see if it is a free node or the target node.
464
+ object* hash_pair = car (*map);
465
+ bool ll = hh & 1 ;
466
+ object* children = cdr (*map);
467
+ if (!hash_pair) {
468
+ DBG (" Found tombstoned node. Inserting key." );
469
+ car (*map) = vm->cons (vm->integer (hash), vm->cons (key, val));
470
+ goto killshadow;
471
+ } else {
472
+ // Check if the hashes match
473
+ int64_t z = vm->intof (car (hash_pair));
474
+ if (z == hash) {
475
+ DBG (" Found matching node. Re-setting it. }" );
476
+ if (!cdr (hash_pair)) cdr (hash_pair) = vm->cons (nil, nil);
477
+ car (cdr (hash_pair)) = key;
478
+ cdr (cdr (hash_pair)) = val;
479
+ return *map;
480
+ }
481
+ }
482
+ if (!children) {
483
+ DBG (" Reached node with no children cons. Adding children cons." );
484
+ cdr (*map) = children = vm->cons (nil, nil);
485
+ }
486
+ if (ll) map = &car (children);
487
+ else map = &cdr (children);
488
+ hh >>= 1 ;
489
+ DBG (" Recursing on %s" , ll ? " LEFT" : " RIGHT" );
490
+ goto recurse;
491
+ // -------------
492
+ killshadow:
493
+ DBG (" Now searching for shadower nodes in search path and killing them." );
494
+ if (ll) map = &car (children);
495
+ else map = &cdr (children);
496
+ hh >>= 1 ;
497
+ DBG (" Continuing on %s" , ll ? " LEFT" : " RIGHT" );
498
+ hash_pair = car (*map);
499
+ ll = hh & 1 ;
500
+ children = cdr (*map);
501
+ if (hash_pair) {
502
+ int64_t bad = vm->intof (car (hash_pair));
503
+ if (bad == hash) {
504
+ DBG (" Found shadowing node, killing it." );
505
+ car (*map) = nil;
506
+ }
507
+ }
508
+ if (!children) {
509
+ DBG (" Reached node with no children. Stopping }" );
510
+ return *map;
511
+ }
512
+ if (ll) map = &car (children);
513
+ else map = &cdr (children);
514
+ hh >>= 1 ;
515
+ DBG (" Shadow recursing on %s" , ll ? " LEFT" : " RIGHT" );
516
+ goto killshadow;
517
+ }
518
+
519
+ object* pvm::get_property (object* obj, uint64_t hash, bool recurse) {
520
+ // Nil has no properties
521
+ if (!obj) return nil;
522
+ if (recurse) {
523
+ // Try to find it directly.
524
+ object* val = this ->get_property (obj, hash, false );
525
+ if (val) return val;
526
+ // Not found, traverse prototypes list.
527
+ for (object* p = car (obj); p; p = cdr (p)) {
528
+ val = this ->get_property (car (p), hash, true );
529
+ if (val) return val;
530
+ }
531
+ return nil;
532
+ }
533
+ // Check if it is an object-object (primitives have no own properties)
534
+ if (obj->type != &obj_type) return nil;
535
+ // Search the hashmap.
536
+ object* hashmap = cdr (obj);
537
+ object* node = hashmap_find (this , obj, hash);
538
+ if (node) return cdr (car (node));
539
+ return nil;
540
+ }
541
+
542
+ bool pvm::set_property (object* obj, object* val, uint64_t hash, object* value) {
543
+ // Nil has no properties
544
+ if (!obj) return false ;
545
+ // Check if it is an object-object (primitives have no own properties)
546
+ if (obj->type != &obj_type) return false ;
547
+ hashmap_set (this , &cdr (obj), val, hash, value);
548
+ return true ;
549
+ }
550
+
551
+ bool pvm::remove_property (object* obj, uint64_t hash) {
552
+ // Nil has no properties
553
+ if (!obj) return false ;
554
+ // Check if it is an object-object (primitives have no own properties)
555
+ if (obj->type != &obj_type) return false ;
556
+ bool had = hashmap_find (this , cdr (obj), hash) != nil;
557
+ // Try to set the node to nil, which will kill the shadow references
558
+ object* node = hashmap_set (this , &cdr (obj), nil, hash, nil);
559
+ // Then kill this node too
560
+ ASSERT (node, " hashmap_set() failed" );
561
+ car (node) = nil;
562
+ return had;
563
+ }
564
+
565
+ // ------------------ PATTERN MATCHING -----------------------------
566
+
416
567
static object* get_best_match (pvm* vm, object* ast, object** env) {
417
- return NULL ;
568
+ return nil ;
418
569
}
419
570
420
571
// Eval(list) ::= apply_first_pattern(list), then eval(remaining list), else list if no patterns match
@@ -448,24 +599,27 @@ object* eval(pvm* vm, object* cookie, object* inst_type) {
448
599
// // No matches so return unchanged
449
600
// vm->set_retval(vm->list(1, ast), env, cont, fail_cont);
450
601
// }
602
+ return nil;
451
603
}
452
604
453
605
object* splice_match (pvm* vm, object* cookie, object* inst_type) {
454
606
// TODO(sm);
607
+ return nil;
455
608
}
456
609
457
610
// ------------------- Circular-reference-proof object dumper -----------------------
458
611
// ---------- (based on https://stackoverflow.com/a/78169673/23626926) --------------
459
612
460
613
static void make_refs_list (pvm* vm, object* obj, object** alist) {
461
614
again:
462
- if (obj == NULL || obj->type != &cons_type) return ;
615
+ if (obj == NULL || ( obj->type != &cons_type && obj-> type != &obj_type) ) return ;
463
616
object* entry = assoc (*alist, obj);
464
617
if (entry) {
465
618
cdr (entry) = vm->integer (2 );
466
619
return ;
467
620
}
468
621
vm->push (vm->cons (obj, vm->integer (1 )), *alist);
622
+ if (obj->type == &obj_type) return ; // hashmaps are guaranteed non disjoint, i guess
469
623
make_refs_list (vm, car (obj), alist);
470
624
obj = cdr (obj);
471
625
goto again;
@@ -493,6 +647,22 @@ static int64_t reffed(pvm* vm, object* obj, object* alist, int64_t* counter) {
493
647
return 0 ;
494
648
}
495
649
650
+ static void print_with_refs (pvm*, object*, object*, int64_t *);
651
+
652
+ static void print_hashmap (pvm* vm, object* node, object* alist, int64_t * counter) {
653
+ recur:
654
+ if (node) {
655
+ print_with_refs (vm, car (cdr (car (node))), alist, counter);
656
+ printf (" : " );
657
+ print_with_refs (vm, cdr (cdr (car (node))), alist, counter);
658
+ printf (" , " );
659
+ if (!cdr (node)) return ;
660
+ print_hashmap (vm, car (cdr (node)), alist, counter);
661
+ node = cdr (cdr (node));
662
+ goto recur;
663
+ }
664
+ }
665
+
496
666
static void print_with_refs (pvm* vm, object* obj, object* alist, int64_t * counter) {
497
667
if (obj == nil) {
498
668
printf (" NIL" );
@@ -517,8 +687,7 @@ static void print_with_refs(pvm* vm, object* obj, object* alist, int64_t* counte
517
687
PRINTTYPE (&c_function_type, as_ptr, " <function %p>" );
518
688
PRINTTYPE (NULL , as_ptr, " <garbage %p>" );
519
689
#undef PRINTTYPE
520
- else if (obj->type != &cons_type) printf (" <%s:%p>" , obj->type ->name , obj->as_ptr );
521
- else {
690
+ else if (obj->type == &cons_type) {
522
691
// it's a cons
523
692
// test if it's in the table
524
693
int64_t ref = reffed (vm, obj, alist, counter);
@@ -552,6 +721,21 @@ static void print_with_refs(pvm* vm, object* obj, object* alist, int64_t* counte
552
721
}
553
722
putchar (' )' );
554
723
}
724
+ else if (obj->type == &obj_type) {
725
+ // Try to find the class name
726
+ // TODO: String/symbol/int hash.
727
+ const char * nm = " object" ;
728
+ // if (car(obj) && !cdr(car(obj)) && car(car(obj))) {
729
+ // object* super = car(car(obj));
730
+ // object* name = vm->get_property(obj, vm->static_hash(vm->string("__name__")));
731
+ // if (name->type == &symbol_type) nm = vm->stringof(name);
732
+ // }
733
+ printf (" %s { " , nm);
734
+ print_hashmap (vm, cdr (obj), alist, counter);
735
+ putchar (' }' );
736
+ }
737
+ else printf (" <%s:%p>" , obj->type ->name , obj->as_ptr );
738
+
555
739
}
556
740
557
741
void pvm::dump (object* obj) {
@@ -561,4 +745,10 @@ void pvm::dump(object* obj) {
561
745
print_with_refs (this , obj, alist, &counter);
562
746
}
563
747
748
+
749
+ size_t pvm::gc () {
750
+ DBG (" TODO: garbage collect all of the hashmaps" );
751
+ return tinobsy::vm::gc ();
752
+ }
753
+
564
754
}
0 commit comments