Skip to content

Add test corpus, oracle tooling, and the implementation loop - #2

Merged
kyleconroy merged 1 commit into
mainfrom
claude/go-sqlite-sql-parser-r8o75v
Jul 30, 2026
Merged

Add test corpus, oracle tooling, and the implementation loop#2
kyleconroy merged 1 commit into
mainfrom
claude/go-sqlite-sql-parser-r8o75v

Conversation

@kyleconroy

Copy link
Copy Markdown
Contributor

Builds the conformance corpus and development workflow ahead of parser implementation (PLAN.md milestones 1–2 groundwork).

The corpus

4,685 cases across 69 files (~1.2 MB in parser/testdata/), extracted from SQLite's own test suite: parser1, tokenize, keyword1, select1selectH, expr/expr2, inin5, between, with*, window1windowE/windowerr, alter*, altertab*, alterdropcol*, trigger1, upsert1upsert5, returning1, and the e_select/e_expr/e_createtable/e_insert/e_update/e_delete evidence files.

Every case stores the raw per-statement verdict from a real SQLite build: ok, or result code + byte offset + exact error message. The harness derives the requirement from it: meyer must reject with the identical message when SQLite's parser rejected (near "X": syntax error, unrecognized token: "X", incomplete input), and must accept everything else — including statements that failed semantically (no such table), since those parsed fine. All 4,685 cases start as todo in metadata sidecars.

Tooling

  • cmd/regenerate-parse — downloads the pinned SQLite 3.53.4 release (SHA-256-verified, cached in gitignored .sqlite/), compiles an embedded C oracle against the amalgamation, extracts literal SQL from the TCL scripts (do_execsql_test, do_catchsql_test, and single-call do_test { catchsql {…} } bodies), and writes corpus + merged metadata. The oracle splits statements shell-style via sqlite3_complete and prepares each independently against :memory: with sqlite3_prepare_v2 — nothing executes, so cases are order-independent. Extraction is conservative and loud: of 5,643 blocks found, 958 skipped (TCL substitution / non-literal bodies), every skip counted in the output.
  • cmd/next-test — picks the next todo case (file with fewest remaining todos first).
  • parser/parser_test.go — corpus harness: skips todo cases by default; with -check-parse, re-runs them and removes newly passing ones from the metadata (logged as PARSE PASSES NOW), so progress commits alongside code.
  • internal/testfile (corpus format + classification policy) and internal/tclextract (TCL extraction), both with unit tests.

Scaffolding

  • parser and ast API skeletons: the final Parse(ctx, io.Reader) ([]ast.Stmt, error) signature and parser.Error{Message, Offset}; every input currently errors, which is what keeps all corpus cases todo.
  • CLAUDE.md (workflow + rules: never hand-edit corpus files, zero dependencies, no parser generators), parser/testdata/README.md (provenance + pinned hashes, public-domain note), MIT LICENSE, updated README.md, GitHub Actions CI (go build / go vet / go test -race).

Notes

  • Grammar-action errors (e.g. syntax error after column name "b") are currently classified as semantic, so meyer is permitted to accept them for now. The pattern list lives in internal/testfile and can tighten later without regenerating, because the corpus stores raw oracle output.
  • go build ./..., go vet ./..., and go test ./... are green (corpus subtests all skip as todo).

The implementation loop is ready: go run ./cmd/next-test → implement → go test ./parser -check-parse.

🤖 Generated with Claude Code

https://claude.ai/code/session_014vjRSyzyQ5AGtfH8DZYcfc


Generated by Claude Code

Build the conformance corpus and workflow ahead of parser implementation:

- cmd/regenerate-parse: extracts literal SQL from SQLite's TCL test suite
  (do_execsql_test, do_catchsql_test, and single-call do_test bodies) and
  records ground truth from a real SQLite build — a small embedded C oracle
  compiled against the pinned 3.53.4 amalgamation that splits statements
  shell-style and prepares each one against :memory: without executing.
  Downloads are pinned by SHA-256 and cached in .sqlite/ (gitignored).
- parser/testdata: 4,685 cases across 69 corpus files with raw
  per-statement oracle results (ok, or exact error message and offset),
  plus metadata sidecars marking every case as todo.
- internal/testfile: corpus file format, metadata sidecars, and the
  accept/reject classification policy (syntax-family errors must be
  reproduced verbatim; semantic prepare errors mean the parse succeeded).
- internal/tclextract: conservative TCL extraction; anything it cannot take
  verbatim is counted and skipped, never guessed at.
- cmd/next-test: picks the next todo case to implement.
- parser, ast: API skeletons (Parse, parser.Error, Node/Stmt/Expr) so the
  harness compiles; parser/parser_test.go runs the corpus, skipping todo
  cases by default and clearing them from metadata under -check-parse.
- CLAUDE.md, README.md, testdata provenance README, MIT LICENSE, CI.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014vjRSyzyQ5AGtfH8DZYcfc
@kyleconroy
kyleconroy merged commit 940671c into main Jul 30, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants