From 403e5981453b6772ed140e27cb34c2f0992d3491 Mon Sep 17 00:00:00 2001
From: Joseph Ferano
Date: Sat, 12 Sep 2026 04:11:22 +0700
Subject: [PATCH 1/3] Catch up with four facts that moved while this page sat
on a branch
The quote checker found three of them on the first run against the new tip: the
sand hash was changed deliberately by the grid lane, break and continue now
refuse by name instead of reading as unknown functions, and the usage text grew
--debug. The prelude also grew a string and UTF-8 family the table did not list.
---
web/examples/quotes.sh | 3 ++-
web/index.html | 25 ++++++++++++++++++-------
2 files changed, 20 insertions(+), 8 deletions(-)
diff --git a/web/examples/quotes.sh b/web/examples/quotes.sh
index dd447fc..b0f50b3 100644
--- a/web/examples/quotes.sh
+++ b/web/examples/quotes.sh
@@ -56,7 +56,8 @@ for pair in \
'fnty:(defn f [g (Fn [i32] i32)] i32 (g 1))' \
'quoted:(defn f [] i32 (quote a))' \
'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)))'
+ 'i64index:(defconst xs [3 i32] [1 2 3]) (defn main [] i32 (let [i (i64 1)] (at xs i)))' \
+ 'break:(defn main [] (let [i 0] (while (< i 3) (break))))'
do
name=${pair%%:*}; src=${pair#*:}
printf '%s\n' "$src" > "$here/.q.flan"
diff --git a/web/index.html b/web/index.html
index 08b78ce..c042f21 100644
--- a/web/index.html
+++ b/web/index.html
@@ -217,7 +217,7 @@ $ ./_build/default/bin/main.exe run calc-me.flan "1 + 2 * (3 - 0.5) / 2"
@@ -528,10 +528,13 @@ a body that changes it cannot change the trip count, and the loop variable is no
assignable.
Loops are imperative, with while, until and
-return. There is no loop/recur, and there is no
-break or continue either — both are planned and neither
-exists, so today they report as unknown function break. An early exit out
-of a loop is return, as first-even does above.
+return. There is no loop/recur. There is no
+break or continue yet either; both refuse by name:
+
+
break is not implemented yet (see the build sequence in plan.org)
+
+
An early exit out of a loop is return, as first-even does
+above.
That number is the whole point of writing the RNG in Flan rather than calling libc's:
a grid hash is only a regression test if the sequence is byte-identical on both targets.
@@ -1206,6 +1211,12 @@ module to bind to; release builds call directly, emit constants as constants, an
the folding back. Dev builds are not pruned by reachability, because what a REPL may
redefine next is not a function of what has been called so far.
+
--debug is a third flag beside --dev and the optimisation
+level. --dev asks whether you can redefine the program while it runs;
+--debug asks whether you can stop it and read it. It emits DWARF, sets
+-O0, and is refused by name for wasm32. lldb needs no plugin to read a
+Flan struct: the struct is its C struct.
+
Some things are refused by name rather than half-supported, and both cross-target
refusals say why:
From d995094b5251f1e5ab443e644d07aa6e6a145bb4 Mon Sep 17 00:00:00 2001
From: Joseph Ferano
Date: Sat, 12 Sep 2026 04:17:27 +0700
Subject: [PATCH 2/3] Put the contents beside the text instead of above it
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Nineteen entries at the top of a long page are scrolled past once and then
unreachable. A fixed column stays put and scrolls on its own. Below 66rem there
is not room for two columns, so it collapses to a bar with a toggle — a
checkbox, so the page still needs no script to navigate.
The wordmark's dot was a circle at a guessed x, which drifted from the n
whenever the reader's serif was not the one it was measured against. It is a
full stop in the same text run now.
---
web/index.html | 119 ++++++++++++++++++++++++++++++++++++-------------
1 file changed, 89 insertions(+), 30 deletions(-)
diff --git a/web/index.html b/web/index.html
index c042f21..d99fb28 100644
--- a/web/index.html
+++ b/web/index.html
@@ -67,6 +67,7 @@ body {
color: var(--text);
font: 17px/1.65 "Iowan Old Style", "Palatino Linotype", Palatino, Georgia, serif;
}
+main { display: block; }
.wrap { max-width: 44rem; margin: 0 auto; padding: 0 1.25rem 6rem; }
header { padding: 3.5rem 0 2rem; }
@@ -117,12 +118,63 @@ th { font-weight: 600; color: var(--muted); }
.lede { font-size: 1.1rem; }
.note { color: var(--muted); font-size: .94rem; }
-nav.toc { background: var(--panel); border-radius: 5px; padding: 1rem 1.25rem; margin: 2rem 0 0; }
-nav.toc ul { list-style: none; padding: 0; margin: 0; columns: 2; column-gap: 2rem; }
-nav.toc li { margin: .18rem 0; font-size: .93rem; break-inside: avoid; }
+
+/* The table of contents: a bar with a toggle when the window is narrow, a
+ fixed column beside the text when there is room for one. The toggle is a
+ checkbox so that no script is needed to open it. */
+.toc-toggle { position: absolute; width: 1px; height: 1px; opacity: 0; }
+.toc-button {
+ display: block; cursor: pointer; user-select: none;
+ position: sticky; top: 0; z-index: 2;
+ padding: .6rem 1.25rem;
+ background: var(--panel); border-bottom: 1px solid var(--rule);
+ color: var(--muted); font-size: .92rem; letter-spacing: .02em;
+}
+.toc-button::before { content: "\2261\00a0\00a0"; }
+.toc-toggle:focus-visible + .toc-button { outline: 2px solid var(--accent); outline-offset: -2px; }
+nav.toc {
+ display: none;
+ background: var(--panel); border-bottom: 1px solid var(--rule);
+ padding: .75rem 1.25rem 1.1rem;
+}
+.toc-toggle:checked ~ nav.toc { display: block; }
+.toc-title {
+ display: none; /* the toggle already says "Contents" */
+ margin: 0 0 .5rem; font-size: .78rem; letter-spacing: .09em;
+ text-transform: uppercase; color: var(--muted);
+}
+nav.toc ul { list-style: none; padding: 0; margin: 0; }
+nav.toc li { margin: 0; font-size: .93rem; }
+nav.toc a {
+ display: block; padding: .2rem 0; color: var(--muted);
+ text-decoration: none; border-left: 2px solid transparent; padding-left: .6rem;
+}
+nav.toc a:hover { color: var(--link); border-left-color: var(--accent); }
+h2, h3 { scroll-margin-top: 3.5rem; }
+
+/* Nineteen entries one to a line fills a phone screen, so the opened panel
+ goes to two columns as soon as there is room for them. */
+@media (min-width: 30rem) and (max-width: 65.99rem) {
+ nav.toc ul { columns: 2; column-gap: 1.5rem; }
+ nav.toc li { break-inside: avoid; }
+}
footer { margin-top: 3.5rem; padding-top: 1.5rem; border-top: 1px solid var(--rule); color: var(--muted); font-size: .92rem; }
-@media (max-width: 34rem) { nav.toc ul { columns: 1; } }
+/* Wide enough for both: the contents become a column of their own, scrolling
+ independently of the page, and the text moves over to sit beside it. */
+@media (min-width: 66rem) {
+ .toc-button { display: none; }
+ nav.toc {
+ display: block;
+ position: fixed; top: 0; left: 0; bottom: 0;
+ width: 15rem; overflow-y: auto; overscroll-behavior: contain;
+ background: none; border-bottom: 0; border-right: 1px solid var(--rule);
+ padding: 3.6rem 1rem 2rem 1.5rem;
+ }
+ main { margin-left: 15rem; }
+ .toc-title { display: block; }
+ h2, h3 { scroll-margin-top: 1rem; }
+}
.c { color: var(--c-comment); font-style: italic; }
.s { color: var(--c-string); }
@@ -133,34 +185,11 @@ footer { margin-top: 3.5rem; padding-top: 1.5rem; border-top: 1px solid var(--ru
-
-
-
-
-
A statically typed Lisp for game development. Clojure's brackets,
- C's memory and value model, no garbage collector.
-
-
-
Flan compiles s-expressions to LLVM IR and then to a native binary.
-There are no object headers, so a Flan struct is exactly its C struct. There is no
-collector, so nothing runs between frames that you did not write. And a running
-program can be edited: a function recompiled in Emacs is installed into the live
-process at its next frame boundary, in about twenty milliseconds.
-
-
This page describes the compiler as it is, not as it is planned. Where
-something is designed but not built, it says so and gives the message the compiler
-prints for it. Every Flan program on this page is a file in web/examples/
-with its output recorded beside it; sh web/examples/check.sh runs them all
-and compares, and quotes.sh re-derives the blocks that are transcripts
-rather than programs. If the page and the compiler disagree, one of those two goes
-red.
+
+
+
+
+
+
+
+
A statically typed Lisp for game development. Clojure's brackets,
+ C's memory and value model, no garbage collector.
+
+
+
Flan compiles s-expressions to LLVM IR and then to a native binary.
+There are no object headers, so a Flan struct is exactly its C struct. There is no
+collector, so nothing runs between frames that you did not write. And a running
+program can be edited: a function recompiled in Emacs is installed into the live
+process at its next frame boundary, in about twenty milliseconds.
+
+
This page describes the compiler as it is, not as it is planned. Where
+something is designed but not built, it says so and gives the message the compiler
+prints for it. Every Flan program on this page is a file in web/examples/
+with its output recorded beside it; sh web/examples/check.sh runs them all
+and compares, and quotes.sh re-derives the blocks that are transcripts
+rather than programs. If the page and the compiler disagree, one of those two goes
+red.
+
What Flan is
A minimal Lisp for games. In one line: Odin with a Lisp frontend and a live REPL.
@@ -1304,6 +1362,7 @@ macro is a function from Form to Form, which needs