summaryrefslogtreecommitdiff
path: root/src/runtime/dump.c
blob: 3d5ec9c2a97f11d1f794fa5faaacd7c867509c48 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
#include <lcq/pit/runtime/dump.h>

#define CHECK_BUF if (buf >= end) { return buf - start; }
#define CHECK_BUF_LABEL(label) if (buf >= end) { goto label; }
i64 pit_dump(pit_runtime *rt, char *buf, i64 len, pit_value v, bool readable) {
    pit_value_heavy *h = NULL;
    if (len <= 0) return 0;
    switch (pit_value_sort(v)) {
    case PIT_VALUE_SORT_DOUBLE:
        #ifndef PIT_NO_DOUBLE
        return pit_libc_string_snprintf(buf, (size_t) len, "%lf", pit_value_as_double(rt, v));
        #else
        return pit_string_snprintf(buf, (size_t) len, "<unsupported double>");
        #endif
    case PIT_VALUE_SORT_INTEGER:
        return pit_libc_string_snprintf(buf, (size_t) len, "%ld", pit_value_as_integer(rt, v));
    case PIT_VALUE_SORT_SYMBOL: {
        pit_symtab_entry *ent = pit_symtab_lookup(rt, v);
        if (ent
            && pit_value_sort(ent->name) == PIT_VALUE_SORT_REF
            && (h = pit_value_ref_deref(rt, pit_value_as_ref(rt, ent->name)))
        ) {
            i64 i = 0;
            for (; i < h->in.bytes.len && i < len - 1; ++i) {
                buf[i] = (char) h->in.bytes.data[i];
            }
            return i;
        } else {
            return pit_libc_string_snprintf(buf, (size_t) len, "<broken symbol %ld>", pit_value_as_symbol(rt, v));
        }
    }
    case PIT_VALUE_SORT_REF: {
        pit_ref r = pit_value_as_ref(rt, v);
        char *end = buf + len;
        char *start = buf;
        h = pit_value_ref_deref(rt, r);
        if (!h) pit_libc_string_snprintf(buf, (size_t) len, "<ref %ld>", r);
        else {
            switch (h->hsort) {
            case PIT_VALUE_HEAVY_SORT_CELL: {
                CHECK_BUF; *(buf++) = '{';
                CHECK_BUF; buf += pit_dump(rt, buf, end - buf, pit_value_cons_car(rt, h->in.cell), readable);
                CHECK_BUF; *(buf++) = '}';
                return buf - start;
            }
            case PIT_VALUE_HEAVY_SORT_CONS: {
                pit_value cur = v;
                CHECK_BUF_LABEL(list_end);
                do {
                    if (pit_value_is_cons(rt, cur)) {
                        CHECK_BUF_LABEL(list_end); *(buf++) = ' ';
                        CHECK_BUF_LABEL(list_end); buf += pit_dump(rt, buf, end - buf, pit_value_cons_car(rt, cur), readable);
                    } else {
                        CHECK_BUF_LABEL(list_end); buf += pit_libc_string_snprintf(buf, (size_t) (end - buf), " . ");
                        CHECK_BUF_LABEL(list_end); buf += pit_dump(rt, buf, end - buf, cur, readable);
                    }
                } while (!pit_value_eq((cur = pit_value_cons_cdr(rt, cur)), PIT_NIL));
                CHECK_BUF_LABEL(list_end); *(buf++) = ')';
                list_end:
                *start = '(';
                return buf - start;
            }
            case PIT_VALUE_HEAVY_SORT_ARRAY: {
                i64 i = 0;
                CHECK_BUF_LABEL(array_end);
                if (h->in.array.len == 0) {
                    CHECK_BUF_LABEL(array_end); *(buf++) = '[';
                } else for (; i < h->in.array.len; ++i) {
                    CHECK_BUF_LABEL(array_end); *(buf++) = ' ';
                    CHECK_BUF_LABEL(array_end); buf += pit_dump(rt, buf, end - buf, h->in.array.data[i], readable);
                }
                CHECK_BUF_LABEL(array_end); *(buf++) = ']';
                array_end:
                *start = '[';
                return buf - start;
            }
            case PIT_VALUE_HEAVY_SORT_BYTES: {
                i64 i = 0;
                if (readable) { CHECK_BUF; buf[i++] = '"'; }
                i64 maxlen = len - i;
                for (i64 j = 0; i < maxlen && j < h->in.bytes.len;) {
                    if (buf[i - 1] != '\\' && (h->in.bytes.data[j] == '\\' || h->in.bytes.data[j] == '"')) {
                        CHECK_BUF; buf[i++] = '\\';
                    }
                    else {
                        CHECK_BUF; buf[i++] = (char) h->in.bytes.data[j++];
                    }
                }
                if (readable && i < len - 1) buf[i++] = '"';
                return i;
            }
            default:
                return pit_libc_string_snprintf(buf, (size_t) len, "<ref %ld>", r);
            }
        }
        break;
    }
    }
    return 0;
}