WokML compiler code coverage report (LCOV)
Current view: top level - c/cmd - wokparse.c (source / functions) Coverage Total Hit
Test: 084deda Lines: 66.7 % 84 56
Test Date: 2026-08-10 11:39:41 Functions: 66.7 % 3 2
Legend: Lines:     hit not hit

            Line data    Source code
       1              : // wokparse -- the CLI.
       2              : //
       3              : //   wokparse FILE.wok              print the AST as an s-expression (any
       4              : //                                  parse-clean file dumps; stage-4 checks
       5              : //                                  belong to -check-only and -json)
       6              : //   wokparse -tokens FILE.wok      the token stream, with positions
       7              : //   wokparse -layout FILE.wok      the stream after the layout filter
       8              : //   wokparse -check-only FILE.wok  parse, resolve, report faults; print nothing else
       9              : //   wokparse -json FILE.wok        the same faults, one JSON object per line
      10              : //   wokparse -sexp -reorder FILE.wok
      11              : //                                  parse -> resolve -> reorder -> dump: the
      12              : //                                  s-expression carries precedence-RESOLVED
      13              : //                                  chains instead of flat ones. `-reorder`
      14              : //                                  is a modifier of `-sexp`, not a mode of
      15              : //                                  its own -- it is an error without it (see
      16              : //                                  docs/superpowers/specs/
      17              : //                                  2026-08-07-sexp-reorder-pass.md).
      18              : //
      19              : // Human diagnostics are `file:line:col: message`, which every editor and CI
      20              : // log already jumps to. A batch is printed, not the first fault.
      21              : 
      22              : // The prelude comes FIRST: it carries the POSIX feature-test macros, which
      23              : // have no effect once a system header has been read. wok_base.h hard-errors
      24              : // if it is reached too late.
      25              : #include "wok_base.h"
      26              : 
      27              : #include <stdio.h>
      28              : #include <stdlib.h>
      29              : #include <string.h>
      30              : 
      31              : #include "../wok_arena.h"
      32              : #include "../wok_ast.h"
      33              : #include "../wok_diag.h"
      34              : #include "../wok_layout.h"
      35              : #include "../wok_parse.h"
      36              : #include "../wok_reorder.h"
      37              : #include "../wok_resolve.h"
      38              : #include "../wok_sexpr.h"
      39              : #include "../wok_token.h"
      40              : 
      41              : typedef enum { M_SEXP, M_TOKENS, M_LAYOUT, M_CHECK, M_JSON } Mode;
      42              : 
      43            4 : static char *slurp(const char *path, usize *n) {
      44            4 :   FILE *fp = fopen(path, "rb");
      45            4 :   if (!fp) return nullptr;
      46            4 :   if (fseek(fp, 0, SEEK_END) != 0) {
      47            0 :     fclose(fp);
      48            0 :     return nullptr;
      49              :   }
      50            4 :   long sz = ftell(fp);
      51            4 :   if (sz < 0) {
      52            0 :     fclose(fp);
      53            0 :     return nullptr;
      54              :   }
      55            4 :   rewind(fp);
      56            4 :   char *buf = (char *)malloc((usize)sz + 1);
      57            4 :   if (!buf) {
      58            0 :     fclose(fp);
      59            0 :     return nullptr;
      60              :   }
      61            4 :   usize got = fread(buf, 1, (usize)sz, fp);
      62            4 :   buf[got] = '\0';
      63            4 :   *n = got;
      64            4 :   fclose(fp);
      65            4 :   return buf;
      66              : }
      67              : 
      68            0 : static void print_tokens(WokTokens t, const char *src, const WokDiagSink *d) {
      69            0 :   for (usize i = 0; i < t.n; i++) {
      70            0 :     u32 line, col;
      71            0 :     wok_diag_position(d, t.tok[i].off, &line, &col);
      72            0 :     const char *nm = wok_kind_name((WokKind)t.tok[i].kind);
      73            0 :     printf("%4u:%-3u %-16s", line, col, nm);
      74            0 :     if (t.tok[i].word != WW_NONE)
      75            0 :       printf(" word=%s", wok_word_text((WokWord)t.tok[i].word));
      76            0 :     if (t.tok[i].len > 0 && (WokKind)t.tok[i].kind != WT_EOF)
      77            0 :       printf(" `%.*s`", (int)t.tok[i].len, src + t.tok[i].off);
      78            0 :     if ((t.tok[i].flags & WOK_TF_FIRST_ON_LINE) != 0) printf("  [line-start]");
      79            0 :     putchar('\n');
      80              :   }
      81            0 : }
      82              : 
      83            5 : int main(int argc, char **argv) {
      84            5 :   Mode mode = M_SEXP;
      85            5 :   bool saw_sexp = false;
      86            5 :   bool reorder = false;
      87            5 :   int argi = 1;
      88           11 :   for (; argi < argc && argv[argi][0] == '-'; argi++) {
      89            6 :     if (strcmp(argv[argi], "-tokens") == 0) mode = M_TOKENS;
      90            6 :     else if (strcmp(argv[argi], "-layout") == 0) mode = M_LAYOUT;
      91            6 :     else if (strcmp(argv[argi], "-check-only") == 0) mode = M_CHECK;
      92            5 :     else if (strcmp(argv[argi], "-sexp") == 0) { mode = M_SEXP; saw_sexp = true; }
      93            3 :     else if (strcmp(argv[argi], "-json") == 0) mode = M_JSON;
      94            3 :     else if (strcmp(argv[argi], "-reorder") == 0) reorder = true;
      95              :     else {
      96            0 :       fprintf(stderr, "wokparse: unknown flag %s\n", argv[argi]);
      97            0 :       return 2;
      98              :     }
      99              :   }
     100            5 :   if (argi >= argc) {
     101            0 :     fprintf(stderr, "usage: wokparse [-tokens|-layout|-sexp[-reorder]|"
     102              :                     "-check-only|-json] FILE.wok\n");
     103            0 :     return 2;
     104              :   }
     105              :   // `-reorder` reassociates the very chains `-sexp` dumps, so it means
     106              :   // nothing under any other mode -- and nothing implicitly either: -sexp is
     107              :   // the default mode, but a bare `wokparse -reorder FILE` did not ASK for
     108              :   // the dump `-reorder` modifies, so it is refused rather than guessed. The
     109              :   // MODE check (not just "was -sexp typed") is what catches `-sexp -json
     110              :   // -reorder`: a later mode flag overrides -sexp, and -reorder would
     111              :   // otherwise silently do nothing under the mode that won.
     112            5 :   if (reorder && (!saw_sexp || mode != M_SEXP)) {
     113            1 :     fprintf(stderr, "wokparse: -reorder requires -sexp\n");
     114            1 :     return 2;
     115              :   }
     116              : 
     117              :   int status = 0;
     118            8 :   for (; argi < argc; argi++) {
     119            4 :     usize n = 0;
     120            4 :     char *src = slurp(argv[argi], &n);
     121            4 :     if (!src) {
     122            0 :       fprintf(stderr, "wokparse: cannot read %s\n", argv[argi]);
     123            0 :       status = 2;
     124            0 :       continue;
     125              :     }
     126            4 :     WokArena *a = wok_arena_new(0);
     127            4 :     WokDiagSink *d = wok_diag_new(a, argv[argi], src, n);
     128              : 
     129            4 :     WokScanResult sr = wok_scan(src, n, a, d);
     130            4 :     WokTokens lay = wok_layout(sr.tokens, a, d);
     131              : 
     132            4 :     if (mode == M_TOKENS) {
     133            0 :       print_tokens(sr.tokens, src, d);
     134            4 :     } else if (mode == M_LAYOUT) {
     135            0 :       print_tokens(lay, src, d);
     136              :     } else {
     137            4 :       WokNode *file = wok_parse(lay, src, a, d);
     138            4 :       bool parsed = wok_diag_count(d) == 0;
     139              :       // Resolution runs only over a clean parse: a damaged tree has holes
     140              :       // where the names and counts belong, and the parse fault already said
     141              :       // the true thing about them. And it runs only in the CHECK modes, or
     142              :       // under -sexp -reorder where the reorder pass needs resolve's fixity
     143              :       // table -- plain -sexp stays the dump tool, and a stage-4 fault must
     144              :       // not cost the reader the very tree the fault is about.
     145            4 :       if (parsed && (mode == M_CHECK || mode == M_JSON)) {
     146            1 :         wok_resolve(file, src, a, d);
     147            3 :       } else if (parsed && mode == M_SEXP && reorder) {
     148            2 :         WokFixTable fix = {0};
     149            2 :         wok_resolve_fix(file, src, a, d, &fix);
     150            2 :         if (wok_diag_count(d) == 0)
     151            2 :           file = (WokNode *)wok_reorder(file, src, a, d, &fix);
     152              :       }
     153            4 :       if (mode == M_SEXP && parsed && wok_diag_count(d) == 0)
     154            2 :         wok_sexpr_dump(file, src, stdout);
     155              :     }
     156              : 
     157            4 :     if (wok_diag_count(d) > 0) {
     158            2 :       if (mode == M_JSON) wok_diag_render_jsonl(d, stdout);
     159            2 :       else wok_diag_render(d, stderr);
     160              :       status = 1;
     161              :     }
     162              :     // JSON Lines: no diagnostics means no output, not an empty container.
     163              : 
     164            4 :     wok_arena_free(a);
     165            4 :     free(src);
     166              :   }
     167              :   return status;
     168              : }
        

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.