Skip to content

Commit ea56491

Browse files
add test printing code
from https://stackoverflow.com/a/78169673/23626926 need to test recursive nature ok
1 parent 5489a94 commit ea56491

File tree

8 files changed

+245
-8860
lines changed

8 files changed

+245
-8860
lines changed

.vscode/settings.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
{
22
"cSpell.words": [
3+
"eqcmp",
34
"tinobsy"
45
],
56
"files.associations": {

pickle.cpp

Lines changed: 77 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -70,11 +70,11 @@ void pickle::step() {
7070

7171
static bool is_primitive_type(object* x) {
7272
if (x == NULL) return true;
73-
size_t i = 0; while (primitives[i] != NULL) { if (x->type == primitives[i]) break; }
73+
size_t i = 0; while (primitives[i] != NULL) { if (x->type == primitives[i]) break; i++; }
7474
return primitives[i] != NULL;
7575
}
7676

77-
int prim_cmp(object* a, object* b) {
77+
int eqcmp(object* a, object* b) {
7878
if (a == b) return 0;
7979
if (a == NULL) return -1;
8080
if (b == NULL) return 1;
@@ -88,15 +88,15 @@ int prim_cmp(object* a, object* b) {
8888
object* assoc(object* list, object* key) {
8989
for (; list; list = cdr(list)) {
9090
object* pair = car(list);
91-
if (!prim_cmp(key, car(pair))) return pair;
91+
if (!eqcmp(key, car(pair))) return pair;
9292
}
9393
return NULL;
9494
}
9595

9696
object* delassoc(object** list, object* key) {
9797
for (; *list; list = &cdr(*list)) {
9898
object* pair = car(*list);
99-
if (!prim_cmp(key, car(pair))) {
99+
if (!eqcmp(key, car(pair))) {
100100
*list = cdr(*list);
101101
return pair;
102102
}
@@ -171,37 +171,90 @@ void splice_match(pickle* vm, object* args, object* env, object* cont, object* f
171171
// TODO(sm);
172172
}
173173

174-
static void count_pointers() {
174+
static void make_refs_list(pickle* vm, object* obj, object** alist) {
175+
again:
176+
DBG();
177+
if (obj == NULL || obj->type != &cons_type) return;
178+
object* entry = assoc(*alist, obj);
179+
if (entry) {
180+
cdr(entry) = vm->make_integer(2);
181+
return;
182+
}
183+
vm->push(vm->cons(obj, vm->make_integer(1)), *alist);
184+
make_refs_list(vm, cdr(obj), alist);
185+
obj = cdr(obj);
186+
goto again;
187+
}
175188

189+
// returns zero if the object doesn't need a #N# marker
190+
// otherwise returns N (negative if not first time)
191+
static int64_t reffed(pickle* vm, object* obj, object* alist, int64_t* counter) {
192+
object* entry = assoc(alist, obj);
193+
if (entry) {
194+
int64_t value = vm->unwrap_integer(cdr(entry));
195+
if (value < 0) {
196+
// seen already
197+
return value;
198+
}
199+
if (value == 2) {
200+
// object with shared structure but no id yet
201+
// assign id
202+
int64_t my_id = *counter++;
203+
// store entry
204+
cdr(entry) = vm->make_integer(-my_id);
205+
return my_id;
206+
}
207+
}
208+
return 0;
176209
}
177210

178-
void dump(object* x) {
179-
if (x == NULL) printf("NULL");
180-
else if (x->type == &cons_type) {
181-
// Try to print a Scheme list
211+
static void print_with_refs(pickle* vm, object* obj, object* alist, int64_t* counter) {
212+
if (obj == NULL) {
213+
printf("NULL");
214+
return;
215+
}
216+
#define PRINTTYPE(t, f, fmt) else if (obj->type == t) printf(fmt, obj->f)
217+
PRINTTYPE(&string_type, as_chars, "\"%s\"");
218+
PRINTTYPE(&symbol_type, as_chars, strchr(obj->as_chars, ' ') ? "#|%s|" : "%s");
219+
PRINTTYPE(&integer_type, as_big_int, "%" PRId64);
220+
PRINTTYPE(&float_type, as_double, "%lg");
221+
PRINTTYPE(&c_function_type, as_ptr, "<function %p>");
222+
PRINTTYPE(NULL, as_ptr, "<garbage %p>");
223+
#undef PRINTTYPE
224+
else if (obj->type != &cons_type) printf("<%s:%p>", obj->type->name, obj->as_ptr);
225+
else {
226+
// it's a cons
227+
// test if it's in the table
228+
int64_t ref = reffed(vm, obj, alist, counter);
229+
if (ref < 0) {
230+
printf("#%" PRId64 "#", -ref);
231+
return;
232+
}
233+
if (ref) {
234+
printf("#%" PRId64 "=", ref);
235+
}
236+
// now print the object
182237
putchar('(');
183238
for (;;) {
184-
dump(car(x));
185-
x = cdr(x);
186-
if (x && x->type == &cons_type) putchar(' ');
239+
print_with_refs(vm, car(obj), alist, counter);
240+
obj = cdr(obj);
241+
if (reffed(vm, obj, alist, counter)) break;
242+
if (obj && obj->type == &cons_type) putchar(' ');
187243
else break;
188244
}
189-
if (x) {
245+
if (obj) {
190246
printf(" . ");
191-
dump(x);
247+
print_with_refs(vm, obj, alist, counter);
192248
}
193249
putchar(')');
194250
}
195-
else {
196-
#define PRINTTYPE(t, f, fmt) if (x->type == &t) printf(fmt, x->f)
197-
PRINTTYPE(string_type, as_chars, "\"%s\"");
198-
else PRINTTYPE(symbol_type, as_chars, strchr(x->as_chars, ' ') ? "#|%s|" : "%s");
199-
else PRINTTYPE(integer_type, as_big_int, "%" PRId64);
200-
else PRINTTYPE(float_type, as_double, "%lg");
201-
else PRINTTYPE(c_function_type, as_ptr, "<function %p>");
202-
else printf("<%s:%p>", x->type->name, x->as_ptr);
203-
#undef PRINTTYPE
204-
}
251+
}
252+
253+
void pickle::dump(object* obj) {
254+
object* alist = NULL;
255+
int64_t counter = 0;
256+
make_refs_list(this, obj, &alist);
257+
print_with_refs(this, obj, alist, &counter);
205258
}
206259

207260
}

pickle.hpp

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -21,17 +21,12 @@ class pickle;
2121

2222
typedef object* (*func_ptr)(pickle* vm);
2323

24-
extern const object_type metadata_type;
2524
extern const object_type cons_type;
26-
extern const object_type partial_type;
2725
extern const object_type c_function_type;
2826
extern const object_type string_type;
2927
extern const object_type symbol_type;
30-
extern const object_type stream_type;
31-
extern const object_type error_type;
3228
extern const object_type integer_type;
3329
extern const object_type float_type;
34-
extern const object_type list_type;
3530

3631
class pickle : public tinobsy::vm {
3732
public:
@@ -91,17 +86,28 @@ class pickle : public tinobsy::vm {
9186
o->as_big_int = x;
9287
return o;
9388
}
89+
inline int64_t unwrap_integer(object* x) {
90+
ASSERT(x != NULL && x->type == &integer_type);
91+
return x->as_big_int;
92+
}
9493
inline object* make_float(double x) {
9594
INTERN(this, int64_t, &float_type, x);
9695
object* o = this->alloc(&float_type);
9796
o->as_double = x;
9897
return o;
9998
}
99+
inline double unwrap_double(object* x) {
100+
ASSERT(x != NULL && x->type == &float_type);
101+
return x->as_double;
102+
}
100103

101104

102105
void step();
103106

104107

108+
void dump(object*);
109+
110+
105111
private:
106112
void mark_globals();
107113
};
@@ -110,7 +116,7 @@ class pickle : public tinobsy::vm {
110116
// Helper functions.
111117

112118
// Returns 0 if equal, or nonzero if not equal. Doesn't work on compound or user types
113-
int prim_cmp(object*, object*);
119+
int eqcmp(object*, object*);
114120
// Returns the pair in the assoc list that has the same key, or NULL if not found.
115121
object* assoc(object*, object*);
116122
// Removes the key/value pair from the list and returns it, or returns NULL if the pair never existed.
@@ -121,7 +127,6 @@ void eval(pickle* vm, object* args, object* env, object* cont, object* fail_cont
121127
void splice_match(pickle* vm, object* args, object* env, object* cont, object* fail_cont);
122128

123129
// Chokes on self-referential objects -- you have been warned
124-
void dump(object*);
125130

126131

127132
}

pickle_test.cpp

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -21,15 +21,13 @@ void start_catch_segfault() {
2121
int main() {
2222
start_catch_segfault();
2323
pickle::pickle vm;
24-
for (size_t i = 0; i < 100; i++) {
25-
vm.push_instruction(vm.make_symbol("foo"));
26-
vm.push_instruction(vm.make_symbol("bar"), vm.make_symbol("error"));
27-
vm.push_instruction(vm.make_symbol("baz"));
28-
vm.push_instruction(vm.make_symbol("baz"), vm.make_symbol("test long symbol with spaces"));
29-
vm.push_instruction(vm.make_symbol("baz"));
30-
vm.push_instruction(vm.make_symbol("baz"));
31-
}
32-
pickle::dump(vm.instruction_stack);
24+
vm.push_instruction(vm.make_symbol("foo"));
25+
vm.push_instruction(vm.make_symbol("bar"), vm.make_symbol("error"));
26+
vm.push_instruction(vm.make_symbol("baz"));
27+
vm.push_instruction(vm.make_symbol("baz"), vm.make_symbol("test long symbol with spaces"));
28+
vm.push_instruction(vm.make_symbol("baz"));
29+
vm.push_instruction(vm.make_symbol("baz"));
30+
vm.dump(vm.instruction_stack);
3331
putchar('\n');
3432
vm.gc();
3533
printf("all done -- cleaning up\n");

0 commit comments

Comments
 (0)