Line data Source code
1 : // Everything in this file is derived from the schema in wok_ast.h. If you are
2 : // adding a node, you are in the wrong file.
3 :
4 : #include "wok_ast.h"
5 :
6 : #include <string.h>
7 :
8 : // A sentinel keeps the array non-empty for nodes with no fields; nfields comes
9 : // from the slot-index enum, so the sentinel is never visited.
10 : #define WOK_FIELD_DESC(T, cls, name, fam) {#name, WFC_##cls, WFAM_##fam},
11 : #define WOK_DECLARE_FIELDS(T, fam) \
12 : static const WokFieldDesc T##_field_desc[] = { \
13 : T##_FIELDS(WOK_FIELD_DESC, T){nullptr, WFC_NODE, WFAM_NONE}};
14 : WOK_NODES(WOK_DECLARE_FIELDS)
15 : #undef WOK_DECLARE_FIELDS
16 :
17 : const WokNodeDesc wok_node_desc[WOK_TAG_COUNT] = {
18 : #define WOK_NODE_DESC(T, fam) \
19 : [T] = {#T, T##_field_desc, T##__NSLOTS, WFAM_##fam},
20 : WOK_NODES(WOK_NODE_DESC)
21 : #undef WOK_NODE_DESC
22 : };
23 :
24 : static const char *const family_name[WOK_FAMILY_COUNT] = {
25 : #define WOK_X(f) [WFAM_##f] = #f,
26 : WOK_FAMILIES(WOK_X)
27 : #undef WOK_X
28 : };
29 :
30 6 : const char *wok_family_name(WokFamily f) {
31 6 : return f < WOK_FAMILY_COUNT ? family_name[f] : "?";
32 : }
33 :
34 : static const u16 node_slots[WOK_TAG_COUNT] = {
35 : #define WOK_NODE_SLOTS(T, fam) [T] = T##__NSLOTS,
36 : WOK_NODES(WOK_NODE_SLOTS)
37 : #undef WOK_NODE_SLOTS
38 : };
39 :
40 1035918 : WokNode *wok_node(WokArena *a, WokTag tag, u32 off, u32 len) {
41 1035918 : u16 n = node_slots[tag];
42 1035918 : usize bytes = sizeof(WokNode) + (usize)n * sizeof(WokSlot);
43 1035918 : WokNode *node = wok_arena_alloc(a, bytes, alignof(WokNode));
44 : // Only the SLOTS are zeroed: the 16 header bytes are all assigned right
45 : // below (the static_asserts in wok_ast.h pin that the header is exactly
46 : // those five fields), so zeroing them first was pure double-writing.
47 1035918 : memset(node->slot, 0, (usize)n * sizeof(WokSlot));
48 1035918 : node->tag = (u16)tag;
49 1035918 : node->nslots = n;
50 1035918 : node->trivia = 0; // no comments until wok_trivia_attach says otherwise
51 1035918 : node->off = off;
52 1035918 : node->len = len;
53 1035918 : return node;
54 : }
55 :
56 42883 : WokSeq wok_seq(WokArena *a, WokNode *const *restrict items, u32 n) {
57 42883 : if (n == 0) return wok_seq_empty();
58 42680 : WokNode **base = WOK_NEW_N(a, WokNode *, (usize)n + 1);
59 42680 : base[0] = (WokNode *)(uptr)n; // the inline count; never dereferenced
60 42680 : memcpy(base + 1, items, (usize)n * sizeof *base);
61 42680 : return (WokSeq){.items = base + 1, .n = n};
62 : }
63 :
64 369251 : void wok_buf_init(WokNodeBuf *b, WokArena *a) {
65 369251 : *b = (WokNodeBuf){.raw = nullptr, .raw_n = 0, .cap = 0, .arena = a};
66 369251 : }
67 :
68 391051 : void wok_buf_push(WokNodeBuf *b, WokNode *node) {
69 391051 : if (b->raw_n == 0) b->raw_n = 1; // index 0 is the inline count
70 391051 : if (b->raw_n >= b->cap) {
71 256421 : u32 next = b->cap ? b->cap * 2 : 8;
72 256421 : WokNode **grown = WOK_NEW_N(b->arena, WokNode *, next);
73 256421 : if (b->raw_n > 1) memcpy(grown, b->raw, (usize)b->raw_n * sizeof *grown);
74 256421 : b->raw = grown;
75 256421 : b->cap = next;
76 : }
77 391051 : b->raw[b->raw_n++] = node;
78 391051 : }
79 :
80 308352 : WokSeq wok_buf_seq(WokNodeBuf *b) {
81 : // Zero copy: the buffer already lives in the arena and index 0 was reserved
82 : // by the first push, so it becomes the inline count in place.
83 308352 : u32 count = wok_buf_count(b);
84 308352 : if (count == 0) return wok_seq_empty();
85 243587 : b->raw[0] = (WokNode *)(uptr)count;
86 243587 : return (WokSeq){.items = b->raw + 1, .n = count};
87 : }
88 :
89 : // ---------------------------------------------------------------- coverage
90 : //
91 : // Single-threaded by design: this is a test instrument, and a batch parse
92 : // does not enable it. Making it atomic would buy nothing and cost the hot
93 : // path.
94 :
95 : bool wok_cover_bits[WOK_TAG_COUNT];
96 : static WokTag cover_missing_buf[WOK_TAG_COUNT];
97 :
98 1 : void wok_cover_reset(void) { memset(wok_cover_bits, 0, sizeof wok_cover_bits); }
99 0 : bool wok_cover_seen(WokTag t) { return wok_cover_bits[t]; }
100 :
101 1 : usize wok_cover_missing(const WokTag **out) {
102 1 : usize n = 0;
103 85 : for (int t = 0; t < WOK_TAG_COUNT; t++)
104 84 : if (!wok_cover_bits[t]) cover_missing_buf[n++] = (WokTag)t;
105 1 : *out = cover_missing_buf;
106 1 : return n;
107 : }
|