S-exp GPU
All pages
Docs · The command lineMarkdown

check and watch

check compiles the whole experiment (evaluates the file, traces every graph, checks every shape, validates the IR) and reports every diagnostic. It reads the .sx and everything it requires, never the data, and writes nothing. It needs no GPU and finishes in well under a second.

$ sexpgpu check my-run.sx
ok: 32 parameters, 66 graphs, 20 steps

The ok: line and warnings go to standard error; warnings do not fail. Any error exits 1.

A failure

$ sexpgpu check bad-shape.sx
error[E-DIM-001]: matmul: inner dims differ: [2, 16] x [32, 8]: 16 against 32
  --> bad-shape.sx:7:15
   |
 7 |   (lambda (x) (matmul x weight)))
   |               ^^^^^^^^^^^^^^^^^
note: operands: `x` [2, 16] f32, `weight` [32, 8] f32
note: applying model `model`
  --> bad-shape.sx:9:15
   |
 9 | (defvar model (tiny 32 8))
   |               ^^^^^^^^^^^
help: `(matmul a b)` contracts the last axis of `a` with the second to last of `b`
in: model -> matmul

Every diagnostic has a code, a primary span, the expected and actual facts, and a fix when one is known. Look codes up in diagnostic codes.

--json

check <file> --json puts an array on standard output instead, one object per diagnostic. Flags come after the file.

[{"code": "E-DIM-001",
  "message": "matmul: inner dims differ: [2, 16] x [32, 8]: 16 against 32",
  "span": {"file": ".../bad-shape.sx", "line": 7, "col": 15, "start": 248, "end": 265},
  "notes": [{"message": "operands: `x` [2, 16] f32, `weight` [32, 8] f32", "span": {...}},
            {"message": "applying model `model`", "span": {"line": 9, "col": 15, ...}}],
  "trace": ["model", "matmul"],
  "fix": "`(matmul a b)` contracts the last axis of `a` with the second to last of `b`"}]

span is null when there is no location. An empty array is a clean file.

Where a diagnostic points

The primary span is a line in a file you own. A failure raised in library code (the prelude, a standard module, or a file with a directory called lib in its path) moves its span to the innermost call that is yours: a model application, a function call, or the macro call whose expansion built the failing form. The line that raised it becomes the note "raised by this expression". Code generated by a macro keeps the macro call and template origin as notes. A failure while loading a required file notes every require on the way, each "file is required here".

The message states the expected and the actual facts: the value it found, type and text (found string "4"), the axis and the sizes that disagree. A wrong name gets the nearest one that exists, and the list when it is short. A wrong argument count or keyword prints the callee's signature and notes where it is defined. An unclosed bracket names the form it opens and notes the first line inside it that starts at column one, where the closer most likely belongs. W-* codes are warnings and never stop a compilation.

watch

sexpgpu watch <file.sx> runs check, then polls every file the last compilation read every 250 ms, clearing the terminal and checking again whenever one moves, appears or disappears. It never exits on its own; Ctrl-C stops it. Standard modules have no file on disk and are not watched. It takes the selection.

Related: explain, diagnostic codes.