flan/REFERENCES.md
Joseph Ferano 3e181b52b2 The docs described a language that stopped existing today
A consistency sweep, run by checking claims against the compiler rather
than reading for style. Every edit here corrects something that is false
now, or adds something the page had no way to say.

`web/index.html` was the worst of it, and the worst of that was control
flow: the page said there is no `loop`/`recur` and no `break` or
`continue`, and printed the refusal message for `break` as evidence. All
four are built, with loop labels. A live code example called
`index-of-i32`, which no longer exists and would not compile. The prelude
table was the pre-generics per-type families, a paragraph said there is
no `println` two paragraphs after calling `println` the compiler's, and
`sqrt-f32` was "the one `declare` in the file" when there are five. The
"Not implemented yet" table listed `Vec`, `Map`, `Handle`, `Fn`, `fn`,
unions, `defmacro` and quasiquote, all of which check; what is actually
left is `Result`, `try`, a quoted symbol as a value, `errdefer`, `await`,
`handler-case` and the restart-stack readers. Restarts take parameters
(`(invoke-restart 'use-value 21)` answers 42), `defer` in a `let` is
allowed, and there is both an allocator and a `context`.

Generics is a new section, because nobody had documented the syntax. The
brief for it was wrong in one place and the corpus settled it: `$t` goes
in *every* type position including the return type, and bare `t` is the
type-name argument in expression position — `(vec-new t)`, `(t x)`. It
says what a type variable is move-only by default means, since that is
the rule a reader hits first and it is not Odin's.

`FLAN_RAYLIB_H` is gone from every doc that claimed it still decided
something. The passages that say "this used to be opt-in" are kept and
labelled; the ones that said "this is opt-in" are not. `plan.org` had
`{string i32}` in the type list and four predicates where there are five.
`conditions.org` described `errdefer`'s behaviour without saying it is
refused by name. `REFERENCES.md` pointed at the gitignored copy of the
raylib header rather than the committed one, which is the exact trap that
made committing it necessary.

Found and not fixed, because it is not documentation: `vendor/raylib/headers`
still says a build reads it "when the variable happens to be set", which
contradicts the section below it in the same file and is false — moving
the header makes every build fail by name.
2026-09-13 18:04:24 +07:00

5.7 KiB

Reference clones on this machine

Read the source, do not recall it. Every claim in this repository's notes that came from one of these was read out of the clone, and the ones that were recalled instead have been wrong before — see NEXT.md's corrections. When a note cites a file and line, it is because someone opened it.

All paths are under ~/Repositories. Dates are the last commit in the clone at the time this file was written (2026-09-13); a stale clone is still the right source for how a thing works, just not for what its newest release does.

The ones this language is built against

Clone Last commit What it answers
Odin 2026-07-10 The primary reference. Memory model, containers, generics.
sbcl 2026-09-07 Conditions and restarts — what they should mean.
zig 2026-09-12 Comptime, build system, error handling, C interop.
jank 2026-09-11 A Clojure with native interop and a REPL into a running process.
janet 2025-09-29 A small embeddable Lisp. varfn and its reload story.
raylib 2026-07-16 The C library the FFI binds. Note: vendor/raylib/raylib-5.5.h in this repo is the committed header the bindings are checked against on every build; the clone may be a different version. It used to be whatever vendor/raylib/web/ happened to hold, which is gitignored and therefore absent from a fresh worktree — the reason the header is tracked now.

Odin, specifically

Most of what this repository copies. Places already cited in the notes:

  • base/runtime/core.odin:369Map_Info. The type-erased container runtime: rawptr keys, cell info for size and alignment, hash and equality as function pointers. This is why Vec and Map here need no generics, and it is the thing that was not converted when generics landed — Vec and Map are still type-erased, and a $t only reaches them as an element or key type.
  • base/runtime/dynamic_map_internal.odin — the map algorithm (Map K V) follows.
  • base/runtime/dynamic_array_internal.odin — the same for Vec.
  • src/check_expr.cpp:470-510find_or_generate_polymorphic_procedure. The instantiation cache: a polymorphic proc entity carries a gen_procs list, each call builds the concrete proc type, and the checker scans for are_types_identical before generating a new Entity. This is the machinery the generics spike copied.
  • src/check_type.cpp:173-200FieldFlag_using and FieldFlag_subtype. Odin's answer to "a function over anything with these fields": nominal embedding, not row polymorphism.

Two Odin facts worth keeping together, because conflating them has already caused one wrong note: $T procs are monomorphised, containers are type-erased. Odin uses both and picks per case.

Also present, same family

odin-examples, ols (the Odin language server), odin-imgui, odin-raylib-hot-reload-game-template — the last is a worked hot-reload loop in the language this one borrows its memory model from.

Lisp, conditions, and the editor loop

Clone Last commit What it answers
farolero 2023-05-05 Common Lisp conditions and restarts, portably — a smaller read than SBCL's for semantics.
lem 2025-08-29 An editor written in CL. Its own REPL and process model.
cider 2026-09-10 The Clojure editor protocol this repo's flan-dev.el is shaped after.
emacs 2026-04-18 Overlays, faces, pre-command-hook — the C and Lisp behind the editor half.
fennel-ls 2026-05-06 A Lisp language server.
Carp 2026-08-24 A statically typed Lisp with no GC. The closest thing to this language's premise.
lisp assorted.
cl-missile-command, b12n-raylib-clj, raylib-clojure-playground games in the Lisps, the same corpus ~/Development/fnm ports.

Carp deserves the note it has: statically typed, no GC, Lisp syntax, borrow-checked. Whatever it got right or wrong is the nearest prior art to what is being built here.

Graphics and the C boundary

raylib, raygui, glfw, SDL, freetype-gl, TIC-80, aseprite, macroquad, godot, bevy.

glfw and SDL matter for the window and input layer raylib sits on. TIC-80 and aseprite are real C/C++ programs to read for how they structure a frame loop.

Tooling, debuggers, terminals

tree-sitter (grammars — relevant if the editor mode ever stops being regexp-based), dape (a debug-adapter client for Emacs), gf (a GDB frontend), kitty, st, ratatui, stumpwm.

dape and gf are the two to read when the debugger question comes back: this repo emits DWARF already and flan dev --debug exists.

Everything else

Ambient, CelesteClone, RI-DASH, RichTextFX, controlsfx, openglfx, cljfx, pyimgui, emsdk (the Emscripten SDK — the web target uses it), esp-idf, linux, fedora-kernel, quickemu, OSX-KVM, tauri, keyd, alttab, xdg-ninja, jpm, cl-git, bragi, calm, pretty, dash-*, graph-rag, gptel, neocaml, marian, brainfuck, minimal_blockchain_in_rust, mpgameserver, computer_enhance, interactive-c-demo, falconerd-editor, unity-paper.io-2, vscode-defold, PyPaperBot, RyzenAdj, Tug, doom-themes, odin-webgl-experiment.

emsdk is the only one of these on a build path — the --target=web build needs it.

~/Development/fnm — the author's own falling-sand and siam-farmer ports in Clojure, Common Lisp, jank, Janet, Odin, OCaml and JS. PORTING.md in this repository is the report written from reading them, and sand.flan is kept at parity with lisp/sand.lisp, clojure/src/fnm/sand.clj and src/fnm/sand.jank.