/* * wwdump — deterministic dump tool for ww source. * * Reads a .ww file and writes either a token stream or an AST * s-expression to stdout, byte-for-byte stable across runs. It is the * diff anchor for self-host: the C-side libwcc and the future ww-side * frontend must produce the same dump for the same input. * * wwdump -t file.ww tokens, one per line: ":: [val]" * wwdump -a file.ww AST as s-expr, one node per line * * No newlines or trailing whitespace varies by phase of the moon. If * the bytes differ, somebody changed the front end. */ #include "ww.h" #include #include #include static int slurp(const char *path, char **outbuf, u64 *outlen) { FILE *f = fopen(path, "rb"); if (f == NULL) return -1; fseek(f, 0, SEEK_END); long n = ftell(f); fseek(f, 0, SEEK_SET); if (n < 0) { fclose(f); return -1; } char *b = malloc((size_t)n + 1); if (b == NULL) { fclose(f); return -1; } if (fread(b, 1, (size_t)n, f) != (size_t)n) { free(b); fclose(f); return -1; } b[n] = '\0'; fclose(f); *outbuf = b; *outlen = (u64)n; return 0; } static int dump_tokens(const char *src, char *buf, u64 len, FILE *out) { Arena *a = newarena(); Lex l; lexinit(&l, a, src, buf, len); for (;;) { Tok t = lexnext(&l); tokprint(out, t); if (t.kind == TK_EOF || t.kind == TK_ERR) break; } int errs = l.errs; freearena(a); return errs ? 1 : 0; } static int dump_ast(const char *src, char *buf, u64 len, FILE *out) { Arena *a = newarena(); Lex l; Parser p; lexinit(&l, a, src, buf, len); parserinit(&p, a, &l); Node *file = parsefile(&p); int errs = l.errs || p.errs; if (file) astprint(out, file); freearena(a); return errs ? 1 : 0; } int main(int argc, char **argv) { int mode = 't'; /* tokens by default */ const char *src = NULL; const char *out = NULL; for (int i = 1; i < argc; i++) { const char *a = argv[i]; if (strcmp(a, "-t") == 0) mode = 't'; else if (strcmp(a, "-a") == 0) mode = 'a'; else if (strcmp(a, "-o") == 0 && i + 1 < argc) out = argv[++i]; else if (a[0] == '-') { fprintf(stderr, "wwdump: unknown flag %s\n", a); return 2; } else if (src == NULL) src = a; else { fputs("wwdump: only one input supported\n", stderr); return 2; } } if (src == NULL) { fputs("usage: wwdump [-t|-a] [-o out] file.ww\n", stderr); return 2; } char *buf; u64 len; if (slurp(src, &buf, &len) < 0) { fprintf(stderr, "wwdump: %s: cannot read\n", src); return 1; } FILE *of = stdout; if (out) { of = fopen(out, "wb"); if (of == NULL) { fprintf(stderr, "wwdump: cannot open %s\n", out); return 1; } } int rc; if (mode == 'a') rc = dump_ast(src, buf, len, of); else rc = dump_tokens(src, buf, len, of); if (of != stdout) fclose(of); free(buf); return rc; }