diff --git a/docs/BUILT.md b/docs/BUILT.md index 6c92dae..e4b68ff 100644 --- a/docs/BUILT.md +++ b/docs/BUILT.md @@ -1618,10 +1618,10 @@ allocator the language does not have. ``` big 18446744073709551615 col :blue -(.pos b) (V {:x 1.5 :y 0}) -b (Blob {:id 7 :name "sandy \"quoted\"" :pos (V {:x 1.5 :y 0}) :tags [ 0 42 0]}) +(.pos b) (V {.x 1.5 .y 0}) +b (Blob {.id 7 .name "sandy \"quoted\"" .pos (V {.x 1.5 .y 0}) .tags [ 0 42 0]}) (slice (.tags b) 0 3) [ 0 42 0] -(rl/get-color 0x11223344) (rl/Color {:r 17 :g 34 :b 51 :a 68}) +(rl/get-color 0x11223344) (rl/Color {.r 17 .g 34 .b 51 .a 68}) sim/grid [ [ 0 0 0 0 0 0 0 0 ...] [ 0 ... ] ...] ``` diff --git a/spike/x86/cells.sh b/spike/x86/cells.sh index cae5481..81c1d4f 100755 --- a/spike/x86/cells.sh +++ b/spike/x86/cells.sh @@ -24,11 +24,25 @@ set -u here=$(cd "$(dirname "$0")" && pwd) root=$(cd "$here/../.." && pwd) +# FLAN overrides the compiler, and when it is set nothing is built here. The +# @cells alias sets it, because a dune action that shells out to dune waits on a +# lock it cannot get; main.exe is in that rule's deps instead. Resolved to an +# absolute path *before* the cd below, because dune's %{workspace_root} expands +# relative to the directory the rule is written in, and a relative path stops +# meaning what it meant the moment the working directory changes. +flan= +if [ -n "${FLAN:-}" ]; then + case $FLAN in /*) flan=$FLAN ;; + *) flan=$(cd "$(dirname "$FLAN")" && pwd)/$(basename "$FLAN") ;; esac +fi + cd "$root" || exit 1 -dune build --root . bin/main.exe 2>&1 | head -30 -flan=$root/_build/default/bin/main.exe -test -x "$flan" || { echo "build failed"; exit 1; } +if [ -z "$flan" ]; then + dune build --root . bin/main.exe 2>&1 | head -30 + flan=$root/_build/default/bin/main.exe +fi +test -x "$flan" || { echo "no compiler at $flan"; exit 1; } out=$(mktemp -d); trap 'rm -rf "$out"' EXIT cc -shared -fPIC -o "$out/override.so" "$here/cell-override.c" || exit 1 diff --git a/test/dune b/test/dune index 6c7bf6c..a4d558b 100644 --- a/test/dune +++ b/test/dune @@ -221,3 +221,114 @@ (setenv SURVEY_QUIET 1 (setenv FLAN %{workspace_root}/bin/main.exe (run bash %{workspace_root}/spike/x86/survey.sh)))))) + +; The reference page, checked against the compiler that is supposed to have +; produced everything on it. Two scripts, one alias, because they are halves of +; the same claim: web/examples/check.sh runs each program the page shows and +; diffs it against the .out recorded beside it, and web/examples/quotes.sh +; re-derives every *other* block -- the usage text, the refusal messages, the +; LLVM excerpt, the keybindings -- and looks for it in web/index.html. A +; paraphrase reads exactly like a quotation, which is the whole reason the +; second one exists. +; +; dune build --root . @page +; +; Opt-in rather than part of `dune test`, and for a reason that is NOT the one +; @sanitize, @valgrind and @x86 give. Those three are minutes; this is eleven +; seconds, five of which is breakdemo's deliberate sleep. Slowness is measured +; and is not the argument here. The argument is what a failure +; means: these two fail when a *document* has gone stale, not when the compiler +; has regressed, and a suite that goes red because prose drifted teaches the +; person running it to skim past red. `dune test` should mean "the language +; broke". This should mean "the page is lying". Keeping them apart is what lets +; both stay worth reading. See @checks below, which is how they get run. +; +; A rule rather than a (test ...) for the reason the @x86 comment gives: a test +; stanza attaches to @runtest and offers no way to be attached to anything else. +; FLAN is passed for the same reason too -- the scripts otherwise run `dune +; build` themselves, and a dune inside a dune action waits on a lock it cannot +; get. Everything either script reads has to be in the deps, because the action +; runs in _build and a glob that came up empty would let check.sh loop over no +; programs and exit 0 -- an alias that passes because it checked nothing. +(rule + (alias page) + (deps + (glob_files %{workspace_root}/web/examples/*) + ; pkg.flan imports "geom" as a package, and dune's glob does not descend. + (glob_files %{workspace_root}/web/examples/geom/*) + (file %{workspace_root}/web/index.html) + (file %{workspace_root}/bin/main.exe) + ; quotes.sh re-derives its needles from these: calc-me for the arithmetic + ; answer, the corpus for the sand hash and the renderer's field spelling, + ; conditions.org and flan-mode.el for the lines quoted verbatim. + (file %{workspace_root}/calc-me.flan) + (file %{workspace_root}/conditions.org) + (glob_files %{workspace_root}/emacs/*.el) + (glob_files programs/*.flan) + ; breakdemo.flan is built --dev, so it imports the agent; raylib is here for + ; the binding line quotes.sh greps out of it. + (glob_files %{workspace_root}/vendor/agent/*) + (glob_files %{workspace_root}/vendor/raylib/*)) + (action + (progn + (setenv FLAN %{workspace_root}/bin/main.exe + (run sh %{workspace_root}/web/examples/check.sh)) + (setenv FLAN %{workspace_root}/bin/main.exe + (run sh %{workspace_root}/web/examples/quotes.sh))))) + +; The indirection cell, driven from outside the language. spike/x86/cells.sh +; preloads a shared object whose constructor stores a different body into +; flan.cell.twice with dlsym, and checks that a --dev build notices and a +; release build does not -- 22 22 against 42 42, both backends, four builds. +; Its own alias and not part of @x86 because it is a different question: +; survey.sh asks whether the backend agrees with LLVM about what a program +; prints, and no program can answer this one, because a dev build starts with +; every cell already pointing at the body this build compiled. +; +; dune build --root . @cells +; +; Wired here for the reason everything on this page is wired: it was a real +; pass/fail check that nothing ran, which is how a check becomes decoration. +(rule + (alias cells) + (deps + (file %{workspace_root}/spike/x86/cells.sh) + (file %{workspace_root}/spike/x86/cell-override.c) + (glob_files %{workspace_root}/spike/x86/*.flan) + (file %{workspace_root}/bin/main.exe)) + (action + (setenv FLAN %{workspace_root}/bin/main.exe + (run bash %{workspace_root}/spike/x86/cells.sh)))) + +; Everything that checks something and is not `dune test`, in one word. +; +; dune build --root . @checks +; +; This exists because the opt-in aliases had the same disease as the scripts +; they replaced. @x86 was added after two backend refusals sat unnoticed for a +; month, and an alias nobody types is no better than a script nobody types -- +; it only looks more responsible. Five names to remember is four too many, and +; the cost of remembering them is paid every time, by whoever is least likely +; to know they exist. +; +; What is in it is the whole design. @page, @x86 and @cells: a couple of +; minutes between them, they need nothing installed that a build does not +; already need, and they are exactly the two failures this repository has +; actually had plus the one that was found beside them. @sanitize and @valgrind +; are deliberately out. They are tens of minutes and they want ASan and +; Valgrind present, and folding them in would make @checks the thing you do not +; have time for -- which is the disease, not the cure. +; +; It is honest to say what this does not do. It does not run itself. Nothing +; here runs itself, because there is no CI, and a commit hook that costs two +; minutes gets switched off in a week. What it buys is that deciding to check +; and checking everything are now the same act, so the gap between "somebody +; wondered" and "everything was verified" is one command instead of five. The +; habit that closes the rest of the gap is written down in README.md: a lane's +; handoff quotes this alias, the way the x86 handoffs already quote survey.sh. +(alias + (name checks) + (deps + (alias page) + (alias x86) + (alias cells))) diff --git a/web/examples/check.sh b/web/examples/check.sh index 7811669..3b229f8 100644 --- a/web/examples/check.sh +++ b/web/examples/check.sh @@ -10,6 +10,10 @@ here=$(cd "$(dirname "$0")" && pwd) root=$(cd "$here/../.." && pwd) FLAN=${FLAN:-$root/_build/default/bin/main.exe} +# Made absolute before the cd below, because a relative FLAN stops meaning what +# it meant the moment the working directory changes. dune hands one over: +# %{workspace_root} expands relative to the directory the rule is written in. +case $FLAN in /*) ;; *) FLAN=$(cd "$(dirname "$FLAN")" && pwd)/$(basename "$FLAN") ;; esac tmp=${TMPDIR:-/tmp}/flan-web-check.$$ cd "$here" || exit 1 diff --git a/web/examples/quotes.sh b/web/examples/quotes.sh index 6e0b97d..9d48eb2 100644 --- a/web/examples/quotes.sh +++ b/web/examples/quotes.sh @@ -8,6 +8,10 @@ here=$(cd "$(dirname "$0")" && pwd) root=$(cd "$here/../.." && pwd) FLAN=${FLAN:-$root/_build/default/bin/main.exe} +# Absolute, for the reason check.sh gives beside the same line: everything else +# here is resolved against $here or $root, so a FLAN relative to the caller's +# working directory would be the one path that meant something different. +case $FLAN in /*) ;; *) FLAN=$(cd "$(dirname "$FLAN")" && pwd)/$(basename "$FLAN") ;; esac page=$here/../index.html fail=0