Quote the compiler's own words for the index rule, and pin the Emacs keys

The paraphrase of why a wide index is refused was shorter and said less than
the message; and the keybinding table came from NEXT.md, which is two keys
behind flan-mode.el, so it now reads the keymap instead.
This commit is contained in:
Joseph Ferano 2026-09-12 03:50:48 +07:00
parent fc47489802
commit 6c34d4a66e
2 changed files with 26 additions and 12 deletions

View File

@ -11,14 +11,16 @@ FLAN=${FLAN:-$root/_build/default/bin/main.exe}
page=$here/../index.html page=$here/../index.html
fail=0 fail=0
# Look for a literal string in the page, allowing for HTML escaping of < and >. # The page is compared with its whitespace collapsed, so that a long compiler
# message may be wrapped in the HTML and still be recognised as the same text.
flat=$(sed -e 's/&lt;/</g' -e 's/&gt;/>/g' -e 's/&amp;/\&/g' "$page" | tr '\n' ' ' | tr -s ' ')
want() { want() {
esc=$(printf '%s' "$2" | sed -e 's/&/\&amp;/g' -e 's/</\&lt;/g' -e 's/>/\&gt;/g') needle=$(printf '%s' "$2" | tr '\n' ' ' | tr -s ' ')
if grep -qF -- "$esc" "$page"; then echo "ok $1"; else case $flat in
echo "FAIL $1" *"$needle"*) echo "ok $1" ;;
echo " not on the page: $2" *) echo "FAIL $1"; echo " not on the page: $2"; fail=1 ;;
fail=1 esac
fi
} }
# The usage text, from the binary itself. # The usage text, from the binary itself.
@ -27,7 +29,8 @@ want "flan usage" "$("$FLAN" 2>&1 | sed -n 2p)"
# calc-me, the first acceptance program, still answers what the page says. # calc-me, the first acceptance program, still answers what the page says.
want "calc-me" "$("$FLAN" run "$root/calc-me.flan" '1 + 2 * (3 - 0.5) / 2')" want "calc-me" "$("$FLAN" run "$root/calc-me.flan" '1 + 2 * (3 - 0.5) / 2')"
# The refusal messages quoted in "Not implemented yet" and under defer. # The refusal and diagnostic messages quoted in the prose and in the
# "Not implemented yet" table.
for pair in \ for pair in \
'vec:(defvar xs (Vec i32))' \ 'vec:(defvar xs (Vec i32))' \
'map:(defvar m (Map string i32))' \ 'map:(defvar m (Map string i32))' \
@ -35,12 +38,13 @@ for pair in \
'handle:(defvar h (Handle i32))' \ 'handle:(defvar h (Handle i32))' \
'fnty:(defn f [g (Fn [i32] i32)] i32 (g 1))' \ 'fnty:(defn f [g (Fn [i32] i32)] i32 (g 1))' \
'quoted:(defn f [] i32 (quote a))' \ 'quoted:(defn f [] i32 (quote a))' \
'deferblock:(defn f [] i32 (let [x 1] (defer (print-line "a")) x))' 'deferblock:(defn f [] i32 (let [x 1] (defer (print-line "a")) x))' \
'i64index:(defconst xs [3 i32] [1 2 3]) (defn main [] i32 (let [i (i64 1)] (at xs i)))'
do do
name=${pair%%:*}; src=${pair#*:} name=${pair%%:*}; src=${pair#*:}
printf '%s\n' "$src" > "$here/.q.flan" printf '%s\n' "$src" > "$here/.q.flan"
msg=$("$FLAN" check "$here/.q.flan" 2>&1 | sed 's/^[^ ]*: //') msg=$("$FLAN" check "$here/.q.flan" 2>&1 | sed 's/^[^ ]*: //')
want "refusal: $name" "$msg" want "message: $name" "$msg"
done done
rm -f "$here/.q.flan" rm -f "$here/.q.flan"
@ -59,4 +63,11 @@ want "agent declare" "$(grep -F 'flan_agent_poll' "$root/vendor/agent/agent.fla
want "conditions.org" "$(grep -F 'Innermost frame offering the name wins' "$root/conditions.org")" want "conditions.org" "$(grep -F 'Innermost frame offering the name wins' "$root/conditions.org")"
want "renderer" "$(grep -F ':r 17 :g 34 :b 51 :a 68' "$root/NEXT.md")" want "renderer" "$(grep -F ':r 17 :g 34 :b 51 :a 68' "$root/NEXT.md")"
# The Emacs bindings, from the keymap rather than from any prose about it.
for k in "C-c C-c" "C-c C-k" "C-x C-e" "C-c C-b" "C-c C-v" "C-c C-x"; do
grep -qF "(kbd \"$k\")" "$root/emacs/flan-mode.el" || {
echo "FAIL keybinding $k is not in flan-mode.el"; fail=1; continue; }
want "keybinding $k" "<kbd>$k</kbd>"
done
exit $fail exit $fail

View File

@ -372,8 +372,11 @@ and logical on an unsigned one.</p>
<p>An index converts from a narrower integer and never from a wider one. A <p>An index converts from a narrower integer and never from a wider one. A
<code>u32</code> index is fine — anything above 2<sup>31</sup> truncates to a negative <code>u32</code> index is fine — anything above 2<sup>31</sup> truncates to a negative
<code>i32</code> and the unsigned bounds check rejects it. An <code>i64</code> index is <code>i32</code> and the unsigned bounds check rejects it. An <code>i64</code> index is
refused, because 2<sup>32</sup>+5 truncates to 5 and would read the wrong element with refused, and the message is worth reading because it is the shape of most of them:</p>
no trap at all.</p>
<pre><code class="sh">an index is an i32, and i64 is wider — write (i32 …), because a value that does
not fit truncates to one that does and would read the wrong element without
tripping the bounds check</code></pre>
<h2 id="structs">Structs and enums</h2> <h2 id="structs">Structs and enums</h2>