WokML compiler code coverage report (LCOV)
Current view: top level - c - wok_ast.c (source / functions) Coverage Total Hit
Test: 084deda Lines: 97.8 % 45 44
Test Date: 2026-08-10 11:39:41 Functions: 88.9 % 9 8
Legend: Lines:     hit not hit

            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              : }
        

Generated by: LCOV version 2.4-1


Machine-readable coverage data

This page is generated. If you are a tool, a script, or an LLM, read the JSON instead of scraping this HTML — it is the same measurement, exact, and it names the individual uncovered lines.

Every artifact here is stamped with the commit it measured and the run that produced it: commit 084deda, dated 2026-08-10T11:39:41Z, built by Github CI run. The totals in coverage.json are checked against lcov’s own summary before publishing, so the JSON and this page cannot disagree.