GWEB — Literate programming for Go

GWEB — Literate programming for Go

Hi everyone,

I’d like to share a project I’ve been working on: GWEB, a literate programming system for Go, modeled closely on Donald Knuth and Silvio Levy’s CWEB.

You write a single .w source file that interleaves TeX documentation with Go code, and two tools turn it into either a compilable program or a typeset document — exactly what CWEB does for C, with C replaced by Go:

CWEB GWEB purpose
ctangle gtangle extract compilable source (.go) for the machine
cweave gweave produce a typeset document (.tex → PDF) for people
  • gtangle strips the documentation, reassembles the named code sections in the order the Go compiler needs, and writes gofmt-formatted .go files.
  • gweave produces a TeX file where reserved words are bold, identifiers italic, strings typewriter, named sections linked by number, plus an automatically generated, cross-referenced index and list of refinements.

What might interest Go people specifically

A couple of design choices came out differently from CWEB precisely because this is Go:

  • Lexing for free / pretty-printing without a parser. gtangle leans on gofmt (go/format) to canonicalize the assembled program, so the emitted Go is always tidily formatted. On the weave side, gweave mirrors the source’s own spacing instead of re-deriving layout from a full Go grammar the way CWEB does for C. Because gofmt-formatted Go already encodes the grammar in its spacing, mirroring it reproduces gofmt exactly — including the tricky cases (*T vs a * b, []T vs a[i], precedence spacing like a*b + c) — with no parsing.
  • //line directives by default. The tangled Go carries //line directives, so the compiler, go vet, and panic traces report errors at .w positions rather than .go ones — the Go counterpart of CWEB’s #line. Pass -line=false to omit them.
  • Examples that lean on things C has no answer to — generics, goroutines, channels, sync.WaitGroup, first-class functions and closures, and Go 1.23 range-over-func iterators.

Self-hosting

Like CWEB, GWEB is written in itself. The literate sources in lit/web.w, tangle.w, weave.w, gtangle.w, gweave.w — are the source of truth; the .go files under internal/ and cmd/ are tangled from them (and committed, so a fresh checkout still builds without a gtangle at hand).

make tangle       # re-tangle lit/*.w back into the Go tree
make bootstrap    # tangle into a scratch tree and verify it is byte-for-byte
                  # identical to the committed sources (the fixpoint)
make selfdoc      # -> build/gweb.pdf, GWEB woven as a literate program

The bootstrap target is the self-hosting proof: a freshly built gtangle reproduces its own source exactly. make selfdoc gives you GWEB documenting itself — the same pretty-printed code, index, and cross-references it produces for any other program.

Links & feedback

I’d love feedback from anyone who’s into literate programming, or who just wants their Go code and its explanation to live in one place and stay in sync. Bug reports, ideas, and questions are all very welcome. Thanks for reading!