Every citation of a moved document now resolves from where it is written
This commit is contained in:
parent
eb641cf8eb
commit
9d5689ffa2
200
NEXT.md
200
NEXT.md
@ -7,7 +7,7 @@ of taste, and it is worth your reading of it: `runtime/flan_rt.c:70-86` allocate
|
|||||||
`restart-case` that offers it, on that frame's own stack**, so the runtime cannot push one on a program's
|
`restart-case` that offers it, on that frame's own stack**, so the runtime cannot push one on a program's
|
||||||
behalf. Offering `use-value` at a division would mean an alloca plus a push and pop emitted at every
|
behalf. Offering `use-value` at a division would mean an alloca plus a push and pop emitted at every
|
||||||
division in every checked build — which is the identical cost `lib/prelude.ml:70-76` already refuses, in
|
division in every checked build — which is the identical cost `lib/prelude.ml:70-76` already refuses, in
|
||||||
prose and on the record, for indexing. `HANDOFF-arith.md` is the full write-up.
|
prose and on the record, for indexing. `docs/handoffs/HANDOFF-arith.md` is the full write-up.
|
||||||
|
|
||||||
So the question back to you: **is signal-and-die-with-a-location enough for arithmetic, the way it is for
|
So the question back to you: **is signal-and-die-with-a-location enough for arithmetic, the way it is for
|
||||||
`BoundsError`, or do you want `saturate` on the cast arm** — which is the one case where clamping is
|
`BoundsError`, or do you want `saturate` on the cast arm** — which is the one case where clamping is
|
||||||
@ -26,14 +26,14 @@ Nothing is running and nothing is half-built. Read this first.
|
|||||||
`spike/x86/survey.sh` builds every program in `test/programs` and every probe in `spike/x86` both
|
`spike/x86/survey.sh` builds every program in `test/programs` and every probe in `spike/x86` both
|
||||||
ways and compares **stdout, stderr and exit status**: **97 MATCH, 0 DIFFER, 0 refused by name.** That
|
ways and compares **stdout, stderr and exit status**: **97 MATCH, 0 DIFFER, 0 refused by name.** That
|
||||||
is up from 41/1/41 at the start of the day. Conditions, bounds checks, `Fnval`'s indirection cell and
|
is up from 41/1/41 at the start of the day. Conditions, bounds checks, `Fnval`'s indirection cell and
|
||||||
`--x86 --dev` all landed. `DISCUSS.md` items 16, 17 and 18 are the three reports.
|
`--x86 --dev` all landed. `docs/DISCUSS.md` items 16, 17 and 18 are the three reports.
|
||||||
|
|
||||||
**`HANDOFF-x86-rt.md` at the root has the remaining seven items in order.** Item 1 is the substantial
|
**`docs/handoffs/HANDOFF-x86-rt.md` at the root has the remaining seven items in order.** Item 1 is the substantial
|
||||||
one and is the reason the backend exists:
|
one and is the reason the backend exists:
|
||||||
|
|
||||||
> **A redefinition emitter in `lib/x86.ml`** — the counterpart to `Emit.redefinition`, producing a
|
> **A redefinition emitter in `lib/x86.ml`** — the counterpart to `Emit.redefinition`, producing a
|
||||||
> `.so`. Until it exists the backend builds whole programs and cannot serve a single `C-c C-c`, which
|
> `.so`. Until it exists the backend builds whole programs and cannot serve a single `C-c C-c`, which
|
||||||
> is where `DISCUSS.md` item 13's ~21ms of a 35ms redefinition actually lives.
|
> is where `docs/DISCUSS.md` item 13's ~21ms of a 35ms redefinition actually lives.
|
||||||
|
|
||||||
**And the constraint the last lane found, which is the thing not to rediscover:** publishing a cell an
|
**And the constraint the last lane found, which is the thing not to rediscover:** publishing a cell an
|
||||||
LLVM-built module can store into puts an edge on `lib/x86.ml`'s own licence that *"a dev build is
|
LLVM-built module can store into puts an edge on `lib/x86.ml`'s own licence that *"a dev build is
|
||||||
@ -78,7 +78,7 @@ request and `Session.eval` commits below the checker.
|
|||||||
|
|
||||||
## Queued, nothing blocked on a decision
|
## Queued, nothing blocked on a decision
|
||||||
|
|
||||||
1. `HANDOFF-x86-rt.md`'s seven items, item 1 first.
|
1. `docs/handoffs/HANDOFF-x86-rt.md`'s seven items, item 1 first.
|
||||||
2. `text_codepoints_loading` and `textures_image_processing` — ordinary porting now that
|
2. `text_codepoints_loading` and `textures_image_processing` — ordinary porting now that
|
||||||
`slice-from-ptr` exists.
|
`slice-from-ptr` exists.
|
||||||
3. Generic structs and `$n` array lengths — decided, unblocked, sections below. **Stopped once
|
3. Generic structs and `$n` array lengths — decided, unblocked, sections below. **Stopped once
|
||||||
@ -101,7 +101,7 @@ something that is not memory. Their old entries stand; do not schedule either.
|
|||||||
**Built.** `flan_slice_promise_error` is its own function in `runtime/flan_rt.c`, shaped like the two
|
**Built.** `flan_slice_promise_error` is its own function in `runtime/flan_rt.c`, shaped like the two
|
||||||
beside it — it signals `BoundsError`, walks the handlers, offers the break loop, and only then falls
|
beside it — it signals `BoundsError`, walks the handlers, offers the break loop, and only then falls
|
||||||
through to a message and a status. The sentence names the promise and the number that broke it, and a
|
through to a message and a status. The sentence names the promise and the number that broke it, and a
|
||||||
second line says what is *not* checked. See [`BUILT.md`](BUILT.md), "`slice-from-ptr` refuses in its
|
second line says what is *not* checked. See [`docs/BUILT.md`](docs/BUILT.md), "`slice-from-ptr` refuses in its
|
||||||
own words". The original entry follows.
|
own words". The original entry follows.
|
||||||
|
|
||||||
Small, and known rough at the time it shipped. `(slice-from-ptr p n)` with a **computed** negative
|
Small, and known rough at the time it shipped. `(slice-from-ptr p n)` with a **computed** negative
|
||||||
@ -127,10 +127,10 @@ is the whole reason it was left. Say what the caller promised and what was passe
|
|||||||
**Named here because it is not on the list below and would otherwise be discovered late.**
|
**Named here because it is not on the list below and would otherwise be discovered late.**
|
||||||
|
|
||||||
Finishing items 1-6 below gives a second **whole-program** compiler. `--x86` is refused with `--dev`
|
Finishing items 1-6 below gives a second **whole-program** compiler. `--x86` is refused with `--dev`
|
||||||
today, deliberately, and `DISCUSS.md` item 16 says it has no cells. So at the end of that list the
|
today, deliberately, and `docs/DISCUSS.md` item 16 says it has no cells. So at the end of that list the
|
||||||
backend can build `sand.flan` and cannot serve a single `C-c C-c`.
|
backend can build `sand.flan` and cannot serve a single `C-c C-c`.
|
||||||
|
|
||||||
What the backend was for is `DISCUSS.md` item 13's measurement: `llc` and `ld` are **about 21ms of a
|
What the backend was for is `docs/DISCUSS.md` item 13's measurement: `llc` and `ld` are **about 21ms of a
|
||||||
35ms redefinition**, and removing them is the only thing that touches that number. Collecting it means
|
35ms redefinition**, and removing them is the only thing that touches that number. Collecting it means
|
||||||
emitting a **redefinition module** — one function, compiled and installed into a running process
|
emitting a **redefinition module** — one function, compiled and installed into a running process
|
||||||
through an indirection cell — which is what `Build.shared` does on the LLVM path.
|
through an indirection cell — which is what `Build.shared` does on the LLVM path.
|
||||||
@ -150,13 +150,13 @@ Concretely, and none of it is scoped yet:
|
|||||||
- **DWARF.** `flan dev --debug` exists and `--x86` refuses `--debug`. A dev backend that cannot be
|
- **DWARF.** `flan dev --debug` exists and `--x86` refuses `--debug`. A dev backend that cannot be
|
||||||
debugged is a narrower tool than the one it replaces.
|
debugged is a narrower tool than the one it replaces.
|
||||||
- **Then measure, because the whole case rests on it.** If a hand-written backend does not actually
|
- **Then measure, because the whole case rests on it.** If a hand-written backend does not actually
|
||||||
beat 35ms end to end, the argument for it was wrong and that is worth knowing. `DISCUSS.md` item 13
|
beat 35ms end to end, the argument for it was wrong and that is worth knowing. `docs/DISCUSS.md` item 13
|
||||||
says the backend is decided at step 4 on a measurement taken at step 3, and this is that
|
says the backend is decided at step 4 on a measurement taken at step 3, and this is that
|
||||||
measurement finally being takeable.
|
measurement finally being takeable.
|
||||||
|
|
||||||
## The backend, in the order that finishes it
|
## The backend, in the order that finishes it
|
||||||
|
|
||||||
`DISCUSS.md` item 16 is the report and its verdict is the sequencing: *"the wiring is done and it was
|
`docs/DISCUSS.md` item 16 is the report and its verdict is the sequencing: *"the wiring is done and it was
|
||||||
the easy half. What is left is conditions, and the measurement moved them from 'first obstacle' to
|
the easy half. What is left is conditions, and the measurement moved them from 'first obstacle' to
|
||||||
'the only obstacle'."* 40 of 111 programs lower today; the other 40 are refused by name.
|
'the only obstacle'."* 40 of 111 programs lower today; the other 40 are refused by name.
|
||||||
|
|
||||||
@ -211,7 +211,7 @@ question 4 seriously now that there are two backends that can disagree.
|
|||||||
policy that distinguishes it from `two_process`. `HANDOFF-f1.md` is gone with it.
|
policy that distinguishes it from `two_process`. `HANDOFF-f1.md` is gone with it.
|
||||||
- ~~**The memcheck half of the registry**~~ — done. `flan_arena_proc`'s `free-all` issues memcheck's
|
- ~~**The memcheck half of the registry**~~ — done. `flan_arena_proc`'s `free-all` issues memcheck's
|
||||||
`MAKE_MEM_UNDEFINED` over the arena, vendored rather than included; it is a control in
|
`MAKE_MEM_UNDEFINED` over the arena, vendored rather than included; it is a control in
|
||||||
`test_valgrind.ml` now, and `BUILT.md` carries the cost. The registry answer and the memcheck
|
`test_valgrind.ml` now, and `docs/BUILT.md` carries the cost. The registry answer and the memcheck
|
||||||
answer stay two claims.
|
answer stay two claims.
|
||||||
|
|
||||||
## Not in the freeze, because it is already decided and unblocked
|
## Not in the freeze, because it is already decided and unblocked
|
||||||
@ -236,7 +236,7 @@ everything below it is the standing queue and the decision record.
|
|||||||
- **`pause` marking, both halves.** `C-u` before an eval marks the innermost form, `C-u C-u` the
|
- **`pause` marking, both halves.** `C-u` before an eval marks the innermost form, `C-u C-u` the
|
||||||
top-level one.
|
top-level one.
|
||||||
- **`spy-num`.** A watch slot keeps count, min, max, last, mean, windowed to the editor's last tick.
|
- **`spy-num`.** A watch slot keeps count, min, max, last, mean, windowed to the editor's last tick.
|
||||||
- **Frame rollback**, `PORTING.md` Tier 1 item 6. `restore` goes in the `continue` clause, not a defer.
|
- **Frame rollback**, `docs/PORTING.md` Tier 1 item 6. `restore` goes in the `continue` clause, not a defer.
|
||||||
- **The dev allocation registry is finished.** `M-x flan-inspect-address`, `M-x flan-allocations`,
|
- **The dev allocation registry is finished.** `M-x flan-inspect-address`, `M-x flan-allocations`,
|
||||||
`M-x flan-leaks`.
|
`M-x flan-leaks`.
|
||||||
- **15 raylib examples**, an idiomatic layer over the bindings, and `vendor/raylib/vector.flan`.
|
- **15 raylib examples**, an idiomatic layer over the bindings, and `vendor/raylib/vector.flan`.
|
||||||
@ -252,7 +252,7 @@ everything below it is the standing queue and the decision record.
|
|||||||
|
|
||||||
~~**`worktree-agent-a859480edc827ab73` — macros importable from a package.**~~ **Finished.** The suite
|
~~**`worktree-agent-a859480edc827ab73` — macros importable from a package.**~~ **Finished.** The suite
|
||||||
is green, the acceptance wiring asserts both halves of the rule, and the dev loop is covered. See
|
is green, the acceptance wiring asserts both halves of the rule, and the dev loop is covered. See
|
||||||
BUILT.md, "A package may declare a macro, and its name is the package's".
|
docs/BUILT.md, "A package may declare a macro, and its name is the package's".
|
||||||
|
|
||||||
The finding is worth keeping: the old refusal claimed collecting a package's macros needed a second
|
The finding is worth keeping: the old refusal claimed collecting a package's macros needed a second
|
||||||
import resolver at the Form level. It did not. The file being compiled is parsed before `Load` runs
|
import resolver at the Form level. It did not. The file being compiled is parsed before `Load` runs
|
||||||
@ -260,7 +260,7 @@ too, so no shape of the feature could have left import resolution where it was
|
|||||||
forms now and uses the one resolver that always existed.
|
forms now and uses the one resolver that always existed.
|
||||||
|
|
||||||
~~One gap left, and it is older than this work: **`C-x C-e` expands no macros at all.**~~ **Done** —
|
~~One gap left, and it is older than this work: **`C-x C-e` expands no macros at all.**~~ **Done** —
|
||||||
see [`BUILT.md`](BUILT.md), "`C-x C-e` expands too, and a declaration is not an expression". It was
|
see [`docs/BUILT.md`](docs/BUILT.md), "`C-x C-e` expands too, and a declaration is not an expression". It was
|
||||||
the wrap `Parse.decl` already had, and the decision it was waiting on came out as: an expression that
|
the wrap `Parse.decl` already had, and the decision it was waiting on came out as: an expression that
|
||||||
expands to a declaration is **refused by name**, in `Parse.expr`'s head dispatch, so a `defn` nested
|
expands to a declaration is **refused by name**, in `Parse.expr`'s head dispatch, so a `defn` nested
|
||||||
anywhere in the expansion and a `defvar` typed by hand get the same sentence. The spin refusal fires
|
anywhere in the expansion and a `defvar` typed by hand get the same sentence. The spin refusal fires
|
||||||
@ -269,7 +269,7 @@ expands is the prelude's macros and the imported packages' — and, since the la
|
|||||||
the file's own as well.
|
the file's own as well.
|
||||||
|
|
||||||
Two things left behind it, neither this lane's. ~~**A session expands no macro the buffer itself
|
Two things left behind it, neither this lane's. ~~**A session expands no macro the buffer itself
|
||||||
declares**~~ — **done**, see [`BUILT.md`](BUILT.md), "A session expands the buffer's own macros". The
|
declares**~~ — **done**, see [`docs/BUILT.md`](docs/BUILT.md), "A session expands the buffer's own macros". The
|
||||||
session seeds its file's own `defmacro`s in `Session.create`, from the same read that produced
|
session seeds its file's own `defmacro`s in `Session.create`, from the same read that produced
|
||||||
`decls`, and an evaluated `defmacro` joins the set so the next evaluation can call it — the shape
|
`decls`, and an evaluated `defmacro` joins the set so the next evaluation can call it — the shape
|
||||||
`defn` already has. Re-reading the file was the alternative and was refused: it would put
|
`defn` already has. Re-reading the file was the alternative and was refused: it would put
|
||||||
@ -303,7 +303,7 @@ the Emacs side". **Superseded** — the registry lane built that properly. Delet
|
|||||||
|
|
||||||
## For siam-farmer
|
## For siam-farmer
|
||||||
|
|
||||||
`PORTING.md`'s verdict is unconditional now: the game's state is **fixed arrays with counts**, so it
|
`docs/PORTING.md`'s verdict is unconditional now: the game's state is **fixed arrays with counts**, so it
|
||||||
fits in `defvar` globals, nothing is move-only, and generics is off its critical path. Tier 0 and Tier 1
|
fits in `defvar` globals, nothing is move-only, and generics is off its critical path. Tier 0 and Tier 1
|
||||||
items 4, 5 and 6 are all done. Nothing blocks writing it.
|
items 4, 5 and 6 are all done. Nothing blocks writing it.
|
||||||
|
|
||||||
@ -407,7 +407,7 @@ allocation**, which is Odin's `Small_Array` and a good fit for a game that refus
|
|||||||
(defvar enemies (Small-Array 64 Enemy))
|
(defvar enemies (Small-Array 64 Enemy))
|
||||||
```
|
```
|
||||||
|
|
||||||
`PORTING.md`'s recommendation for the game's state was fixed arrays with counts held in `defvar` globals, kept
|
`docs/PORTING.md`'s recommendation for the game's state was fixed arrays with counts held in `defvar` globals, kept
|
||||||
deliberately away from `Vec` so nothing is move-only. `(Small-Array $n $t)` is that pattern with a type behind it
|
deliberately away from `Vec` so nothing is move-only. `(Small-Array $n $t)` is that pattern with a type behind it
|
||||||
instead of two variables kept in step by hand. That is the argument for building this, and it is stronger than
|
instead of two variables kept in step by hand. That is the argument for building this, and it is stronger than
|
||||||
"Odin has it".
|
"Odin has it".
|
||||||
@ -436,7 +436,7 @@ separate question and should be answered deliberately rather than falling out of
|
|||||||
|
|
||||||
## Decided 2026-09-13: generics by monomorphisation, checked abstractly, with `where` predicates
|
## Decided 2026-09-13: generics by monomorphisation, checked abstractly, with `where` predicates
|
||||||
|
|
||||||
The spike answered it (`SPIKE-GENERICS.md`, on `worktree-agent-afcd2406f3660629b`): **it runs**, the whole feature
|
The spike answered it (`docs/SPIKE-GENERICS.md`, on `worktree-agent-afcd2406f3660629b`): **it runs**, the whole feature
|
||||||
is `lib/check.ml` and nothing else in `lib/`, and instantiation is under the noise floor at 1.8ms whole-program
|
is `lib/check.ml` and nothing else in `lib/`, and instantiation is under the noise floor at 1.8ms whole-program
|
||||||
re-check. The bill is `llc`+`ld` at **+1.7ms per extra body**, so a generic used at three types adds ~7ms to a
|
re-check. The bill is `llc`+`ld` at **+1.7ms per extra body**, so a generic used at three types adds ~7ms to a
|
||||||
redefinition. `plan.org` is updated; what follows is the decision and the reasoning that does not belong there.
|
redefinition. `plan.org` is updated; what follows is the decision and the reasoning that does not belong there.
|
||||||
@ -615,13 +615,13 @@ why they are here and not in a binding list.
|
|||||||
check now accepts an enum where the header says `int`, symmetrically, and still refuses
|
check now accepts an enum where the header says `int`, symmetrically, and still refuses
|
||||||
anything that is not four bytes. `Camera3D.projection` is a `CameraProjection` again and the
|
anything that is not four bytes. `Camera3D.projection` is a `CameraProjection` again and the
|
||||||
`rl/camera-projection` helper is gone; `.projection :perspective` resolves at the construction
|
`rl/camera-projection` helper is gone; `.projection :perspective` resolves at the construction
|
||||||
site, so the keyword half of the problem went away with it. See BUILT.md.
|
site, so the keyword half of the problem went away with it. See docs/BUILT.md.
|
||||||
|
|
||||||
3. ~~**The header check does not reach `defconst` or `defenum`.**~~ **Closed.** It reaches both.
|
3. ~~**The header check does not reach `defconst` or `defenum`.**~~ **Closed.** It reaches both.
|
||||||
`bindings` gained `enum`, `const` and `constant` lines that say what a Flan constant is called in
|
`bindings` gained `enum`, `const` and `constant` lines that say what a Flan constant is called in
|
||||||
C; every mapped name is compared by value, and a name the mapping cannot find, a rule that
|
C; every mapped name is compared by value, and a name the mapping cannot find, a rule that
|
||||||
reaches nothing, and a `defenum` with no line at all are each reported rather than skipped. All
|
reaches nothing, and a `defenum` with no line at all are each reported rather than skipped. All
|
||||||
eight raylib enums and all 16 `ConfigFlags` bits check out against 5.5. See BUILT.md.
|
eight raylib enums and all 16 `ConfigFlags` bits check out against 5.5. See docs/BUILT.md.
|
||||||
|
|
||||||
4. ~~**raymath is `static inline`, so there is no symbol to bind.**~~ **Closed for the vector half.**
|
4. ~~**raymath is `static inline`, so there is no symbol to bind.**~~ **Closed for the vector half.**
|
||||||
`Clamp`, `Vector2Add`, `Remap` and the rest exist only in the header and `declare-c` has nothing
|
`Clamp`, `Vector2Add`, `Remap` and the rest exist only in the header and `declare-c` has nothing
|
||||||
@ -662,7 +662,7 @@ tip themselves. A lane that did not notice would produce plausible work against
|
|||||||
|
|
||||||
**Built.** All seven items landed: the `eval_expr` pause path, `flan-dev--eval` sending the position,
|
**Built.** All seven items landed: the `eval_expr` pause path, `flan-dev--eval` sending the position,
|
||||||
`flan-eval-defun` taking `C-u`, the overlay and its face, `test/programs/dev-pause.flan`, the `test_dev.ml` block and
|
`flan-eval-defun` taking `C-u`, the overlay and its face, `test/programs/dev-pause.flan`, the `test_dev.ml` block and
|
||||||
the `emacs/test-flan-dev.el` one. `HANDOFF-f2.md` is deleted; the reasoning is in `BUILT.md`, "A breakpoint is a
|
the `emacs/test-flan-dev.el` one. `HANDOFF-f2.md` is deleted; the reasoning is in `docs/BUILT.md`, "A breakpoint is a
|
||||||
function call, and the editor only says where".
|
function call, and the editor only says where".
|
||||||
|
|
||||||
### ~~From `HANDOFF-f1.md`~~ — the socket flake is fixed, and everything that followed it is done
|
### ~~From `HANDOFF-f1.md`~~ — the socket flake is fixed, and everything that followed it is done
|
||||||
@ -730,7 +730,7 @@ actually worth having. The timers are 30s, down from a minute, because the build
|
|||||||
|
|
||||||
### ~~From `HANDOFF-f3.md` — the watch is built; two tests are not~~
|
### ~~From `HANDOFF-f3.md` — the watch is built; two tests are not~~
|
||||||
|
|
||||||
`spy-num` landed and `PORTING.md` Tier 1 item 5 is closed. The `spy` half already existed — the finding that
|
`spy-num` landed and `docs/PORTING.md` Tier 1 item 5 is closed. The `spy` half already existed — the finding that
|
||||||
reframed the task is that the table, the agent commands, the buffer and the ghost text were all there at `344e571`,
|
reframed the task is that the table, the agent commands, the buffer and the ghost text were all there at `344e571`,
|
||||||
and only the numeric accumulator was missing. A slot keeps count, min, max, last and mean; the window is since the
|
and only the numeric accumulator was missing. A slot keeps count, min, max, last and mean; the window is since the
|
||||||
editor's last tick rather than cumulative, because cumulative min/max reach the session's extremes within seconds of
|
editor's last tick rather than cumulative, because cumulative min/max reach the session's extremes within seconds of
|
||||||
@ -745,19 +745,19 @@ stopped program does not sample, so an epoch-aware reader would blank the watch
|
|||||||
is exactly when the numbers are being read. What was actually wrong was in the editor — `flan-watch--tick` sent
|
is exactly when the numbers are being read. What was actually wrong was in the editor — `flan-watch--tick` sent
|
||||||
`:reset t` five times a second at a program that could not answer it — and it is now guarded on `flan-dev--stopped`,
|
`:reset t` five times a second at a program that could not answer it — and it is now guarded on `flan-dev--stopped`,
|
||||||
with the read still going out every tick. `emacs/test-flan-watch.el` pins both halves. `HANDOFF-f3.md` is deleted;
|
with the read still going out every tick. `emacs/test-flan-watch.el` pins both halves. `HANDOFF-f3.md` is deleted;
|
||||||
the reasoning is in `BUILT.md`, "A hot loop keeps five numbers, and the window is the editor's".
|
the reasoning is in `docs/BUILT.md`, "A hot loop keeps five numbers, and the window is the editor's".
|
||||||
|
|
||||||
### Not started: five more raylib core examples
|
### Not started: five more raylib core examples
|
||||||
|
|
||||||
Ten are in `examples/`. Five more were queued and the lane was stopped before it wrote anything, so there is nothing
|
Ten are in `examples/`. Five more were queued and the lane was stopped before it wrote anything, so there is nothing
|
||||||
to pick up — only the brief. Pick for what they exercise of the bindings rather than for how they look, since the
|
to pick up — only the brief. Pick for what they exercise of the bindings rather than for how they look, since the
|
||||||
point of the corpus is finding gaps in `vendor/raylib/raylib.flan`. Upstream is
|
point of the corpus is finding gaps in `vendor/raylib/raylib.flan`. Upstream is
|
||||||
`vendor/raylib/web/raylib-5.5/examples/core/`. `PORTING.md` §1's rule binds: a raylib function on a real per-frame
|
`vendor/raylib/web/raylib-5.5/examples/core/`. `docs/PORTING.md` §1's rule binds: a raylib function on a real per-frame
|
||||||
path is hand-written and header-checked, not left to the opt-in `FLAN_RAYLIB_H` import, because the default build
|
path is hand-written and header-checked, not left to the opt-in `FLAN_RAYLIB_H` import, because the default build
|
||||||
has no `FLAN_RAYLIB_H` and still has to draw. An enum value has to be added by hand whatever happens — the importer
|
has no `FLAN_RAYLIB_H` and still has to draw. An enum value has to be added by hand whatever happens — the importer
|
||||||
generates functions and only functions.
|
generates functions and only functions.
|
||||||
|
|
||||||
### Landed: frame rollback, `PORTING.md` Tier 1 item 6
|
### Landed: frame rollback, `docs/PORTING.md` Tier 1 item 6
|
||||||
|
|
||||||
`test/programs/frame-rollback.flan`, with three acceptance rows beside `bounds-condition.flan`'s (plain, `-O0`,
|
`test/programs/frame-rollback.flan`, with three acceptance rows beside `bounds-condition.flan`'s (plain, `-O0`,
|
||||||
dev). Nothing was added to the language, which was the premise: `snapshot` is `(set grid-backup grid)` and
|
dev). Nothing was added to the language, which was the premise: `snapshot` is `(set grid-backup grid)` and
|
||||||
@ -820,7 +820,7 @@ written in `vendor/raylib` now, and have not been.
|
|||||||
|
|
||||||
## ~~Queued: a restart is not a transaction, and the docs must say so~~ — **landed**
|
## ~~Queued: a restart is not a transaction, and the docs must say so~~ — **landed**
|
||||||
|
|
||||||
See [`BUILT.md`](BUILT.md), "A restart is not a transaction". **This entry was stale** — all three places already
|
See [`docs/BUILT.md`](docs/BUILT.md), "A restart is not a transaction". **This entry was stale** — all three places already
|
||||||
carried the note when it was re-read: `conditions.org` under *Gotchas*, `spec-conditions.md` §5, and
|
carried the note when it was re-read: `conditions.org` under *Gotchas*, `spec-conditions.md` §5, and
|
||||||
`web/index.html`'s restart gotcha list, which was rewritten in place rather than gaining a second bullet beside the
|
`web/index.html`'s restart gotcha list, which was rewritten in place rather than gaining a second bullet beside the
|
||||||
existing one. Nothing was left to write.
|
existing one. Nothing was left to write.
|
||||||
@ -841,7 +841,7 @@ skip a frame and carry on rather than die — exactly the case where a non-idemp
|
|||||||
|
|
||||||
## ~~Queued: a dev-build allocation registry~~ — **landed; one item left, and it is not a registry item**
|
## ~~Queued: a dev-build allocation registry~~ — **landed; one item left, and it is not a registry item**
|
||||||
|
|
||||||
Items 1 to 5 are built and the test is written. `BUILT.md`'s *"An address answers with a type"* is the account of the
|
Items 1 to 5 are built and the test is written. `docs/BUILT.md`'s *"An address answers with a type"* is the account of the
|
||||||
table, the note and the inspector's pointer arm; *"An address you have in your hand"* is the account of the reader —
|
table, the note and the inspector's pointer arm; *"An address you have in your hand"* is the account of the reader —
|
||||||
the address root, the breakdown, the leak report, and what "at exit" turned out to mean.
|
the address root, the breakdown, the leak report, and what "at exit" turned out to mean.
|
||||||
|
|
||||||
@ -861,7 +861,7 @@ do not need the registry. This is for plain structs, `Vec`, `Map` and pool stora
|
|||||||
|
|
||||||
**On cost, as built.** One insert per allocation, always on in a dev build, no opt-out — the author's instruction,
|
**On cost, as built.** One insert per allocation, always on in a dev build, no opt-out — the author's instruction,
|
||||||
followed literally. Nothing was built per-region, no range recording, no per-allocator opt-out. Revisit only if a real
|
followed literally. Nothing was built per-region, no range recording, no per-allocator opt-out. Revisit only if a real
|
||||||
program shows a problem, and `BUILT.md` still names **two** places a release build is not quite free: the readers
|
program shows a problem, and `docs/BUILT.md` still names **two** places a release build is not quite free: the readers
|
||||||
added since are functions nothing in a release build calls, and the exit report is registered by `atexit` from inside
|
added since are functions nothing in a release build calls, and the exit report is registered by `atexit` from inside
|
||||||
`flan_dev_reg_enable` rather than by a file-scope destructor, precisely so that it is not a third.
|
`flan_dev_reg_enable` rather than by a file-scope destructor, precisely so that it is not a third.
|
||||||
|
|
||||||
@ -871,14 +871,14 @@ Three things, in order. The first two are one line each and unblock a real game.
|
|||||||
|
|
||||||
**1. `DrawTexturePro` is not bound — DONE.** It is `draw-texture-pro` in `vendor/raylib/raylib.flan` now, hand-written
|
**1. `DrawTexturePro` is not bound — DONE.** It is `draw-texture-pro` in `vendor/raylib/raylib.flan` now, hand-written
|
||||||
beside `draw-texture-rec` and read off a raylib header rather than remembered. `image-from-image` and `window-ready?`
|
beside `draw-texture-rec` and read off a raylib header rather than remembered. `image-from-image` and `window-ready?`
|
||||||
went in with it. The rule the gap exposed is written down in `BUILT.md` and `PORTING.md` §1: *a raylib function on a
|
went in with it. The rule the gap exposed is written down in `docs/BUILT.md` and `docs/PORTING.md` §1: *a raylib function on a
|
||||||
game's per-frame path is hand-written and header-checked, not left to the opt-in import* — the import widens the
|
game's per-frame path is hand-written and header-checked, not left to the opt-in import* — the import widens the
|
||||||
surface and must not be load-bearing, because the default build has no `FLAN_RAYLIB_H` and still has to draw.
|
surface and must not be load-bearing, because the default build has no `FLAN_RAYLIB_H` and still has to draw.
|
||||||
|
|
||||||
**2. `Key` has no `left-shift` — DONE.** `left-shift 340`, and nothing else: `PORTING.md` §5 checked every other enum
|
**2. `Key` has no `left-shift` — DONE.** `left-shift 340`, and nothing else: `docs/PORTING.md` §5 checked every other enum
|
||||||
value the game touches and they were all already right.
|
value the game touches and they were all already right.
|
||||||
**1. `DrawTexturePro` — done, and not by a hand-written line.** It was the one true blocker for `siam-farmer`
|
**1. `DrawTexturePro` — done, and not by a hand-written line.** It was the one true blocker for `siam-farmer`
|
||||||
(see `PORTING.md`: every tile in both implementations goes through it, and neither `DrawTextureRec` nor
|
(see `docs/PORTING.md`: every tile in both implementations goes through it, and neither `DrawTextureRec` nor
|
||||||
`DrawTextureEx` substitutes). It was reachable only through the opt-in `FLAN_RAYLIB_H` import. The bindings are
|
`DrawTextureEx` substitutes). It was reachable only through the opt-in `FLAN_RAYLIB_H` import. The bindings are
|
||||||
committed now, so `rl/draw-texture-pro` is in `vendor/raylib/generated.flan` and a default build has it. **Nothing
|
committed now, so `rl/draw-texture-pro` is in `vendor/raylib/generated.flan` and a default build has it. **Nothing
|
||||||
should add it by hand** — a second `declare-c` for the same C symbol is refused for the whole program.
|
should add it by hand** — a second `declare-c` for the same C symbol is refused for the whole program.
|
||||||
@ -892,7 +892,7 @@ still a hand edit: the importer generates functions and only functions, so no `d
|
|||||||
the break loop, and tail into the old `flan_bounds_fail` message and status only if nothing answered. `Vec`'s two
|
the break loop, and tail into the old `flan_bounds_fail` message and status only if nothing answered. `Vec`'s two
|
||||||
checks are plumbed the same way, since `(at v i)` and `(at arr i)` are one form in the source.
|
checks are plumbed the same way, since `(at v i)` and `(at arr i)` are one form in the source.
|
||||||
|
|
||||||
**No restart is established at the failing index**, and `BUILT.md` has the argument: `retry` exists for allocation and
|
**No restart is established at the failing index**, and `docs/BUILT.md` has the argument: `retry` exists for allocation and
|
||||||
for files because those attempts are *repeatable*, and nothing a handler can do makes index 51 valid for a length-50
|
for files because those attempts are *repeatable*, and nothing a handler can do makes index 51 valid for a length-50
|
||||||
array. `use-value` for the index would cost every indexing operation a restart frame and buy a silently different
|
array. `use-value` for the index would cost every indexing operation a restart frame and buy a silently different
|
||||||
element. What answers a bad index is the restart the program already had — a frame loop's `continue`, `sand.flan`'s
|
element. What answers a bad index is the restart the program already had — a frame loop's `continue`, `sand.flan`'s
|
||||||
@ -912,22 +912,22 @@ resumes with the session intact.
|
|||||||
different kind of failure — the region the container lived in was released — and there is no frame to go back to that
|
different kind of failure — the region the container lived in was released — and there is no frame to go back to that
|
||||||
would not read freed memory. The map path was left alone rather than converted half-way.
|
would not read freed memory. The map path was left alone rather than converted half-way.
|
||||||
|
|
||||||
### What is left on `PORTING.md`'s list
|
### What is left on `docs/PORTING.md`'s list
|
||||||
|
|
||||||
Tier 0 is finished, and so is item 5. **The watch for a running program is done** — the `spy` half was already
|
Tier 0 is finished, and so is item 5. **The watch for a running program is done** — the `spy` half was already
|
||||||
built (a pushed table, the watch buffer, inline ghost text) and the `spy-num` half landed 2026-09-13: a hot-loop slot
|
built (a pushed table, the watch buffer, inline ghost text) and the `spy-num` half landed 2026-09-13: a hot-loop slot
|
||||||
keeps count/min/max/last/mean, the write path does no formatting, and the window is since the editor's last tick
|
keeps count/min/max/last/mean, the write path does no formatting, and the window is since the editor's last tick
|
||||||
rather than cumulative, which is a deliberate divergence from `watch.clj` argued in `BUILT.md`, "A hot loop keeps
|
rather than cumulative, which is a deliberate divergence from `watch.clj` argued in `docs/BUILT.md`, "A hot loop keeps
|
||||||
five numbers, and the window is the editor's". **Item 6 landed the same day**:
|
five numbers, and the window is the editor's". **Item 6 landed the same day**:
|
||||||
`test/programs/frame-rollback.flan` is the worked example — `snapshot` at the top of the frame, `restore` in the
|
`test/programs/frame-rollback.flan` is the worked example — `snapshot` at the top of the frame, `restore` in the
|
||||||
`continue` clause — and `bounds-condition.flan`'s half-written abandoned frame is the thought it finishes. That was
|
`continue` clause — and `bounds-condition.flan`'s half-written abandoned frame is the thought it finishes. That was
|
||||||
the last Tier 1 item anyone was going to move. Items 7 (`drop`), 8 (generics) and 9 (`(read-edn T bytes)`) are still
|
the last Tier 1 item anyone was going to move. Items 7 (`drop`), 8 (generics) and 9 (`(read-edn T bytes)`) are still
|
||||||
on that list and still deferred with reasons written beside each; none is a blocker for this game.
|
on that list and still deferred with reasons written beside each; none is a blocker for this game.
|
||||||
|
|
||||||
**What `PORTING.md` says NOT to build, with evidence:** escaping closures (one capture site, fixed by one parameter),
|
**What `docs/PORTING.md` says NOT to build, with evidence:** escaping closures (one capture site, fixed by one parameter),
|
||||||
`Handle`/pools, `Result`/`try`, `handler-case`, `loop`/`recur` and tail calls, user allocators, structural typing —
|
`Handle`/pools, `Result`/`try`, `handler-case`, `loop`/`recur` and tail calls, user allocators, structural typing —
|
||||||
**none has a customer in that code**. (`Handle` and the pool were built anyway, and on the other reason: they are the
|
**none has a customer in that code**. (`Handle` and the pool were built anyway, and on the other reason: they are the
|
||||||
gate on classes. The finding stands and is why they were built small — see [`BUILT.md`](BUILT.md). `loop`/`recur` was
|
gate on classes. The finding stands and is why they were built small — see [`docs/BUILT.md`](docs/BUILT.md). `loop`/`recur` was
|
||||||
built too, and the finding stands there as well: what it is not is **tail calls**, which are still not built and still
|
built too, and the finding stands there as well: what it is not is **tail calls**, which are still not built and still
|
||||||
have no customer.) And **generics is not the blocker** there either: the element-changing maps are
|
have no customer.) And **generics is not the blocker** there either: the element-changing maps are
|
||||||
five-line load-time loops. That last one hangs on a design decision the report states flatly — whether the game's
|
five-line load-time loops. That last one hangs on a design decision the report states flatly — whether the game's
|
||||||
@ -940,9 +940,9 @@ byte-identical between 5.5 and the vendored 6.0.
|
|||||||
|
|
||||||
Both lanes committed their main work and died on trailing polish; both are merged and the suite is green.
|
Both lanes committed their main work and died on trailing polish; both are merged and the suite is green.
|
||||||
|
|
||||||
- ~~**`pause` marking from Emacs was not built.**~~ **Built**, both halves. See `BUILT.md`, "A breakpoint is a
|
- ~~**`pause` marking from Emacs was not built.**~~ **Built**, both halves. See `docs/BUILT.md`, "A breakpoint is a
|
||||||
function call, and the editor only says where".
|
function call, and the editor only says where".
|
||||||
- ~~**Ghost text** for the watch window — values shown inline at the code they belong to — is noted and not designed.~~ **Built.** See `BUILT.md`, "Ghost text finds its anchor in the buffer, not in the table".
|
- ~~**Ghost text** for the watch window — values shown inline at the code they belong to — is noted and not designed.~~ **Built.** See `docs/BUILT.md`, "Ghost text finds its anchor in the buffer, not in the table".
|
||||||
- `tools/unit-return.py` is re-runnable; run it over any `.flan` file a lane wrote before the conversion landed.
|
- `tools/unit-return.py` is re-runnable; run it over any `.flan` file a lane wrote before the conversion landed.
|
||||||
|
|
||||||
# Where this is
|
# Where this is
|
||||||
@ -951,11 +951,11 @@ Both lanes committed their main work and died on trailing polish; both are merge
|
|||||||
|
|
||||||
**Branch `dev-loop`, 199 commits, working tree clean, `dune test` green.**
|
**Branch `dev-loop`, 199 commits, working tree clean, `dune test` green.**
|
||||||
|
|
||||||
**[`DISCUSS.md`](DISCUSS.md) is what has been *asked* and not answered** — open questions with the repo context that
|
**[`docs/DISCUSS.md`](docs/DISCUSS.md) is what has been *asked* and not answered** — open questions with the repo context that
|
||||||
bears on each, so an investigation starts from what exists. Nothing in it is a decision or a task; when one becomes
|
bears on each, so an investigation starts from what exists. Nothing in it is a decision or a task; when one becomes
|
||||||
either, it moves here.
|
either, it moves here.
|
||||||
|
|
||||||
**`NEXT.md` is what is left. [`BUILT.md`](BUILT.md) is why the existing parts are the shape they are** — the reload
|
**`NEXT.md` is what is left. [`docs/BUILT.md`](docs/BUILT.md) is why the existing parts are the shape they are** — the reload
|
||||||
primitive, cells, the agent, the session, the daemon, the Emacs client, conditions, the FFI shim, the layout, and the
|
primitive, cells, the agent, the session, the daemon, the Emacs client, conditions, the FFI shim, the layout, and the
|
||||||
order it all got built in. This file was half build log until it was split; do not let it become one again. When a
|
order it all got built in. This file was half build log until it was split; do not let it become one again. When a
|
||||||
track here finishes, its explanation moves there and its entry here goes away.
|
track here finishes, its explanation moves there and its entry here goes away.
|
||||||
@ -994,7 +994,7 @@ The expander is written and the exit criterion plan.org set for milestone 5 is m
|
|||||||
unchanged. Running `test/programs/macro-unless.flan` means the compiler built a shared object, `dlopen`ed it into
|
unchanged. Running `test/programs/macro-unless.flan` means the compiler built a shared object, `dlopen`ed it into
|
||||||
itself and called a Flan function to find out what `(unless c a b)` means.
|
itself and called a Flan function to find out what `(unless c a b)` means.
|
||||||
|
|
||||||
The full explanation is in [`BUILT.md`](BUILT.md), "Macros: the compiler dlopens the program". Four things worth
|
The full explanation is in [`docs/BUILT.md`](docs/BUILT.md), "Macros: the compiler dlopens the program". Four things worth
|
||||||
knowing before touching any of it, because each cost something to find:
|
knowing before touching any of it, because each cost something to find:
|
||||||
|
|
||||||
- **A call inside a quasiquote is output, not a compile-order dependency.** A macro body that *calls* another macro
|
- **A call inside a quasiquote is output, not a compile-order dependency.** A macro body that *calls* another macro
|
||||||
@ -1017,10 +1017,10 @@ difference being a cached `.so`; and a hello-world carries eight bytes of it, be
|
|||||||
|
|
||||||
### Landed — a C header is read, so a binding is checked instead of trusted
|
### Landed — a C header is read, so a binding is checked instead of trusted
|
||||||
|
|
||||||
`lib/cimport.ml`, `lib/cjson.ml`, a `headers` file beside `link`. Full reasoning in `BUILT.md`, "The header is read
|
`lib/cimport.ml`, `lib/cjson.ml`, a `headers` file beside `link`. Full reasoning in `docs/BUILT.md`, "The header is read
|
||||||
now"; DISCUSS.md item 6 is rewritten down to the two decisions left, both the author's.
|
now"; docs/DISCUSS.md item 6 is rewritten down to the two decisions left, both the author's.
|
||||||
|
|
||||||
The gap closed is the one `BUILT.md` recorded as *trusted*: `declare-c` generates the wrapper, the typedefs and the
|
The gap closed is the one `docs/BUILT.md` recorded as *trusted*: `declare-c` generates the wrapper, the typedefs and the
|
||||||
prototype from one declaration, so they agree with each other by construction and only the library could disagree —
|
prototype from one declaration, so they agree with each other by construction and only the library could disagree —
|
||||||
and nothing had a second opinion to disagree with. Now clang is asked for a JSON AST dump of the header (shelled out,
|
and nothing had a second opinion to disagree with. Now clang is asked for a JSON AST dump of the header (shelled out,
|
||||||
never libclang — the dependency plan.org rejected; Zig has since left it too, for Aro) and both halves are compared
|
never libclang — the dependency plan.org rejected; Zig has since left it too, for Aro) and both halves are compared
|
||||||
@ -1030,14 +1030,14 @@ against it.
|
|||||||
all 172 hand-written `declare-c` agree exactly.** Against the 5.1-dev header also installed on this machine, ten real
|
all 172 hand-written `declare-c` agree exactly.** Against the 5.1-dev header also installed on this machine, ten real
|
||||||
differences — nine functions that version lacks and one that gained a parameter — so picking the wrong header is
|
differences — nine functions that version lacks and one that gained a parameter — so picking the wrong header is
|
||||||
loud. Both comparisons run at build time and stop the build; verified by permuting `Texture2D` and by putting `f64`
|
loud. Both comparisons run at build time and stop the build; verified by permuting `Texture2D` and by putting `f64`
|
||||||
where raylib says `float`, which is the hazard `BUILT.md` names and says only a test can catch.
|
where raylib says `float`, which is the hazard `docs/BUILT.md` names and says only a test can catch.
|
||||||
|
|
||||||
**Costs, measured, because they decide the remaining question.** Release build +4ms warm — `Reach.link` already drops
|
**Costs, measured, because they decide the remaining question.** Release build +4ms warm — `Reach.link` already drops
|
||||||
a wrapper nothing reachable calls, confirmed on the wasm32 case it exists for with 256 extra declarations in play.
|
a wrapper nothing reachable calls, confirmed on the wasm32 case it exists for with 256 extra declarations in play.
|
||||||
Redefinition 31.0ms → 46.5ms. Dev build +333ms cold, once per session, since `Build.shared` compiles no C. Reading the
|
Redefinition 31.0ms → 46.5ms. Dev build +333ms cold, once per session, since `Build.shared` compiles no C. Reading the
|
||||||
header is cached (64ms → 17ms), keyed like the object cache; the cache was built against a measurement, not a guess.
|
header is cached (64ms → 17ms), keyed like the object cache; the cache was built against a measurement, not a guess.
|
||||||
|
|
||||||
**Re-measured, and the 15.5ms was misattributed** — see BUILT.md, "Where that 15.5ms actually is". A `C-c C-c` reads
|
**Re-measured, and the 15.5ms was misattributed** — see docs/BUILT.md, "Where that 15.5ms actually is". A `C-c C-c` reads
|
||||||
no header: `Session.eval` puts the forms through `Load`, and forms with no `(import …)` in them touch no package. The
|
no header: `Session.eval` puts the forms through `Load`, and forms with no `(import …)` in them touch no package. The
|
||||||
15.5ms is `flan reload`'s, and `flan reload` is a fresh process — ~14.5ms of it is session startup and ~4ms of *that*
|
15.5ms is `flan reload`'s, and `flan reload` is a fresh process — ~14.5ms of it is session startup and ~4ms of *that*
|
||||||
is the header. What a redefinition really pays for an imported package is **+3.6ms per eval** in `Check` and in
|
is the header. What a redefinition really pays for an imported package is **+3.6ms per eval** in `Check` and in
|
||||||
@ -1057,7 +1057,7 @@ Worth knowing before touching it:
|
|||||||
172 are already bound by hand and left alone. Widening the binding is a `defstruct`, not a list edit.
|
172 are already bound by hand and left alone. Widening the binding is a `defstruct`, not a list edit.
|
||||||
- **No `defstruct` is generated, and that is load-bearing.** Generate them and the header becomes the authority on
|
- **No `defstruct` is generated, and that is load-bearing.** Generate them and the header becomes the authority on
|
||||||
layout, and checking the package's layouts against it would be comparing the header with itself — which is exactly
|
layout, and checking the package's layouts against it would be comparing the header with itself — which is exactly
|
||||||
why `BUILT.md` rejected a `_Static_assert` as circular. Keeping them hand-written is what makes the check a second
|
why `docs/BUILT.md` rejected a `_Static_assert` as circular. Keeping them hand-written is what makes the check a second
|
||||||
source.
|
source.
|
||||||
- **A refusal is a demotion, not a drop** — Zig's `failDecl`, which `Load.refuse_hidden` already implemented for
|
- **A refusal is a demotion, not a drop** — Zig's `failDecl`, which `Load.refuse_hidden` already implemented for
|
||||||
`main`. `rl/get-gamepad-name` is a name that exists, cannot be had, and says why at the use site.
|
`main`. `rl/get-gamepad-name` is a name that exists, cannot be had, and says why at the use site.
|
||||||
@ -1066,7 +1066,7 @@ Worth knowing before touching it:
|
|||||||
- **`test/headers/sample.h`** is the importer's table — one function per decision, committed, no raylib needed. The
|
- **`test/headers/sample.h`** is the importer's table — one function per decision, committed, no raylib needed. The
|
||||||
raylib acceptance case skips without `FLAN_RAYLIB_H`; that one does not.
|
raylib acceptance case skips without `FLAN_RAYLIB_H`; that one does not.
|
||||||
|
|
||||||
Two things that are *not* done, and are 6a and 6b in DISCUSS.md: whether the header stays a build-time read or becomes
|
Two things that are *not* done, and are 6a and 6b in docs/DISCUSS.md: whether the header stays a build-time read or becomes
|
||||||
a committed generator (`flan import-c` already prints the lines, so it costs nothing more to switch), and whether the
|
a committed generator (`flan import-c` already prints the lines, so it costs nothing more to switch), and whether the
|
||||||
172 hand-written lines migrate. Neither is blocked on correctness. The argument for the first is weaker than it
|
172 hand-written lines migrate. Neither is blocked on correctness. The argument for the first is weaker than it
|
||||||
looked — committing the generated lines would save ~4ms of session startup and none of the +3.6ms per redefinition,
|
looked — committing the generated lines would save ~4ms of session startup and none of the +3.6ms per redefinition,
|
||||||
@ -1081,7 +1081,7 @@ sibling of a call that worked did not — by excluding them and hand-writing the
|
|||||||
|
|
||||||
### Landed 2026-09-12 — six tracks, one session
|
### Landed 2026-09-12 — six tracks, one session
|
||||||
|
|
||||||
Six agents in parallel worktrees. Kept short on purpose; the reasoning that outlives the change is in `BUILT.md` or in
|
Six agents in parallel worktrees. Kept short on purpose; the reasoning that outlives the change is in `docs/BUILT.md` or in
|
||||||
the commit that made it.
|
the commit that made it.
|
||||||
|
|
||||||
1. **`nth` removed**, an alias of `at` that was asymmetric — `check.ml` aliased them but `parse.ml` and
|
1. **`nth` removed**, an alias of `at` that was asymmetric — `check.ml` aliased them but `parse.ml` and
|
||||||
@ -1140,7 +1140,7 @@ is written down rather than left out; see the unsettled list under the build ord
|
|||||||
The critical path, and the thing NEXT.md said was the only one standing between this and writing a game. Steps 1, 2 and
|
The critical path, and the thing NEXT.md said was the only one standing between this and writing a game. Steps 1, 2 and
|
||||||
3 of the build order below are struck; `Map` is step 4 and is untouched. `Allocator` is a builtin opaque type and
|
3 of the build order below are struck; `Map` is step 4 and is untouched. `Allocator` is a builtin opaque type and
|
||||||
needed nothing from milestone 5, which was the whole bet. Three amendments to a **frozen** `spec-memory.md`, made
|
needed nothing from milestone 5, which was the whole bet. Three amendments to a **frozen** `spec-memory.md`, made
|
||||||
deliberately and stated as amendments in [`BUILT.md`](BUILT.md): `free-all` is retain-capacity with `arena-destroy`
|
deliberately and stated as amendments in [`docs/BUILT.md`](docs/BUILT.md): `free-all` is retain-capacity with `arena-destroy`
|
||||||
beside it; `context/allocator` is a dynamic variable rather than a literal calling-convention parameter; and the `Vec`
|
beside it; `context/allocator` is a dynamic variable rather than a literal calling-convention parameter; and the `Vec`
|
||||||
header is six words in every build rather than four in release. One addition the spec does not have: a budget on the
|
header is six words in every build rather than four in release. One addition the spec does not have: a budget on the
|
||||||
allocator, because `retry` needs a handler that can make the *same* request succeed.
|
allocator, because `retry` needs a handler that can make the *same* request succeed.
|
||||||
@ -1150,7 +1150,7 @@ allocator, because `retry` needs a handler that can make the *same* request succ
|
|||||||
`--sanitize` is a build flag beside `--debug`; `dune build --root . @sanitize` builds twenty-eight programs twice, plain
|
`--sanitize` is a build flag beside `--debug`; `dune build --root . @sanitize` builds twenty-eight programs twice, plain
|
||||||
and sanitized, and compares output and exit status. Its own alias and not `dune test`, because the sweep is about nine
|
and sanitized, and compares output and exit status. Its own alias and not `dune test`, because the sweep is about nine
|
||||||
minutes. The checked sweep is **clean**. How ASan and UBSan reach a language whose IR is written by hand, and why the
|
minutes. The checked sweep is **clean**. How ASan and UBSan reach a language whose IR is written by hand, and why the
|
||||||
flag does not force `-O0` when `--debug` does, is in [`BUILT.md`](BUILT.md).
|
flag does not force `-O0` when `--debug` does, is in [`docs/BUILT.md`](docs/BUILT.md).
|
||||||
|
|
||||||
Two defects came out of it, both found by reading rather than by the tools, both fixed with a regression case:
|
Two defects came out of it, both found by reading rather than by the tools, both fixed with a regression case:
|
||||||
`flan_bytes_to_i64`/`flan_bytes_to_f64` clamped a slice length with `(size_t)n` and so read 63 or 511 bytes off the end
|
`flan_bytes_to_i64`/`flan_bytes_to_f64` clamped a slice length with `(size_t)n` and so read 63 or 511 bytes off the end
|
||||||
@ -1182,7 +1182,7 @@ it *would* have written.
|
|||||||
control that must report: index 3 of a `Vec` with len 2 and cap 4, with `--track-origins` naming the
|
control that must report: index 3 of a `Vec` with len 2 and cap 4, with `--track-origins` naming the
|
||||||
`aligned_alloc` in `flan_vec_push`. Two more controls pin a heap overrun and a padded `Map` key. `test/valgrind.supp`
|
`aligned_alloc` in `flan_vec_push`. Two more controls pin a heap overrun and a padded `Map` key. `test/valgrind.supp`
|
||||||
holds **no suppressions** — nothing false came up to suppress. Details, and the measured fact that memcheck catches
|
holds **no suppressions** — nothing false came up to suppress. Details, and the measured fact that memcheck catches
|
||||||
0 of `bounds.flan`'s 6 cases where ASan catches 3, in [`BUILT.md`](BUILT.md).
|
0 of `bounds.flan`'s 6 cases where ASan catches 3, in [`docs/BUILT.md`](docs/BUILT.md).
|
||||||
|
|
||||||
**The arena half of the hole is closed; the interior half cannot be.** `free-all` is retain-capacity, so the pages
|
**The arena half of the hole is closed; the interior half cannot be.** `free-all` is retain-capacity, so the pages
|
||||||
stay and `malloc` never learns the storage died — but memcheck can be told directly, and now is: `flan_arena_proc`
|
stay and `malloc` never learns the storage died — but memcheck can be told directly, and now is: `flan_arena_proc`
|
||||||
@ -1192,7 +1192,7 @@ it *would* have written.
|
|||||||
control. Cost outside valgrind is five no-op instructions plus the request block — 23 on the `free-all` path only,
|
control. Cost outside valgrind is five no-op instructions plus the request block — 23 on the `free-all` path only,
|
||||||
about 1ns per reset — and the macro is vendored rather than `#include`d because the machine that runs the sweep
|
about 1ns per reset — and the macro is vendored rather than `#include`d because the machine that runs the sweep
|
||||||
has `valgrind` and not `valgrind-devel`, so a guarded include would silently compile to nothing exactly here. See
|
has `valgrind` and not `valgrind-devel`, so a guarded include would silently compile to nothing exactly here. See
|
||||||
[`BUILT.md`](BUILT.md).
|
[`docs/BUILT.md`](docs/BUILT.md).
|
||||||
|
|
||||||
**Interior overruns remain invisible**, for a structural reason no client request fixes — an arena is one `malloc`,
|
**Interior overruns remain invisible**, for a structural reason no client request fixes — an arena is one `malloc`,
|
||||||
and the `Map`'s `keys | values | hashes | scratch` is one allocation too, so "probe overrun at high load" is not
|
and the `Map`'s `keys | values | hashes | scratch` is one allocation too, so "probe overrun at high load" is not
|
||||||
@ -1253,7 +1253,7 @@ Either way it is an amendment to a **frozen** `spec-conditions.md`, not a gap in
|
|||||||
program, at that program's next frame boundary. Verified against sand: an unsaved buffer edit to `game-draw`, and 240
|
program, at that program's next frame boundary. Verified against sand: an unsaved buffer edit to `game-draw`, and 240
|
||||||
consecutive frames drew it.
|
consecutive frames drew it.
|
||||||
|
|
||||||
Steps 1, 2 and 3 are done — see *The reload primitive* in `BUILT.md`. A list of top-level forms can be recompiled and installed
|
Steps 1, 2 and 3 are done — see *The reload primitive* in `docs/BUILT.md`. A list of top-level forms can be recompiled and installed
|
||||||
into a running process; call sites compiled before they existed follow them, and a `defn` or `defvar` the process was
|
into a running process; call sites compiled before they existed follow them, and a `defn` or `defvar` the process was
|
||||||
never built with can be added and then redefined again. That is the whole of `C-c C-c`, minus an editor: sand.flan takes
|
never built with can be added and then redefined again. That is the whole of `C-c C-c`, minus an editor: sand.flan takes
|
||||||
a redefinition over a socket and installs it between frames.
|
a redefinition over a socket and installs it between frames.
|
||||||
@ -1263,7 +1263,7 @@ running process was built with, and speaks a protocol an editor can talk to.
|
|||||||
|
|
||||||
Milestone 4 is done: **sand.flan builds, links raylib and runs**, and its simulation has a headless acceptance case that
|
Milestone 4 is done: **sand.flan builds, links raylib and runs**, and its simulation has a headless acceptance case that
|
||||||
runs on the `dune test` path at `-O0` and `-O2`. Milestones 2 and 3 are behind it (`calc-me.flan` compiles and runs; the
|
runs on the `dune test` path at `-O0` and `-O2`. Milestones 2 and 3 are behind it (`calc-me.flan` compiles and runs; the
|
||||||
interpreter was dropped — open decision #7, settled — see "Why there is no interpreter" in `BUILT.md`).
|
interpreter was dropped — open decision #7, settled — see "Why there is no interpreter" in `docs/BUILT.md`).
|
||||||
|
|
||||||
```
|
```
|
||||||
reader ✅ → parse ✅ → load ✅ → check ✅ → emit ✅ → clang ✅
|
reader ✅ → parse ✅ → load ✅ → check ✅ → emit ✅ → clang ✅
|
||||||
@ -1322,7 +1322,7 @@ $ flan run sand.flan # a window, 120 fps, hold space
|
|||||||
Five questions were put and answered in one sitting. Each is a decision, not a preference — build against them, and
|
Five questions were put and answered in one sitting. Each is a decision, not a preference — build against them, and
|
||||||
reopen one only with a reason rather than a taste.
|
reopen one only with a reason rather than a taste.
|
||||||
|
|
||||||
~~**1. Assets are embedded at compile time, one file or one directory.**~~ **Built** — `(embed "p")`, `(embed "p" string)`, `(embed-dir "d")`. See BUILT.md, "Assets are baked in". Odin's answer, and the reason it is the right
|
~~**1. Assets are embedded at compile time, one file or one directory.**~~ **Built** — `(embed "p")`, `(embed "p" string)`, `(embed-dir "d")`. See docs/BUILT.md, "Assets are baked in". Odin's answer, and the reason it is the right
|
||||||
one here: it is a *compiler* feature, so it needs no build flags, no linker arguments and no per-target packaging, and
|
one here: it is a *compiler* feature, so it needs no build flags, no linker arguments and no per-target packaging, and
|
||||||
it works identically on desktop and web. That matters more here than it does for Odin, because `Load` gives link flags
|
it works identically on desktop and web. That matters more here than it does for Odin, because `Load` gives link flags
|
||||||
only to directory packages — the single file doing `(rl/load-texture "brush.png")` is structurally the one file with
|
only to directory packages — the single file doing `(rl/load-texture "brush.png")` is structurally the one file with
|
||||||
@ -1331,7 +1331,7 @@ no link channel, which is what stopped the web lane from inventing a flag. Embed
|
|||||||
`--preload-file` stays available later for assets that should load lazily rather than be baked in; the `@web` link
|
`--preload-file` stays available later for assets that should load lazily rather than be baked in; the `@web` link
|
||||||
line already carries it if wanted.
|
line already carries it if wanted.
|
||||||
|
|
||||||
~~**2. Reading a file works everywhere; writing is desktop-only and signals on web.**~~ **Built** — `barf` on the web signals `FileError` with reason `file-unsupported`, and `test/test_web.ml` runs it under node rather than asserting the artifact's shape. See BUILT.md, "slurp, barf, and the two ways they fail". Odin stubs its whole file API on
|
~~**2. Reading a file works everywhere; writing is desktop-only and signals on web.**~~ **Built** — `barf` on the web signals `FileError` with reason `file-unsupported`, and `test/test_web.ml` runs it under node rather than asserting the artifact's shape. See docs/BUILT.md, "slurp, barf, and the two ways they fail". Odin stubs its whole file API on
|
||||||
js/wasm — every operation returns `.Unsupported`, and `core/os/file_js.odin`'s own comment says the stubs exist only
|
js/wasm — every operation returns `.Unsupported`, and `core/os/file_js.odin`'s own comment says the stubs exist only
|
||||||
so importing `core:os` "panics cleanly". Take the restriction and not the mechanism. **Flan has no conditional
|
so importing `core:os` "panics cleanly". Take the restriction and not the mechanism. **Flan has no conditional
|
||||||
compilation** — nothing in `parse.ml` or `check.ml` reads the target — so "isolate this code to desktop" is not
|
compilation** — nothing in `parse.ml` or `check.ml` reads the target — so "isolate this code to desktop" is not
|
||||||
@ -1340,7 +1340,7 @@ it is how a save file disappears with nothing said. So `barf` on web signals a c
|
|||||||
program decides. This is the language having something Odin does not; use it. Per-package target isolation, if a
|
program decides. This is the language having something Odin does not; use it. Per-package target isolation, if a
|
||||||
whole desktop-only package is ever wanted, is the `@native`/`@wasi`/`@web` link-line tagging the web lane built.
|
whole desktop-only package is ever wanted, is the `@native`/`@wasi`/`@web` link-line tagging the web lane built.
|
||||||
|
|
||||||
**3. Build the shadow stack.** ~~Not yet built.~~ **Built**, both halves — see BUILT.md. Kept here as the decision it
|
**3. Build the shadow stack.** ~~Not yet built.~~ **Built**, both halves — see docs/BUILT.md. Kept here as the decision it
|
||||||
was, with the measurement it asked for: +33% on call-heavy code over globals for the frames, +61% with the slot table,
|
was, with the measurement it asked for: +33% on call-heavy code over globals for the frames, +61% with the slot table,
|
||||||
and 0.06% of a 60fps frame.
|
and 0.06% of a 60fps frame.
|
||||||
|
|
||||||
@ -1371,7 +1371,7 @@ length is not known until the file is read and therefore cannot exist before an
|
|||||||
refusal names the new one. `:keys` kept its colon — it names no field, so leaving it alone is what lets the dot mean
|
refusal names the new one. `:keys` kept its colon — it names no field, so leaving it alone is what lets the dot mean
|
||||||
exactly one thing. 681 labels across 45 `.flan` files including `vendor/`, plus 94 more in the Flan embedded in
|
exactly one thing. 681 labels across 45 `.flan` files including `vendor/`, plus 94 more in the Flan embedded in
|
||||||
`lib/prelude.ml` and the tests. `Map` is now free to take `{:key value}` without colliding with struct literals. See
|
`lib/prelude.ml` and the tests. `Map` is now free to take `{:key value}` without colliding with struct literals. See
|
||||||
BUILT.md, "The colon belongs to keys".
|
docs/BUILT.md, "The colon belongs to keys".
|
||||||
|
|
||||||
**What it left for the Emacs lane, both verified.** `render.ml` still *prints* a struct with colons, deliberately:
|
**What it left for the Emacs lane, both verified.** `render.ml` still *prints* a struct with colons, deliberately:
|
||||||
`emacs/flan-inspect.el:165` parses that output and hard-codes the colon when it reads a field out, so the printer
|
`emacs/flan-inspect.el:165` parses that output and hard-codes the colon when it reads a field out, so the printer
|
||||||
@ -1408,7 +1408,7 @@ reason there is no collector.
|
|||||||
|
|
||||||
**Globals in the break buffer — built.** One section under the stack, holding the union of the globals every frame on
|
**Globals in the break buffer — built.** One section under the stack, holding the union of the globals every frame on
|
||||||
the current stack references, each entry annotated with the frames that touch it and ordered by the innermost one. It
|
the current stack references, each entry annotated with the frames that touch it and ordered by the innermost one. It
|
||||||
is `(:op "globals")` in `dev.ml` and `flan-cnr--insert-globals` in the break buffer. See BUILT.md, "Globals of a
|
is `(:op "globals")` in `dev.ml` and `flan-cnr--insert-globals` in the break buffer. See docs/BUILT.md, "Globals of a
|
||||||
stopped stack". ~~The one hole left open — the redefinition check is a fingerprint over a body's *slots*, so a new body
|
stopped stack". ~~The one hole left open — the redefinition check is a fingerprint over a body's *slots*, so a new body
|
||||||
that names different globals while binding the same locals is not caught.~~ **Closed**: `Reach.ref_fingerprint` is a
|
that names different globals while binding the same locals is not caught.~~ **Closed**: `Reach.ref_fingerprint` is a
|
||||||
second fingerprint over the set of globals a body names, carried beside the slot one in `%fninfo` and checked the same
|
second fingerprint over the set of globals a body names, carried beside the slot one in `%fninfo` and checked the same
|
||||||
@ -1428,7 +1428,7 @@ mid-edit in another buffer.
|
|||||||
that nothing starts on managed classes "until ordinary `struct`, `Handle`, and reload semantics are working". All
|
that nothing starts on managed classes "until ordinary `struct`, `Handle`, and reload semantics are working". All
|
||||||
three now hold: structs work fully; reload works with one known hole (a changed signature is refused rather than
|
three now hold: structs work fully; reload works with one known hole (a changed signature is refused rather than
|
||||||
versioned); and `(Handle T)` and `(Pool T)` exist, with the enumeration primitive `migrate-instances` was blocked on.
|
versioned); and `(Handle T)` and `(Pool T)` exist, with the enumeration primitive `migrate-instances` was blocked on.
|
||||||
See [`BUILT.md`](BUILT.md), "`(Handle T)` and the pool, which is what a stale reference answers with".
|
See [`docs/BUILT.md`](docs/BUILT.md), "`(Handle T)` and the pool, which is what a stale reference answers with".
|
||||||
|
|
||||||
It was not an incidental precondition. `migrate-instances` has to *enumerate* live instances, and a pool behind a
|
It was not an incidental precondition. `migrate-instances` has to *enumerate* live instances, and a pool behind a
|
||||||
generational `(Handle T)` gives that by construction while a world arena and an owned region do not. plan.org presents
|
generational `(Handle T)` gives that by construction while a world arena and an owned region do not. plan.org presents
|
||||||
@ -1482,11 +1482,11 @@ acquisitions against releases at that boundary and report what is still held at
|
|||||||
annotation, nothing running at a distance — it does not change how code is written, it reports when something was
|
annotation, nothing running at a distance — it does not change how code is written, it reports when something was
|
||||||
forgotten.
|
forgotten.
|
||||||
|
|
||||||
## ~~Before the batch below: read `DISCUSS.md`'s "NEXT SESSION STARTS HERE"~~ — **answered, and being unwound**
|
## ~~Before the batch below: read `docs/DISCUSS.md`'s "NEXT SESSION STARTS HERE"~~ — **answered, and being unwound**
|
||||||
|
|
||||||
The architectural question raised at the end of 2026-09-12 — **putting the compiler inside the running program's
|
The architectural question raised at the end of 2026-09-12 — **putting the compiler inside the running program's
|
||||||
process** — was researched (`DISCUSS.md` §14), then built: `flan dev` is one binary and one process, and the editor
|
process** — was researched (`docs/DISCUSS.md` §14), then built: `flan dev` is one binary and one process, and the editor
|
||||||
socket did not move. See "One process" in [`BUILT.md`](BUILT.md).
|
socket did not move. See "One process" in [`docs/BUILT.md`](docs/BUILT.md).
|
||||||
|
|
||||||
What it reopened is now being deleted one piece at a time, each with its own green run:
|
What it reopened is now being deleted one piece at a time, each with its own green run:
|
||||||
|
|
||||||
@ -1516,7 +1516,7 @@ whether an in-process JIT or a hand-written backend is needed at all.
|
|||||||
|
|
||||||
## ~~Queued: a second tier of the standard library, after macros~~ — **landed**
|
## ~~Queued: a second tier of the standard library, after macros~~ — **landed**
|
||||||
|
|
||||||
See [`BUILT.md`](BUILT.md), "The prelude's second tier". The diagnosis here was right and the prelude had 44
|
See [`docs/BUILT.md`](docs/BUILT.md), "The prelude's second tier". The diagnosis here was right and the prelude had 44
|
||||||
allocation-free functions because there was nothing to allocate from; there are 24 more now, and the "Refused, by
|
allocation-free functions because there was nothing to allocate from; there are 24 more now, and the "Refused, by
|
||||||
name" block at the foot of `prelude.ml` is down from eight entries to four, each with a *different* reason rather
|
name" block at the foot of `prelude.ml` is down from eight entries to four, each with a *different* reason rather
|
||||||
than the one shared sentence.
|
than the one shared sentence.
|
||||||
@ -1534,14 +1534,14 @@ Tests: `programs/strings.flan`, `programs/format.flan`, `programs/algorithms.fla
|
|||||||
them wants a language decision.
|
them wants a language decision.
|
||||||
|
|
||||||
- ~~**`Map` keys and values.**~~ **Iteration is built** — `flan_map_next` and the `map-next!` builtin, exactly the
|
- ~~**`Map` keys and values.**~~ **Iteration is built** — `flan_map_next` and the `map-next!` builtin, exactly the
|
||||||
shape this described. See [`BUILT.md`](BUILT.md), "`map-next!`, the one thing a Map could not do".
|
shape this described. See [`docs/BUILT.md`](docs/BUILT.md), "`map-next!`, the one thing a Map could not do".
|
||||||
`map-keys`/`map-values` as *prelude functions* stay refused, and the reason is now generics rather than the
|
`map-keys`/`map-values` as *prelude functions* stay refused, and the reason is now generics rather than the
|
||||||
iterator: a `defn` has to name its types and `(defn map-keys [m {K V}] (Vec K))` has no `K`. The loop is three
|
iterator: a `defn` has to name its types and `(defn map-keys [m {K V}] (Vec K))` has no `K`. The loop is three
|
||||||
lines at the call site, where `K` is known.
|
lines at the call site, where `K` is known.
|
||||||
|
|
||||||
- ~~**`map`, `filter`, `reduce`, and a sort taking a comparator.**~~ **All four are in the prelude.** The diagnosis
|
- ~~**`map`, `filter`, `reduce`, and a sort taking a comparator.**~~ **All four are in the prelude.** The diagnosis
|
||||||
was right and is now evidenced: **function values, not generics** — they arrived with no generics at all. See
|
was right and is now evidenced: **function values, not generics** — they arrived with no generics at all. See
|
||||||
[`BUILT.md`](BUILT.md), "Function values, with no capture". They are one copy per element type (i32 and f32), which
|
[`docs/BUILT.md`](docs/BUILT.md), "Function values, with no capture". They are one copy per element type (i32 and f32), which
|
||||||
is the half generics would remove, and a `map` that *changes* the element type is the one shape that did not come
|
is the half generics would remove, and a `map` that *changes* the element type is the one shape that did not come
|
||||||
with them — one copy per ordered pair of types rather than per type.
|
with them — one copy per ordered pair of types rather than per type.
|
||||||
|
|
||||||
@ -1563,7 +1563,7 @@ them wants a language decision.
|
|||||||
Two smaller findings, both written down beside the code that ran into them:
|
Two smaller findings, both written down beside the code that ran into them:
|
||||||
|
|
||||||
- ~~**The prelude is never macro-expanded.**~~ **Fixed, and the diagnosis above was wrong in both halves** — see
|
- ~~**The prelude is never macro-expanded.**~~ **Fixed, and the diagnosis above was wrong in both halves** — see
|
||||||
[`BUILT.md`](BUILT.md), "A prelude function may call a prelude macro". The prelude *does* reach the expander; the
|
[`docs/BUILT.md`](docs/BUILT.md), "A prelude function may call a prelude macro". The prelude *does* reach the expander; the
|
||||||
arity error came from the `Check.program` *inside* `Macro.compile`, where expansion is off. It is a cycle and not
|
arity error came from the `Check.program` *inside* `Macro.compile`, where expansion is off. It is a cycle and not
|
||||||
an ordering — a macro module is compiled from the prelude — so moving the prepend would have changed nothing. What
|
an ordering — a macro module is compiled from the prelude — so moving the prepend would have changed nothing. What
|
||||||
fixed it is `Macro.reduce`, which makes the prelude smaller for that one build, plus dropping the prelude's own
|
fixed it is `Macro.reduce`, which makes the prelude smaller for that one build, plus dropping the prelude's own
|
||||||
@ -1642,7 +1642,7 @@ destination is always honest about what it is.
|
|||||||
|
|
||||||
Drop Clojure's `:eduction` branch — that is the pass-around case, and the one part that would need runtime machinery.
|
Drop Clojure's `:eduction` branch — that is the pass-around case, and the one part that would need runtime machinery.
|
||||||
|
|
||||||
**Done.** See *`into`, which fuses at compile time because it is a macro* in [`BUILT.md`](BUILT.md). It is a prelude
|
**Done.** See *`into`, which fuses at compile time because it is a macro* in [`docs/BUILT.md`](docs/BUILT.md). It is a prelude
|
||||||
`defmacro` over a plain `defn` that walks the transforms in reverse, and all four of the macro limits bit without
|
`defmacro` over a plain `defn` that walks the transforms in reverse, and all four of the macro limits bit without
|
||||||
blocking anything: the three refusals are names nothing defines, `into-wrap` uses only special forms so
|
blocking anything: the three refusals are names nothing defines, `into-wrap` uses only special forms so
|
||||||
`Macro.reduce` does not drop it, the quasiquotes are all single-level, and `into` lives in the prelude because a
|
`Macro.reduce` does not drop it, the quasiquotes are all single-level, and `into` lives in the prelude because a
|
||||||
@ -1664,7 +1664,7 @@ this, and it does not exist.
|
|||||||
## ~~Queued: `loop`/`recur` (the return type is done)~~ — **landed**
|
## ~~Queued: `loop`/`recur` (the return type is done)~~ — **landed**
|
||||||
|
|
||||||
~~**1. A `defn` must always state its return type, and unit is written `()`.**~~ **Done.** See *The return type is
|
~~**1. A `defn` must always state its return type, and unit is written `()`.**~~ **Done.** See *The return type is
|
||||||
the slot, and unit is `()`* in [`BUILT.md`](BUILT.md).
|
the slot, and unit is `()`* in [`docs/BUILT.md`](docs/BUILT.md).
|
||||||
|
|
||||||
The slot after the parameters is unconditionally a type, the pre-pass that collected a file's type names is gone
|
The slot after the parameters is unconditionally a type, the pre-pass that collected a file's type names is gone
|
||||||
along with `is_type_form`, `qualified_type`, `types_in`, `declared_types` and `prelude_types`, and `Parse.decl` no
|
along with `is_type_form`, `qualified_type`, `types_in`, `declared_types` and `prelude_types`, and `Parse.decl` no
|
||||||
@ -1690,10 +1690,10 @@ python3 tools/unit-return.py --in-html web/index.html
|
|||||||
|
|
||||||
`-v` logs every `defn` it saw and what it decided; `--check` changes nothing. It is re-runnable, and on this tree it
|
`-v` logs every `defn` it saw and what it decided; `--check` changes nothing. It is re-runnable, and on this tree it
|
||||||
reports exactly six sites, all in `test_flan.ml`, which spell the refused forms *on purpose* so the refusals can be
|
reports exactly six sites, all in `test_flan.ml`, which spell the refused forms *on purpose* so the refusals can be
|
||||||
tested. Read the diff of every non-`.flan` file — BUILT.md lists what the script can and cannot see.
|
tested. Read the diff of every non-`.flan` file — docs/BUILT.md lists what the script can and cannot see.
|
||||||
|
|
||||||
~~**2. `loop` and `recur`.**~~ **Done.** See *`loop` and `recur`, and why `recur` is better than tail calls and not
|
~~**2. `loop` and `recur`.**~~ **Done.** See *`loop` and `recur`, and why `recur` is better than tail calls and not
|
||||||
only cheaper* in [`BUILT.md`](BUILT.md). `emit.ml` is untouched: a loop is a `let`, a `While` whose condition is
|
only cheaper* in [`docs/BUILT.md`](docs/BUILT.md). `emit.ml` is untouched: a loop is a `let`, a `While` whose condition is
|
||||||
`true`, and two jumps, and the barrier question `recur` asks is the one labelled `break` already answered.
|
`true`, and two jumps, and the barrier question `recur` asks is the one labelled `break` already answered.
|
||||||
|
|
||||||
Three things the plan did not anticipate, each written up there. **Tail position is a permission that is withdrawn**
|
Three things the plan did not anticipate, each written up there. **Tail position is a permission that is withdrawn**
|
||||||
@ -1718,7 +1718,7 @@ run one lane at a time; item 4 is disjoint and runs alongside any of them.
|
|||||||
backtrace line never carried it, and `Dev.locals` compared slot counts and nothing else — four of the five
|
backtrace line never carried it, and `Dev.locals` compared slot counts and nothing else — four of the five
|
||||||
hand-offs were never written, and printing both sides of the comparison could not have found it because there was
|
hand-offs were never written, and printing both sides of the comparison could not have found it because there was
|
||||||
no comparison. The mechanism was sound and stayed: it hashes slot *names* as well as types, so it does see a
|
no comparison. The mechanism was sound and stayed: it hashes slot *names* as well as types, so it does see a
|
||||||
rename. See BUILT.md, "Locals of a stopped frame".
|
rename. See docs/BUILT.md, "Locals of a stopped frame".
|
||||||
|
|
||||||
2. ~~**The colon-to-dot change.**~~ **Done**, and `Map` is unblocked: `{:key value}` is free. The sweep is
|
2. ~~**The colon-to-dot change.**~~ **Done**, and `Map` is unblocked: `{:key value}` is free. The sweep is
|
||||||
`tools/colon-to-dot.py`, kept rather than thrown away, because the lanes that branched before it wrote Flan in the
|
`tools/colon-to-dot.py`, kept rather than thrown away, because the lanes that branched before it wrote Flan in the
|
||||||
@ -1726,7 +1726,7 @@ run one lane at a time; item 4 is disjoint and runs alongside any of them.
|
|||||||
`--in-strings` for a `test/*.ml` that embeds Flan.
|
`--in-strings` for a `test/*.ml` that embeds Flan.
|
||||||
|
|
||||||
3. ~~**`Map`, and the `defer` relaxation.**~~ **Both done.** See *`(Map K V)`, which is Odin's map* and *`defer` may be
|
3. ~~**`Map`, and the `defer` relaxation.**~~ **Both done.** See *`(Map K V)`, which is Odin's map* and *`defer` may be
|
||||||
written in a `let`* in [`BUILT.md`](BUILT.md). The `defer` relaxation **amends `spec-memory.md`**, which said
|
written in a `let`* in [`docs/BUILT.md`](docs/BUILT.md). The `defer` relaxation **amends `spec-memory.md`**, which said
|
||||||
`(defer (free v))` for a `let`-bound `v` was not expressible; it is now. `Map` restricts one thing the spec does not:
|
`(defer (free v))` for a `let`-bound `v` was not expressible; it is now. `Map` restricts one thing the spec does not:
|
||||||
a fixed array is a key only when its elements compare bytewise, so an array of structs or of strings is refused by
|
a fixed array is a key only when its elements compare bytewise, so an array of structs or of strings is refused by
|
||||||
name. The measured answer to "is this another Python dict" is six times quicker cache-resident and *slower* at a
|
name. The measured answer to "is this another Python dict" is six times quicker cache-resident and *slower* at a
|
||||||
@ -1743,7 +1743,7 @@ run one lane at a time; item 4 is disjoint and runs alongside any of them.
|
|||||||
5. ~~**Union values**~~, then the macro expander, then `Result`/`try`. Promoted above `Handle` on the author's call —
|
5. ~~**Union values**~~, then the macro expander, then `Result`/`try`. Promoted above `Handle` on the author's call —
|
||||||
macros are the thing most worth wanting, and unions are the only thing between here and them.
|
macros are the thing most worth wanting, and unions are the only thing between here and them.
|
||||||
|
|
||||||
**Union values are done.** See *Unions, and the tag they carry* in [`BUILT.md`](BUILT.md). The diagnosis was right:
|
**Union values are done.** See *Unions, and the tag they carry* in [`docs/BUILT.md`](docs/BUILT.md). The diagnosis was right:
|
||||||
`Option` is a two-case union wearing a special coat, so `Tast.arm`'s `acase` and `binds` already were union shape
|
`Option` is a two-case union wearing a special coat, so `Tast.arm`'s `acase` and `binds` already were union shape
|
||||||
and `check_match` grew a second subject rather than a second path. A union is `Types.Named` exactly as a struct is,
|
and `check_match` grew a second subject rather than a second path. A union is `Types.Named` exactly as a struct is,
|
||||||
so every path that merely carries a type learned nothing.
|
so every path that merely carries a type learned nothing.
|
||||||
@ -1761,7 +1761,7 @@ run one lane at a time; item 4 is disjoint and runs alongside any of them.
|
|||||||
needs no import and no `load.ml` change. Verified by declaring one there and matching it from a program.
|
needs no import and no `load.ml` change. Verified by declaring one there and matching it from a program.
|
||||||
|
|
||||||
**Macros landed on top of this** and needed no `load.ml` change for `Form`, exactly as this said. See
|
**Macros landed on top of this** and needed no `load.ml` change for `Form`, exactly as this said. See
|
||||||
[`BUILT.md`](BUILT.md), "Macros: the compiler dlopens the program", and the short list of what is left of them
|
[`docs/BUILT.md`](docs/BUILT.md), "Macros: the compiler dlopens the program", and the short list of what is left of them
|
||||||
below.
|
below.
|
||||||
|
|
||||||
Macros are what buy `with-drawing` and `with-mode-2d` over raylib's begin/end pairs, the hiccup DSL if a JS backend
|
Macros are what buy `with-drawing` and `with-mode-2d` over raylib's begin/end pairs, the hiccup DSL if a JS backend
|
||||||
@ -1778,7 +1778,7 @@ run one lane at a time; item 4 is disjoint and runs alongside any of them.
|
|||||||
a C-shaped callback and somewhere to put a `flan_allocator`, neither of which is a type parameter.
|
a C-shaped callback and somewhere to put a `flan_allocator`, neither of which is a type parameter.
|
||||||
|
|
||||||
6. ~~**`Handle` and the pool.**~~ **Built.** A reference to something that can die, that reports that it died rather
|
6. ~~**`Handle` and the pool.**~~ **Built.** A reference to something that can die, that reports that it died rather
|
||||||
than silently resolving to whatever reused the slot. See [`BUILT.md`](BUILT.md), "`(Handle T)` and the pool, which
|
than silently resolving to whatever reused the slot. See [`docs/BUILT.md`](docs/BUILT.md), "`(Handle T)` and the pool, which
|
||||||
is what a stale reference answers with". A handle is one `i64` — slot index low, generation high — so it copies,
|
is what a stale reference answers with". A handle is one `i64` — slot index low, generation high — so it copies,
|
||||||
zeroes and compares like an integer and owns nothing; a live slot's generation is odd, which makes a zeroed handle
|
zeroes and compares like an integer and owns nothing; a live slot's generation is odd, which makes a zeroed handle
|
||||||
resolve to nothing rather than to slot 0; and a generation that would wrap retires its slot instead, because "rare"
|
resolve to nothing rather than to slot 0; and a generation that would wrap retires its slot instead, because "rare"
|
||||||
@ -1800,7 +1800,7 @@ run one lane at a time; item 4 is disjoint and runs alongside any of them.
|
|||||||
is consumed, because there is no borrowing parameter — a pre-existing `Vec` gap, not a pool one.
|
is consumed, because there is no borrowing parameter — a pre-existing `Vec` gap, not a pool one.
|
||||||
|
|
||||||
7. ~~**`break` and `continue`, with loop labels.**~~ **Built.** Labels are Odin's in the head position, both blockers
|
7. ~~**`break` and `continue`, with loop labels.**~~ **Built.** Labels are Odin's in the head position, both blockers
|
||||||
are answered, and the refusals name the construct they refuse for. See BUILT.md, "`break` and `continue`, and the
|
are answered, and the refusals name the construct they refuse for. See docs/BUILT.md, "`break` and `continue`, and the
|
||||||
rule that replaced a blanket refusal". What was settled in conversation before it was built, kept:
|
rule that replaced a blanket refusal". What was settled in conversation before it was built, kept:
|
||||||
|
|
||||||
**Labels, Odin-style but in the head position.** A keyword names a loop and `break` takes it:
|
**Labels, Odin-style but in the head position.** A keyword names a loop and `break` takes it:
|
||||||
@ -1822,7 +1822,7 @@ run one lane at a time; item 4 is disjoint and runs alongside any of them.
|
|||||||
hang.
|
hang.
|
||||||
|
|
||||||
8. ~~**Errors: a structured value with spans and notes, and more than one per compile.**~~ **Built.** See
|
8. ~~**Errors: a structured value with spans and notes, and more than one per compile.**~~ **Built.** See
|
||||||
*An error is a value, and there is more than one of them* in [`BUILT.md`](BUILT.md). `Loc.Error` carries a
|
*An error is a value, and there is more than one of them* in [`docs/BUILT.md`](docs/BUILT.md). `Loc.Error` carries a
|
||||||
`diag` — a stable `kind`, a *span*, `notes` that each have their own span and severity, and the macro expansion
|
`diag` — a stable `kind`, a *span*, `notes` that each have their own span and severity, and the macro expansion
|
||||||
the error came out of — and `flan check`/`flan build` print the source line with the offending span underlined,
|
the error came out of — and `flan check`/`flan build` print the source line with the offending span underlined,
|
||||||
in the GNU format `compilation-mode` already parses. No editor work was needed and none was done.
|
in the GNU format `compilation-mode` already parses. No editor work was needed and none was done.
|
||||||
@ -1880,7 +1880,7 @@ debug tracking allocator, which is the leak safety net and a good candidate when
|
|||||||
|
|
||||||
## Decided in discussion — the array constructor and the module system
|
## Decided in discussion — the array constructor and the module system
|
||||||
|
|
||||||
**`(array 4 rl/Vector2)` makes a fixed array; `[4 T]` stays the type syntax. Built** — see BUILT.md, "`(array 4 rl/Vector2)`, and the one position with no type slot". The problem it solved: a `let`
|
**`(array 4 rl/Vector2)` makes a fixed array; `[4 T]` stays the type syntax. Built** — see docs/BUILT.md, "`(array 4 rl/Vector2)`, and the one position with no type slot". The problem it solved: a `let`
|
||||||
binding takes no type, so `(let [pts [4 rl/Vector2]] ...)` reads `[4 rl/Vector2]` as a two-element array *literal* and
|
binding takes no type, so `(let [pts [4 rl/Vector2]] ...)` reads `[4 rl/Vector2]` as a two-element array *literal* and
|
||||||
fails with *unknown name rl/Vector2*. It cost 32 hand-written `Vector2`s in one raylib example.
|
fails with *unknown name rl/Vector2*. It cost 32 hand-written `Vector2`s in one raylib example.
|
||||||
|
|
||||||
@ -1938,7 +1938,7 @@ package to *mark* a name private, and adding one means a parser change.
|
|||||||
|
|
||||||
## Decided in discussion — three more, two now built
|
## Decided in discussion — three more, two now built
|
||||||
|
|
||||||
~~**A watch window, ported from the author's Clojure one.**~~ **Built.** See `BUILT.md`, "The watch window, and why
|
~~**A watch window, ported from the author's Clojure one.**~~ **Built.** See `docs/BUILT.md`, "The watch window, and why
|
||||||
it is the only listing that is pushed", and `emacs/MANUAL.md` under "Looking at values". Three of the original's
|
it is the only listing that is pushed", and `emacs/MANUAL.md` under "Looking at values". Three of the original's
|
||||||
decisions were kept unchanged — the program decides what is shown, the request is async, and the paint is
|
decisions were kept unchanged — the program decides what is shown, the request is async, and the paint is
|
||||||
`replace-buffer-contents` so point and scroll survive every tick.
|
`replace-buffer-contents` so point and scroll survive every tick.
|
||||||
@ -1954,7 +1954,7 @@ could not have done at any price.
|
|||||||
|
|
||||||
**What was not built, deliberately: the `(watch "hp" hp)` form.** Scalars work today through `declare-c` against four
|
**What was not built, deliberately: the `(watch "hp" hp)` form.** Scalars work today through `declare-c` against four
|
||||||
runtime entry points, which needs no compiler change at all. A struct or a slice needs a compile-time walk over its
|
runtime entry points, which needs no compiler change at all. A struct or a slice needs a compile-time walk over its
|
||||||
type — one arm in `check.ml` beside `print`, which `BUILT.md` writes out in full — and that file is held by another
|
type — one arm in `check.ml` beside `print`, which `docs/BUILT.md` writes out in full — and that file is held by another
|
||||||
lane, so it was left alone rather than reached into.
|
lane, so it was left alone rather than reached into.
|
||||||
|
|
||||||
~~**Ghost text is gated on that same arm**, which is the finding worth keeping.~~ **Wrong, and ghost text is built.**
|
~~**Ghost text is gated on that same arm**, which is the finding worth keeping.~~ **Wrong, and ghost text is built.**
|
||||||
@ -1965,10 +1965,10 @@ conclusion did not follow: the call site is in the *buffer*, and the name in the
|
|||||||
so the anchor is searched for rather than reported. Nothing new is asked of the daemon. The two open questions
|
so the anchor is searched for rather than reported. Nothing new is asked of the daemon. The two open questions
|
||||||
`flan-watch.el` recorded are answered rather than solved — overlays are replaced wholesale every repaint, so an edit
|
`flan-watch.el` recorded are answered rather than solved — overlays are replaced wholesale every repaint, so an edit
|
||||||
has nothing to invalidate, and a watch in a loop shows the last value written exactly as the buffer does, because
|
has nothing to invalidate, and a watch in a loop shows the last value written exactly as the buffer does, because
|
||||||
every better answer is the query UI this design exists to avoid. See `BUILT.md`, "Ghost text finds its anchor in the
|
every better answer is the query UI this design exists to avoid. See `docs/BUILT.md`, "Ghost text finds its anchor in the
|
||||||
buffer, not in the table".
|
buffer, not in the table".
|
||||||
|
|
||||||
~~**The inspector gets a second way to start: an address and a type.**~~ **Built.** See `BUILT.md`, "Two ways to root
|
~~**The inspector gets a second way to start: an address and a type.**~~ **Built.** See `docs/BUILT.md`, "Two ways to root
|
||||||
a walk, and why neither subsumes the other". It went in as a frame and a slot *index* rather than an address and a
|
a walk, and why neither subsumes the other". It went in as a frame and a slot *index* rather than an address and a
|
||||||
type — the daemon holds both and an index is the thing the listing can hand back, while an address is not something an
|
type — the daemon holds both and an index is the thing the listing can hand back, while an address is not something an
|
||||||
editor should be holding. The one prediction that did not survive contact: `l` crossing between the two modes was
|
editor should be holding. The one prediction that did not survive contact: `l` crossing between the two modes was
|
||||||
@ -2042,11 +2042,11 @@ Ranked by how often they were hit, top two first because they are walls rather t
|
|||||||
list head — because `(Key n)` is a *value* now, and putting `Key` in `types` would make a body starting with one
|
list head — because `(Key n)` is a *value* now, and putting `Key` in `types` would make a body starting with one
|
||||||
be eaten as a return type.
|
be eaten as a return type.
|
||||||
3. ~~**`break` is not implemented.**~~ **Built, with `continue` and loop labels.** Both blockers are answered: the
|
3. ~~**`break` is not implemented.**~~ **Built, with `continue` and loop labels.** Both blockers are answered: the
|
||||||
`in_frames` rule became a relative one rather than a blanket one, and `Tast.While` grew a latch. See BUILT.md,
|
`in_frames` rule became a relative one rather than a blanket one, and `Tast.While` grew a latch. See docs/BUILT.md,
|
||||||
"`break` and `continue`, and the rule that replaced a blanket refusal".
|
"`break` and `continue`, and the rule that replaced a blanket refusal".
|
||||||
4. ~~**A `let` binding takes no type annotation**~~ — still true, and **no longer the blocker it was**: `(array 4
|
4. ~~**A `let` binding takes no type annotation**~~ — still true, and **no longer the blocker it was**: `(array 4
|
||||||
rl/Vector2)` is built and is the answer to the case that raised it. The reasoning below is kept because it is what
|
rl/Vector2)` is built and is the answer to the case that raised it. The reasoning below is kept because it is what
|
||||||
chose between the three surfaces, and the first of them is not what was taken — see BUILT.md, "`(array 4
|
chose between the three surfaces, and the first of them is not what was taken — see docs/BUILT.md, "`(array 4
|
||||||
rl/Vector2)`, and the one position with no type slot". The original entry:
|
rl/Vector2)`, and the one position with no type slot". The original entry:
|
||||||
|
|
||||||
A fixed array is either a top-level `defvar` or a literal with
|
A fixed array is either a top-level `defvar` or a literal with
|
||||||
@ -2089,11 +2089,11 @@ array with a struct element, a 2-D struct array, and `[N string]` as both `defco
|
|||||||
|
|
||||||
### The web target: what it does not reach yet
|
### The web target: what it does not reach yet
|
||||||
|
|
||||||
`flan build --target=web` works, a raylib example builds unchanged and `test/test_web.ml` is green — see BUILT.md,
|
`flan build --target=web` works, a raylib example builds unchanged and `test/test_web.ml` is green — see docs/BUILT.md,
|
||||||
"The browser is the third target", for the mechanism and why asyncify rather than `emscripten_set_main_loop`. Four
|
"The browser is the third target", for the mechanism and why asyncify rather than `emscripten_set_main_loop`. Four
|
||||||
things it does not cover.
|
things it does not cover.
|
||||||
|
|
||||||
~~**1. `sand.flan` has no web build, and the cause is one missing `#include`.**~~ **Built. It opens.** See BUILT.md,
|
~~**1. `sand.flan` has no web build, and the cause is one missing `#include`.**~~ **Built. It opens.** See docs/BUILT.md,
|
||||||
"sand.flan in a browser", for the whole of it. Three summary lines, because the diagnosis below was right about the
|
"sand.flan in a browser", for the whole of it. Three summary lines, because the diagnosis below was right about the
|
||||||
structure and wrong about the cause:
|
structure and wrong about the cause:
|
||||||
|
|
||||||
@ -2147,7 +2147,7 @@ The original text follows. `sand.flan` does `(rl/load-texture "brush.png")` agai
|
|||||||
**3. Nothing has been opened in a browser.** *Still true, and now it is the only thing left between here and
|
**3. Nothing has been opened in a browser.** *Still true, and now it is the only thing left between here and
|
||||||
"someone played with it".* `sand.flan` builds for the web, the module carries asyncify, raylib's GL imports and
|
"someone played with it".* `sand.flan` builds for the web, the module carries asyncify, raylib's GL imports and
|
||||||
brush.png's own bytes whole, and `node sand.js` gets as far as `glfwInit` before dying on `window is not defined` —
|
brush.png's own bytes whole, and `node sand.js` gets as far as `glfwInit` before dying on `window is not defined` —
|
||||||
which proves the module is live and proves nothing about the canvas. BUILT.md carries the exact commands to serve and
|
which proves the module is live and proves nothing about the canvas. docs/BUILT.md carries the exact commands to serve and
|
||||||
open it, and the list of what only a human will discover: whether it paints, whether the audio round trip through
|
open it, and the list of what only a human will discover: whether it paints, whether the audio round trip through
|
||||||
MEMFS survives, and the canvas size. The `until` loop never exits on the web, so none of `main`'s `defer`s run —
|
MEMFS survives, and the canvas size. The `until` loop never exits on the web, so none of `main`'s `defer`s run —
|
||||||
expected, and worth knowing before reading anything into it.
|
expected, and worth knowing before reading anything into it.
|
||||||
@ -2167,7 +2167,7 @@ message.
|
|||||||
### `break`, and why it was not built — **it is built now**
|
### `break`, and why it was not built — **it is built now**
|
||||||
|
|
||||||
Kept as written, because everything in it held and the two blockers at the end are the two things the build had to
|
Kept as written, because everything in it held and the two blockers at the end are the two things the build had to
|
||||||
rule on. Both are ruled on in BUILT.md, "`break` and `continue`, and the rule that replaced a blanket refusal":
|
rule on. Both are ruled on in docs/BUILT.md, "`break` and `continue`, and the rule that replaced a blanket refusal":
|
||||||
the `in_frames` precedent was replaced by a barrier on the loop stack, which refuses a *crossing* rather than
|
the `in_frames` precedent was replaced by a barrier on the loop stack, which refuses a *crossing* rather than
|
||||||
everything, and `Tast.While` grew the latch. The original note:
|
everything, and `Tast.While` grew the latch. The original note:
|
||||||
|
|
||||||
@ -2197,7 +2197,7 @@ plan.org's single line on it (831) names a `for` the language does not have and
|
|||||||
|
|
||||||
1. ~~**Allocators, then `Vec` and `Map`.**~~ **Steps 1, 2 and 3 are done** — the allocator, the arena, `(Vec T)`,
|
1. ~~**Allocators, then `Vec` and `Map`.**~~ **Steps 1, 2 and 3 are done** — the allocator, the arena, `(Vec T)`,
|
||||||
`StorageExhausted` and `retry`. `Map` is step 4 and is what is left of this item. See *Allocators, `(Vec T)` and
|
`StorageExhausted` and `retry`. `Map` is step 4 and is what is left of this item. See *Allocators, `(Vec T)` and
|
||||||
`StorageExhausted`* in [`BUILT.md`](BUILT.md) for the shape, the three amendments to a frozen `spec-memory.md` and
|
`StorageExhausted`* in [`docs/BUILT.md`](docs/BUILT.md) for the shape, the three amendments to a frozen `spec-memory.md` and
|
||||||
the one addition. The claim below held: **`Vec` does not need generics** — that was wrong and is worth un-learning: Odin's containers are compiler
|
the one addition. The claim below held: **`Vec` does not need generics** — that was wrong and is worth un-learning: Odin's containers are compiler
|
||||||
builtins over a *type-erased* runtime (`base/runtime/dynamic_array_internal.odin`), where `$T` appears only in thin
|
builtins over a *type-erased* runtime (`base/runtime/dynamic_array_internal.odin`), where `$T` appears only in thin
|
||||||
wrappers producing `size_of`/`align_of` at the call site, and per-key hash and equality are compiler-emitted
|
wrappers producing `size_of`/`align_of` at the call site, and per-key hash and equality are compiler-emitted
|
||||||
@ -2237,7 +2237,7 @@ plan.org's single line on it (831) names a `for` the language does not have and
|
|||||||
|
|
||||||
**Steps 1, 2 and 3 are built; 4 to 8 are what is left.** The reasoning is kept because it is what the remaining steps
|
**Steps 1, 2 and 3 are built; 4 to 8 are what is left.** The reasoning is kept because it is what the remaining steps
|
||||||
rest on, and because the escape it describes was tested rather than assumed — see *Allocators, `(Vec T)` and
|
rest on, and because the escape it describes was tested rather than assumed — see *Allocators, `(Vec T)` and
|
||||||
`StorageExhausted`* in [`BUILT.md`](BUILT.md).
|
`StorageExhausted`* in [`docs/BUILT.md`](docs/BUILT.md).
|
||||||
|
|
||||||
The dependency nobody had written down, and the reason it looked worse than it is. `spec-memory.md` defines an
|
The dependency nobody had written down, and the reason it looked worse than it is. `spec-memory.md` defines an
|
||||||
allocator as "a procedure plus an opaque data pointer" — a function value. `check.ml` refuses function values four
|
allocator as "a procedure plus an opaque data pointer" — a function value. `check.ml` refuses function values four
|
||||||
@ -2280,7 +2280,7 @@ expander last, on 6's unions.
|
|||||||
~~1. **`Allocator` and the arena.**~~ **Done.** The builtin opaque type, the four operations with `size` and `align`,
|
~~1. **`Allocator` and the arena.**~~ **Done.** The builtin opaque type, the four operations with `size` and `align`,
|
||||||
the capability set read off the allocator value, `with-allocator`, `context/allocator`, `context/temp` and the epoch
|
the capability set read off the allocator value, `with-allocator`, `context/allocator`, `context/temp` and the epoch
|
||||||
counter. `free-all` was decided as retain-capacity with `arena-destroy` beside it; the context is a dynamic variable
|
counter. `free-all` was decided as retain-capacity with `arena-destroy` beside it; the context is a dynamic variable
|
||||||
rather than a literal calling-convention parameter; both are stated as amendments in `BUILT.md`. A user-written
|
rather than a literal calling-convention parameter; both are stated as amendments in `docs/BUILT.md`. A user-written
|
||||||
allocator is refused by name with milestone 5 as the reason.
|
allocator is refused by name with milestone 5 as the reason.
|
||||||
|
|
||||||
~~2. **`(Vec T)`**~~ **Done**, over the type-erased runtime, with `push`, `reserve`, `at`, `len`, `as-slice`, `free` and
|
~~2. **`(Vec T)`**~~ **Done**, over the type-erased runtime, with `push`, `reserve`, `at`, `len`, `as-slice`, `free` and
|
||||||
@ -2340,7 +2340,7 @@ expander last, on 6's unions.
|
|||||||
not the next thing to build.
|
not the next thing to build.
|
||||||
- ~~**The operation table may be one operation short.**~~ **Decided.** `free-all` is retain-capacity and
|
- ~~**The operation table may be one operation short.**~~ **Decided.** `free-all` is retain-capacity and
|
||||||
`arena-destroy` hands the pages back — two names rather than the mode parameter, so the table the spec froze at four
|
`arena-destroy` hands the pages back — two names rather than the mode parameter, so the table the spec froze at four
|
||||||
operations did not grow. `BUILT.md` states it as the amendment it is.
|
operations did not grow. `docs/BUILT.md` states it as the amendment it is.
|
||||||
- **The `Vec` header is six words in release too, and should not stay that way.** The 32-byte layout the spec fixes is
|
- **The `Vec` header is six words in release too, and should not stay that way.** The 32-byte layout the spec fixes is
|
||||||
blocked on one thing: a redefinition module is built by `llc` and `ld` against a host built separately, and nothing
|
blocked on one thing: a redefinition module is built by `llc` and `ld` against a host built separately, and nothing
|
||||||
makes the two agree on a struct size. Give the reload path a way to carry the build flags and this falls out.
|
makes the two agree on a struct size. Give the reload path a way to carry the build flags and this falls out.
|
||||||
@ -2372,7 +2372,7 @@ expander last, on 6's unions.
|
|||||||
- ~~`web/examples/breakdemo.out` is stale and `check.sh` fails on it.~~ **Fixed.** Commit `4a6a8fa` made the break
|
- ~~`web/examples/breakdemo.out` is stale and `check.sh` fails on it.~~ **Fixed.** Commit `4a6a8fa` made the break
|
||||||
banner number its restarts and the `.out` was never repinned. Nothing had to drive the socket in the end:
|
banner number its restarts and the `.out` was never repinned. Nothing had to drive the socket in the end:
|
||||||
`check.sh` already builds this one `--dev` and runs it under `timeout 5`, keeping what it printed before it
|
`check.sh` already builds this one `--dev` and runs it under `timeout 5`, keeping what it printed before it
|
||||||
stopped, so the repin was the `.out` plus the two prose copies of the banner — `web/index.html` and `BUILT.md` —
|
stopped, so the repin was the `.out` plus the two prose copies of the banner — `web/index.html` and `docs/BUILT.md` —
|
||||||
and a sentence on the page saying what the numbers are for, since a restart is taken by position.
|
and a sentence on the page saying what the numbers are for, since a restart is taken by position.
|
||||||
|
|
||||||
- ~~A shadowed restart is offered and cannot be taken.~~ **Fixed.** A restart is taken by *position* now:
|
- ~~A shadowed restart is offered and cannot be taken.~~ **Fixed.** A restart is taken by *position* now:
|
||||||
@ -2483,7 +2483,7 @@ memcheck sweep (`@valgrind`), whose alarm is looser at 5400s because memcheck is
|
|||||||
now exists** — `Session.render_locals` is exactly that thunk, rooted at an address the program supplies — so what is
|
now exists** — `Session.render_locals` is exactly that thunk, rooted at an address the program supplies — so what is
|
||||||
left is the first: keep the pointer, and give the agent a verb that hands it back. The type is already known: it is
|
left is the first: keep the pointer, and give the agent a verb that hands it back. The type is already known: it is
|
||||||
the `condition_name` the break loop reports, which `layout` already resolves.
|
the `condition_name` the break loop reports, which `layout` already resolves.
|
||||||
- **The type identity is settled, and it is the qualified name** — `layout` is in, see BUILT.md. `Load` qualifies
|
- **The type identity is settled, and it is the qualified name** — `layout` is in, see docs/BUILT.md. `Load` qualifies
|
||||||
every declaration at import, so the names in `Tast.structs` are a flat namespace where two packages' `Missing` are
|
every declaration at import, so the names in `Tast.structs` are a flat namespace where two packages' `Missing` are
|
||||||
`a/Missing` and `b/Missing`; a bare name is refused with the candidates rather than resolved. `condition` inherits
|
`a/Missing` and `b/Missing`; a bare name is refused with the candidates rather than resolved. `condition` inherits
|
||||||
it for free: the string the break loop already reports *is* that name, because `Emit.struct_name_of` writes
|
it for free: the string the break loop already reports *is* that name, because `Emit.struct_name_of` writes
|
||||||
@ -2491,7 +2491,7 @@ memcheck sweep (`@valgrind`), whose alarm is looser at 5400s because memcheck is
|
|||||||
reads is not qualified by anything.
|
reads is not qualified by anything.
|
||||||
- ~~**`(:op "backtrace")` is blocked** on frame metadata.~~ **Built**, and not out of DWARF: decision 3's shadow
|
- ~~**`(:op "backtrace")` is blocked** on frame metadata.~~ **Built**, and not out of DWARF: decision 3's shadow
|
||||||
stack carries the name and the location on the frame itself, so a backtrace needs no debug information at all. See
|
stack carries the name and the location on the frame itself, so a backtrace needs no debug information at all. See
|
||||||
BUILT.md, "The shadow stack, and `backtrace`", for what it costs. **Locals landed with it** — the pointer-rooted
|
docs/BUILT.md, "The shadow stack, and `backtrace`", for what it costs. **Locals landed with it** — the pointer-rooted
|
||||||
render thunk turned out to be `Render.render` over a `Deref` of a slot's address, and one new arm in the backend.
|
render thunk turned out to be `Render.render` over a `Deref` of a slot's address, and one new arm in the backend.
|
||||||
See "Locals of a stopped frame" for the four things it refuses. Restart source locations and arity are still blocked — `flan_restart` carries `prev`, `name_id`, `name` and `namelen`, so both need a new
|
See "Locals of a stopped frame" for the four things it refuses. Restart source locations and arity are still blocked — `flan_restart` carries `prev`, `name_id`, `name` and `namelen`, so both need a new
|
||||||
field in the frame, which means the compiler emitting it.
|
field in the frame, which means the compiler emitting it.
|
||||||
@ -2614,7 +2614,7 @@ left of the item is visibility, which is listed above and needs a marker the par
|
|||||||
## Macros — landed; what is left of them
|
## Macros — landed; what is left of them
|
||||||
|
|
||||||
**The expander works and `unless` is a prelude `defmacro`.** How all of it fits together is in
|
**The expander works and `unless` is a prelude `defmacro`.** How all of it fits together is in
|
||||||
[`BUILT.md`](BUILT.md), "Macros: the compiler dlopens the program" — the image format, the thunk ABI, why quasiquote
|
[`docs/BUILT.md`](docs/BUILT.md), "Macros: the compiler dlopens the program" — the image format, the thunk ABI, why quasiquote
|
||||||
runs before the walk, the two different ways expansion fails to terminate, `-linkall`, and the three cost numbers.
|
runs before the walk, the two different ways expansion fails to terminate, `-linkall`, and the three cost numbers.
|
||||||
What follows is only the part that is still missing.
|
What follows is only the part that is still missing.
|
||||||
|
|
||||||
@ -2684,7 +2684,7 @@ tests assert on the reason, not just on the failure.
|
|||||||
## Handoff: the shadow stack lane, stopped mid-repair
|
## Handoff: the shadow stack lane, stopped mid-repair
|
||||||
|
|
||||||
Two commits landed and are green: the shadow stack with `(:op "backtrace")`, and `(:op "locals" :frame N)`. See
|
Two commits landed and are green: the shadow stack with `(:op "backtrace")`, and `(:op "locals" :frame N)`. See
|
||||||
BUILT.md's two new sections for the design and the measurements. A third commit was **half-built and its own test
|
docs/BUILT.md's two new sections for the design and the measurements. A third commit was **half-built and its own test
|
||||||
left red** on purpose; **it is finished now** — see the struck item 1 above — and the rest of this section is kept
|
left red** on purpose; **it is finished now** — see the struck item 1 above — and the rest of this section is kept
|
||||||
because the parts of it that were true are still worth having.
|
because the parts of it that were true are still worth having.
|
||||||
|
|
||||||
@ -2698,7 +2698,7 @@ wrote.
|
|||||||
|
|
||||||
**Not obvious from the diff.** Two things cost a day between them. The linked-list frame beat an array-with-a-stack-
|
**Not obvious from the diff.** Two things cost a day between them. The linked-list frame beat an array-with-a-stack-
|
||||||
pointer on both benchmarks, which is the opposite of what the escaping-alloca argument predicts, and the measurement
|
pointer on both benchmarks, which is the opposite of what the escaping-alloca argument predicts, and the measurement
|
||||||
that first said otherwise was comparing a 40-frame binary with a 600-frame one; every number in BUILT.md is now a
|
that first said otherwise was comparing a 40-frame binary with a 600-frame one; every number in docs/BUILT.md is now a
|
||||||
minimum of nine runs for that reason. And `redefinition`'s transient rule (`m.nstr = 0`) silently stops every module
|
minimum of nine runs for that reason. And `redefinition`'s transient rule (`m.nstr = 0`) silently stops every module
|
||||||
carrying a string literal from ever being unloaded — the frame descriptors go through their own counter, `m.nfi`, for
|
carrying a string literal from ever being unloaded — the frame descriptors go through their own counter, `m.nfi`, for
|
||||||
that reason, and a locals thunk passes `~retains:false` because everything it emits is memcpy'd into the result buffer.
|
that reason, and a locals thunk passes `~retains:false` because everything it emits is memcpy'd into the result buffer.
|
||||||
|
|||||||
@ -109,7 +109,7 @@ let sanitize_flag = "--sanitize"
|
|||||||
let two_process_flag = "--two-process"
|
let two_process_flag = "--two-process"
|
||||||
|
|
||||||
(* The hand-written x86-64 backend (lib/x86.ml) instead of LLVM. The dev
|
(* The hand-written x86-64 backend (lib/x86.ml) instead of LLVM. The dev
|
||||||
backend from DISCUSS.md item 15, off by default and named explicitly:
|
backend from docs/DISCUSS.md item 15, off by default and named explicitly:
|
||||||
LLVM stays the release path and the default one. It covers a subset of the
|
LLVM stays the release path and the default one. It covers a subset of the
|
||||||
IR and refuses the rest by name, so a build that succeeds is one it really
|
IR and refuses the rest by name, so a build that succeeds is one it really
|
||||||
compiled. *)
|
compiled. *)
|
||||||
|
|||||||
@ -860,7 +860,7 @@ load a file out of `resources/` and neither file is in this tree.
|
|||||||
- `DotGothic16-Regular.ttf` is SIL OFL 1.1 and therefore redistributable, but it is 2 MB,
|
- `DotGothic16-Regular.ttf` is SIL OFL 1.1 and therefore redistributable, but it is 2 MB,
|
||||||
and whether a compiler repository whose only binary asset is a 1 KB PNG should grow a 2 MB
|
and whether a compiler repository whose only binary asset is a 1 KB PNG should grow a 2 MB
|
||||||
font is a call about the repository rather than about this port. Left to the author;
|
font is a call about the repository rather than about this port. Left to the author;
|
||||||
`HANDOFF-raylib-ports.md` carries it as the open question. The example looks for it under
|
`handoffs/HANDOFF-raylib-ports.md` carries it as the open question. The example looks for it under
|
||||||
`examples/resources/`, says on screen when it is not there, and runs either way — raylib
|
`examples/resources/`, says on screen when it is not there, and runs either way — raylib
|
||||||
answers a missing path with the default font, whose glyphs are ASCII, so the kana draw as
|
answers a missing path with the default font, whose glyphs are ASCII, so the kana draw as
|
||||||
boxes and the program explains itself rather than looking broken.
|
boxes and the program explains itself rather than looking broken.
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
Two examples, `text_codepoints_loading` and `textures_image_processing`, ported into
|
Two examples, `text_codepoints_loading` and `textures_image_processing`, ported into
|
||||||
`examples/`. This file is the running record: what is done, what was decided without being
|
`examples/`. This file is the running record: what is done, what was decided without being
|
||||||
able to ask, and what is still open. `PORTING.md` has the findings that outlive the port —
|
able to ask, and what is still open. `../PORTING.md` has the findings that outlive the port —
|
||||||
its last section, "Porting the raylib examples — the last two" — and this file has the
|
its last section, "Porting the raylib examples — the last two" — and this file has the
|
||||||
state of the work.
|
state of the work.
|
||||||
|
|
||||||
@ -12,7 +12,7 @@ state of the work.
|
|||||||
- [x] `examples/textures-image-processing.flan` — builds
|
- [x] `examples/textures-image-processing.flan` — builds
|
||||||
- [x] `test/programs/raylib-codepoints.flan` and `test/programs/raylib-image-processing.flan`,
|
- [x] `test/programs/raylib-codepoints.flan` and `test/programs/raylib-image-processing.flan`,
|
||||||
both in the acceptance table, both gated on libraylib, both run plain and at `-O0`
|
both in the acceptance table, both gated on libraylib, both run plain and at `-O0`
|
||||||
- [x] `PORTING.md` section for this round
|
- [x] `../PORTING.md` section for this round
|
||||||
- [x] `dune test --root .` green
|
- [x] `dune test --root .` green
|
||||||
|
|
||||||
Four commits, each one a working state:
|
Four commits, each one a working state:
|
||||||
@ -39,7 +39,7 @@ Four commits, each one a working state:
|
|||||||
reported", *"a `(Ptr T)` where the header says `T *` and the hand-written line chose
|
reported", *"a `(Ptr T)` where the header says `T *` and the hand-written line chose
|
||||||
something more specific"*. The function implements the enum-against-i32 arm and nothing
|
something more specific"*. The function implements the enum-against-i32 arm and nothing
|
||||||
else. That missing arm is the only thing standing between this round's two refused
|
else. That missing arm is the only thing standing between this round's two refused
|
||||||
bindings and ordinary binding work — see `PORTING.md` §A.1 and §A.2, which have the
|
bindings and ordinary binding work — see `../PORTING.md` §A.1 and §A.2, which have the
|
||||||
exact declarations and the exact error. **Not built: it is a compiler change and the
|
exact declarations and the exact error. **Not built: it is a compiler change and the
|
||||||
freeze is on.** It is small and it is well specified, and it is the thing to do first if
|
freeze is on.** It is small and it is well specified, and it is the thing to do first if
|
||||||
these two ports are ever revisited.
|
these two ports are ever revisited.
|
||||||
|
|||||||
@ -6,9 +6,9 @@ newcomer at that. This is the plan and, below it, what actually happened.
|
|||||||
|
|
||||||
## The plan
|
## The plan
|
||||||
|
|
||||||
1. `git mv` the nine `HANDOFF-*.md` into `docs/handoffs/`, and `DISCUSS.md`,
|
1. `git mv` the nine `HANDOFF-*.md` into `docs/handoffs/`, and `../DISCUSS.md`,
|
||||||
`BUILT.md`, `PORTING.md`, `SPIKE-GENERICS.md`, `REFERENCES.md` and
|
`../BUILT.md`, `../PORTING.md`, `../SPIKE-GENERICS.md`, `../REFERENCES.md` and
|
||||||
`overview.md` into `docs/`. These are written once and read occasionally.
|
`../overview.md` into `docs/`. These are written once and read occasionally.
|
||||||
2. Leave `plan.org`, `spec-memory.md`, `spec-conditions.md`, `NEXT.md`, the
|
2. Leave `plan.org`, `spec-memory.md`, `spec-conditions.md`, `NEXT.md`, the
|
||||||
`.flan` scratch programs and the build files where they are: they are cited
|
`.flan` scratch programs and the build files where they are: they are cited
|
||||||
by bare filename from source comments in dozens of places, and moving them
|
by bare filename from source comments in dozens of places, and moving them
|
||||||
|
|||||||
@ -61,7 +61,7 @@ So a reference to a symbol the object does not define goes through the GOT. Meas
|
|||||||
`call_flan`'s `` `Cell `` target loaded **one** level: `mov r11, cell@GOTPCREL(%rip)` then `call *%r11`. That
|
`call_flan`'s `` `Cell `` target loaded **one** level: `mov r11, cell@GOTPCREL(%rip)` then `call *%r11`. That
|
||||||
reads as "call through the cell" in a disassembly and in fact *calls the cell*. The GOT slot holds the cell's
|
reads as "call through the cell" in a disassembly and in fact *calls the cell*. The GOT slot holds the cell's
|
||||||
**address**; reading what the cell holds is two loads, not one. Found by the segfault, not by reading — which is
|
**address**; reading what the cell holds is two loads, not one. Found by the segfault, not by reading — which is
|
||||||
DISCUSS.md item 15's claim, now with a sixth instance. `load_sym` is the fix and is the only helper that
|
../DISCUSS.md item 15's claim, now with a sixth instance. `load_sym` is the fix and is the only helper that
|
||||||
double-loads; `Lgot` gets it right for free because `lmem` already had the shape.
|
double-loads; `Lgot` gets it right for free because `lmem` already had the shape.
|
||||||
|
|
||||||
## Scope, deliberately narrower than `Emit.redefinition`
|
## Scope, deliberately narrower than `Emit.redefinition`
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
# Handoff — the x86 backend's last two correctness items
|
# Handoff — the x86 backend's last two correctness items
|
||||||
|
|
||||||
Branch: `dev-loop`, worktree `agent-af9064091c0602dc8`. Three commits plus this one; nothing is half-written and
|
Branch: `dev-loop`, worktree `agent-af9064091c0602dc8`. Three commits plus this one; nothing is half-written and
|
||||||
nothing is reverted. The long-form report is **DISCUSS.md item 18**; this file is the operational version.
|
nothing is reverted. The long-form report is **../DISCUSS.md item 18**; this file is the operational version.
|
||||||
|
|
||||||
## 1. The `flan_vec_as_slice` answer — got it, and it is complete
|
## 1. The `flan_vec_as_slice` answer — got it, and it is complete
|
||||||
|
|
||||||
|
|||||||
@ -3,11 +3,11 @@
|
|||||||
This was the first brainstorm. It is kept for history and is **no longer
|
This was the first brainstorm. It is kept for history and is **no longer
|
||||||
accurate**. Read instead:
|
accurate**. Read instead:
|
||||||
|
|
||||||
- `plan.org` — the design, the build sequence, and the open decisions
|
- `../plan.org` — the design, the build sequence, and the open decisions
|
||||||
- `spec-memory.md` — ownership, containers, places, generics, function values
|
- `../spec-memory.md` — ownership, containers, places, generics, function values
|
||||||
- `spec-conditions.md` — conditions and restarts, operational semantics
|
- `../spec-conditions.md` — conditions and restarts, operational semantics
|
||||||
- `sand.flan` — the first acceptance program
|
- `../sand.flan` — the first acceptance program
|
||||||
- `syntax-sketch.flan` — the syntax, annotated with the decisions above
|
- `../syntax-sketch.flan` — the syntax, annotated with the decisions above
|
||||||
|
|
||||||
## What changed since
|
## What changed since
|
||||||
|
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
# Flan in Emacs
|
# Flan in Emacs
|
||||||
|
|
||||||
A manual for the editor side. It assumes you know Emacs and nothing about how
|
A manual for the editor side. It assumes you know Emacs and nothing about how
|
||||||
Flan's dev loop is built — if you want that, `BUILT.md` has it.
|
Flan's dev loop is built — if you want that, `docs/BUILT.md` has it.
|
||||||
|
|
||||||
The short version: you start a program, you keep it running, and you change it
|
The short version: you start a program, you keep it running, and you change it
|
||||||
while it runs. Everything below is a variation on that.
|
while it runs. Everything below is a variation on that.
|
||||||
|
|||||||
@ -1409,7 +1409,7 @@ START and END, when given, are the region it came from, flashed on success.
|
|||||||
PAUSE, when given, is (BEG . END): the bounds of the form inside CODE the
|
PAUSE, when given, is (BEG . END): the bounds of the form inside CODE the
|
||||||
program should stop at. Only BEG goes on the wire — the daemon matches it
|
program should stop at. Only BEG goes on the wire — the daemon matches it
|
||||||
against the location the reader attached to that form — and END is what the
|
against the location the reader attached to that form — and END is what the
|
||||||
mark is drawn over here. Nothing is inserted in the buffer; see DISCUSS.md
|
mark is drawn over here. Nothing is inserted in the buffer; see docs/DISCUSS.md
|
||||||
§9."
|
§9."
|
||||||
(let ((reply
|
(let ((reply
|
||||||
(flan-dev--request
|
(flan-dev--request
|
||||||
|
|||||||
@ -55,7 +55,7 @@
|
|||||||
;;
|
;;
|
||||||
;; Scalars only, so far. A struct or a slice needs a compile-time walk over
|
;; Scalars only, so far. A struct or a slice needs a compile-time walk over
|
||||||
;; its type — a `(watch "hp" hp)' form in the checker — and that is a file this
|
;; its type — a `(watch "hp" hp)' form in the checker — and that is a file this
|
||||||
;; change does not own. See BUILT.md.
|
;; change does not own. See docs/BUILT.md.
|
||||||
|
|
||||||
;;; Code:
|
;;; Code:
|
||||||
|
|
||||||
@ -533,7 +533,7 @@ Tears down both consumers. `flan-watch--drop' is the way to stop one of them."
|
|||||||
;; Still genuinely blocked on the checker, and unchanged by any of this: a
|
;; Still genuinely blocked on the checker, and unchanged by any of this: a
|
||||||
;; **struct or a slice**. Rendering one is a compile-time walk over its type,
|
;; **struct or a slice**. Rendering one is a compile-time walk over its type,
|
||||||
;; the runtime has scalar entry points only, and no amount of searching the
|
;; the runtime has scalar entry points only, and no amount of searching the
|
||||||
;; buffer produces a value the table does not hold. See BUILT.md.
|
;; buffer produces a value the table does not hold. See docs/BUILT.md.
|
||||||
|
|
||||||
(provide 'flan-watch)
|
(provide 'flan-watch)
|
||||||
;;; flan-watch.el ends here
|
;;; flan-watch.el ends here
|
||||||
|
|||||||
@ -811,7 +811,7 @@ is written instead — the real `message' call the real command makes."
|
|||||||
|
|
||||||
;; ── Marking a form with (pause) ───────────────────────────────────────
|
;; ── Marking a form with (pause) ───────────────────────────────────────
|
||||||
;;
|
;;
|
||||||
;; DISCUSS.md §9: `C-u' before an evaluation marks a form so the program
|
;; docs/DISCUSS.md §9: `C-u' before an evaluation marks a form so the program
|
||||||
;; stops when it runs, and the buffer is never edited — the position goes on
|
;; stops when it runs, and the buffer is never edited — the position goes on
|
||||||
;; the wire beside the code and the daemon splices the call in after parsing.
|
;; the wire beside the code and the daemon splices the call in after parsing.
|
||||||
;;
|
;;
|
||||||
|
|||||||
@ -9,13 +9,13 @@
|
|||||||
;;;; is the same struct going into the call that actually draws with it.
|
;;;; is the same struct going into the call that actually draws with it.
|
||||||
;;;;
|
;;;;
|
||||||
;;;; The hundred buildings are a `defvar` of fixed arrays rather than a Vec:
|
;;;; The hundred buildings are a `defvar` of fixed arrays rather than a Vec:
|
||||||
;;;; a global cannot hold a Vec (PORTING.md §3) and does not need to here,
|
;;;; a global cannot hold a Vec (docs/PORTING.md §3) and does not need to here,
|
||||||
;;;; because the count is a constant in the C too. `(array n T)` is the zeroed
|
;;;; because the count is a constant in the C too. `(array n T)` is the zeroed
|
||||||
;;;; fixed array, and the C's `= { 0 }` is exactly that.
|
;;;; fixed array, and the C's `= { 0 }` is exactly that.
|
||||||
;;;;
|
;;;;
|
||||||
;;;; get-random-value comes from the generated half of the bindings. It is on
|
;;;; get-random-value comes from the generated half of the bindings. It is on
|
||||||
;;;; no frame's path — it runs once, before the loop — and its Flan face is
|
;;;; no frame's path — it runs once, before the loop — and its Flan face is
|
||||||
;;;; the C one, so PORTING.md §1's rule does not reach it.
|
;;;; the C one, so docs/PORTING.md §1's rule does not reach it.
|
||||||
;;;;
|
;;;;
|
||||||
;;;; One deliberate difference from the C: `(- camera.rotation 1.0)` and the
|
;;;; One deliberate difference from the C: `(- camera.rotation 1.0)` and the
|
||||||
;;;; clamp after it are written with the prelude's `clamp` macro rather than
|
;;;; clamp after it are written with the prelude's `clamp` macro rather than
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
;;;;
|
;;;;
|
||||||
;;;; examples/core/core_scissor_test.c. Needed begin-scissor-mode and
|
;;;; examples/core/core_scissor_test.c. Needed begin-scissor-mode and
|
||||||
;;;; end-scissor-mode, now hand-written in vendor/raylib/raylib.flan: they are
|
;;;; end-scissor-mode, now hand-written in vendor/raylib/raylib.flan: they are
|
||||||
;;;; a begin/end pair inside a frame, which is the class PORTING.md §1 says
|
;;;; a begin/end pair inside a frame, which is the class docs/PORTING.md §1 says
|
||||||
;;;; belongs in the hand-written half and not in the importer's. get-mouse-x
|
;;;; belongs in the hand-written half and not in the importer's. get-mouse-x
|
||||||
;;;; and get-mouse-y come from the generated half — their Flan face is the C
|
;;;; and get-mouse-y come from the generated half — their Flan face is the C
|
||||||
;;;; one, two plain i32s, and there is nothing for a hand-written line to say
|
;;;; one, two plain i32s, and there is nothing for a hand-written line to say
|
||||||
|
|||||||
@ -15,7 +15,7 @@
|
|||||||
;;;; window-state?, set-window-state, clear-window-state, toggle-fullscreen,
|
;;;; window-state?, set-window-state, clear-window-state, toggle-fullscreen,
|
||||||
;;;; minimize-window, maximize-window and restore-window all come from the
|
;;;; minimize-window, maximize-window and restore-window all come from the
|
||||||
;;;; generated half. That is the line drawn in vendor/raylib/bindings and it
|
;;;; generated half. That is the line drawn in vendor/raylib/bindings and it
|
||||||
;;;; is worth saying why it falls here: the rule in PORTING.md §1 exists so
|
;;;; is worth saying why it falls here: the rule in docs/PORTING.md §1 exists so
|
||||||
;;;; that a build with no header set can still draw, and generated.flan is
|
;;;; that a build with no header set can still draw, and generated.flan is
|
||||||
;;;; committed, so it can. What a hand-written line adds on top of that is a
|
;;;; committed, so it can. What a hand-written line adds on top of that is a
|
||||||
;;;; Flan face the C signature does not have — a Key instead of an int, a
|
;;;; Flan face the C signature does not have — a Key instead of an int, a
|
||||||
|
|||||||
@ -11,7 +11,7 @@
|
|||||||
;;;; Hand-written in raylib.flan rather than generated, and why each:
|
;;;; Hand-written in raylib.flan rather than generated, and why each:
|
||||||
;;;;
|
;;;;
|
||||||
;;;; begin-mode-3d / end-mode-3d a begin/end pair inside a frame, the
|
;;;; begin-mode-3d / end-mode-3d a begin/end pair inside a frame, the
|
||||||
;;;; class PORTING.md §1 names, and taken
|
;;;; class docs/PORTING.md §1 names, and taken
|
||||||
;;;; together the way begin-mode-2d is
|
;;;; together the way begin-mode-2d is
|
||||||
;;;; draw-cube / draw-cube-wires / draw-grid drawn every frame
|
;;;; draw-cube / draw-cube-wires / draw-grid drawn every frame
|
||||||
;;;; update-camera the Flan face differs: (Ptr Camera3D),
|
;;;; update-camera the Flan face differs: (Ptr Camera3D),
|
||||||
|
|||||||
@ -29,7 +29,7 @@
|
|||||||
;;;; zeroed global standing in for the null pointer that means "the default
|
;;;; zeroed global standing in for the null pointer that means "the default
|
||||||
;;;; ASCII set" — written for exactly this call, before anything called it.
|
;;;; ASCII set" — written for exactly this call, before anything called it.
|
||||||
;;;;
|
;;;;
|
||||||
;;;; **Two things Flan would not do, both written up in PORTING.md.**
|
;;;; **Two things Flan would not do, both written up in docs/PORTING.md.**
|
||||||
;;;;
|
;;;;
|
||||||
;;;; 1. `GetCodepointPrevious` cannot be called at all. It reads BACKWARDS
|
;;;; 1. `GetCodepointPrevious` cannot be called at all. It reads BACKWARDS
|
||||||
;;;; from the pointer it is handed, and a Flan `string` crosses to C as a
|
;;;; from the pointer it is handed, and a Flan `string` crosses to C as a
|
||||||
@ -176,7 +176,7 @@
|
|||||||
;; Whether the TTF was there, asked once. A `defvar` and not the call itself
|
;; Whether the TTF was there, asked once. A `defvar` and not the call itself
|
||||||
;; in the draw loop: path-file? is a stat, and a syscall per frame to answer a
|
;; in the draw loop: path-file? is a stat, and a syscall per frame to answer a
|
||||||
;; question whose answer cannot change while the program runs is exactly what
|
;; question whose answer cannot change while the program runs is exactly what
|
||||||
;; the per-frame rule in PORTING.md is about.
|
;; the per-frame rule in docs/PORTING.md is about.
|
||||||
(defvar font-present bool)
|
(defvar font-present bool)
|
||||||
(defvar show-font-atlas bool)
|
(defvar show-font-atlas bool)
|
||||||
(defvar cursor i32)
|
(defvar cursor i32)
|
||||||
|
|||||||
@ -36,7 +36,7 @@
|
|||||||
;;;; u8]` globals here. The dimensions are compile-time constants in the C
|
;;;; u8]` globals here. The dimensions are compile-time constants in the C
|
||||||
;;;; too (the #defines and the two assignments right after), so nothing is
|
;;;; too (the #defines and the two assignments right after), so nothing is
|
||||||
;;;; lost by fixing them, and a global cannot hold a Vec in any case
|
;;;; lost by fixing them, and a global cannot hold a Vec in any case
|
||||||
;;;; (PORTING.md §3). 375 is 25*15, written out because Flan's array length
|
;;;; (docs/PORTING.md §3). 375 is 25*15, written out because Flan's array length
|
||||||
;;;; must be a literal.
|
;;;; must be a literal.
|
||||||
|
|
||||||
(import rl "vendor:raylib")
|
(import rl "vendor:raylib")
|
||||||
|
|||||||
@ -51,7 +51,7 @@
|
|||||||
;;;; and because the picture is a demonstration of the filter rather than the
|
;;;; and because the picture is a demonstration of the filter rather than the
|
||||||
;;;; point of the program.
|
;;;; point of the program.
|
||||||
;;;;
|
;;;;
|
||||||
;;;; One gap, written up in PORTING.md and worked around in `reload-texture`
|
;;;; One gap, written up in docs/PORTING.md and worked around in `reload-texture`
|
||||||
;;;; below: LoadImageColors answers a (Ptr Color) and UpdateTexture takes a
|
;;;; below: LoadImageColors answers a (Ptr Color) and UpdateTexture takes a
|
||||||
;;;; (Ptr u8), because the header spells its parameter `const void *` and Flan
|
;;;; (Ptr u8), because the header spells its parameter `const void *` and Flan
|
||||||
;;;; has no cast between pointer types. The address of the first field of the
|
;;;; has no cast between pointer types. The address of the first field of the
|
||||||
@ -143,7 +143,7 @@
|
|||||||
;; takes a (Ptr u8), the header having spelled that parameter `const void *`;
|
;; takes a (Ptr u8), the header having spelled that parameter `const void *`;
|
||||||
;; and there is no cast between pointer types in Flan. What there is, is the
|
;; and there is no cast between pointer types in Flan. What there is, is the
|
||||||
;; address of the red channel of pixel zero, which is the address of the
|
;; address of the red channel of pixel zero, which is the address of the
|
||||||
;; buffer said the long way round. See PORTING.md.
|
;; buffer said the long way round. See docs/PORTING.md.
|
||||||
(defn reload-texture [] ()
|
(defn reload-texture [] ()
|
||||||
(rl/unload-image im-copy)
|
(rl/unload-image im-copy)
|
||||||
(set im-copy (rl/image-copy im-origin))
|
(set im-copy (rl/image-copy im-origin))
|
||||||
|
|||||||
@ -189,7 +189,7 @@ let declared_name (d : decl) =
|
|||||||
|
|
||||||
(* ── Instrumenting a form with (pause) ─────────────────────────────── *)
|
(* ── Instrumenting a form with (pause) ─────────────────────────────── *)
|
||||||
|
|
||||||
(* [C-u C-c C-c] marks a form so the program stops when it runs — DISCUSS.md
|
(* [C-u C-c C-c] marks a form so the program stops when it runs — docs/DISCUSS.md
|
||||||
§9. The mark travels beside the source as a position and is applied *here*,
|
§9. The mark travels beside the source as a position and is applied *here*,
|
||||||
to the AST, rather than being spliced into the text the editor sends: text
|
to the AST, rather than being spliced into the text the editor sends: text
|
||||||
would shift every line and column after the insertion, and the error
|
would shift every line and column after the insertion, and the error
|
||||||
|
|||||||
@ -388,7 +388,7 @@ let wasm_main_source =
|
|||||||
(* ── The browser: the main loop, the shell, and the link ─────────────
|
(* ── The browser: the main loop, the shell, and the link ─────────────
|
||||||
The mechanism, and why it is not the one the old note predicted.
|
The mechanism, and why it is not the one the old note predicted.
|
||||||
|
|
||||||
BUILT.md says a web build "drives the loop with [emscripten_set_main_loop]
|
docs/BUILT.md says a web build "drives the loop with [emscripten_set_main_loop]
|
||||||
instead of a [while]. That is a different [main], not a different program."
|
instead of a [while]. That is a different [main], not a different program."
|
||||||
The first half is right about the browser and wrong about what it costs
|
The first half is right about the browser and wrong about what it costs
|
||||||
here: [emscripten_set_main_loop] wants the loop body as a callback, so every
|
here: [emscripten_set_main_loop] wants the loop body as a callback, so every
|
||||||
@ -916,7 +916,7 @@ let shared ?(opts = default) ~ir ~out () : timing =
|
|||||||
host. [flan reload] is precisely that caller. The complete answer is a
|
host. [flan reload] is precisely that caller. The complete answer is a
|
||||||
marker symbol the host defines and a module references, so the loader
|
marker symbol the host defines and a module references, so the loader
|
||||||
refuses the pair at dlopen rather than the processor refusing it at a
|
refuses the pair at dlopen rather than the processor refusing it at a
|
||||||
call. See HANDOFF-x86-aggregates.md. *)
|
call. See docs/handoffs/HANDOFF-x86-aggregates.md. *)
|
||||||
if opts.x86 then
|
if opts.x86 then
|
||||||
failwith
|
failwith
|
||||||
"--x86: Build.shared is the LLVM redefinition path, and an --x86 host \
|
"--x86: Build.shared is the LLVM redefinition path, and an --x86 host \
|
||||||
|
|||||||
@ -1742,7 +1742,7 @@ and var ctx loc ~want name =
|
|||||||
(* spec-memory.md puts the allocator in the calling convention as
|
(* spec-memory.md puts the allocator in the calling convention as
|
||||||
[context/allocator] and [context/temp]. They read as names rather than
|
[context/allocator] and [context/temp]. They read as names rather than
|
||||||
calls because that is how the spec writes them, and they are dynamic
|
calls because that is how the spec writes them, and they are dynamic
|
||||||
variables at run time rather than extra parameters — see BUILT.md for why
|
variables at run time rather than extra parameters — see docs/BUILT.md for why
|
||||||
the literal reading of "calling convention" is deferred. *)
|
the literal reading of "calling convention" is deferred. *)
|
||||||
| "context/allocator" ->
|
| "context/allocator" ->
|
||||||
expect loc ~want
|
expect loc ~want
|
||||||
@ -3493,7 +3493,7 @@ and named_call ctx ~want loc name args =
|
|||||||
expect loc ~want
|
expect loc ~want
|
||||||
(mk loc Types.Alloc (Tast.Prim (Tast.Rt "flan_arena_new", [ cap ])))
|
(mk loc Types.Alloc (Tast.Prim (Tast.Rt "flan_arena_new", [ cap ])))
|
||||||
(* Hands the pages back, which [free-all] deliberately does not — see
|
(* Hands the pages back, which [free-all] deliberately does not — see
|
||||||
BUILT.md, "free-all is retain-capacity". *)
|
docs/BUILT.md, "free-all is retain-capacity". *)
|
||||||
| "arena-destroy" ->
|
| "arena-destroy" ->
|
||||||
arity loc name 1 args;
|
arity loc name 1 args;
|
||||||
let a = check ctx ~want:Types.Alloc (List.hd args) in
|
let a = check ctx ~want:Types.Alloc (List.hd args) in
|
||||||
|
|||||||
@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
[declare-c] closed half the gap: the wrapper, the typedefs and the
|
[declare-c] closed half the gap: the wrapper, the typedefs and the
|
||||||
prototype are generated, so they cannot disagree with each other. The half
|
prototype are generated, so they cannot disagree with each other. The half
|
||||||
it left open is the one BUILT.md records as *trusted* — that the signature
|
it left open is the one docs/BUILT.md records as *trusted* — that the signature
|
||||||
somebody typed is the function's real signature. Nothing checked it,
|
somebody typed is the function's real signature. Nothing checked it,
|
||||||
because no header was ever read. This reads one.
|
because no header was ever read. This reads one.
|
||||||
|
|
||||||
@ -41,7 +41,7 @@
|
|||||||
package's [defstruct]s against the header's records — would be comparing
|
package's [defstruct]s against the header's records — would be comparing
|
||||||
the header with itself. Keeping the layouts hand-written is what makes
|
the header with itself. Keeping the layouts hand-written is what makes
|
||||||
[check_structs] an independent second source, and that check is the
|
[check_structs] an independent second source, and that check is the
|
||||||
cheapest real closure of BUILT.md's trusted-not-guaranteed gap: a
|
cheapest real closure of docs/BUILT.md's trusted-not-guaranteed gap: a
|
||||||
[_Static_assert] was rejected there as circular for exactly this reason,
|
[_Static_assert] was rejected there as circular for exactly this reason,
|
||||||
and this is not circular, because the two sides have different authors.
|
and this is not circular, because the two sides have different authors.
|
||||||
|
|
||||||
@ -810,7 +810,7 @@ let of_dump ~env ~taken ~bound_syms ~config (d : dump) : imported =
|
|||||||
|
|
||||||
(* The point of reading a header that the generator does not otherwise need.
|
(* The point of reading a header that the generator does not otherwise need.
|
||||||
|
|
||||||
BUILT.md rejected a [_Static_assert] on [sizeof]/[offsetof] as circular:
|
docs/BUILT.md rejected a [_Static_assert] on [sizeof]/[offsetof] as circular:
|
||||||
both sides would have come from the same field list. This is not circular.
|
both sides would have come from the same field list. This is not circular.
|
||||||
The [defstruct] was written by hand and the record comes from the library's
|
The [defstruct] was written by hand and the record comes from the library's
|
||||||
own header, so a disagreement is real information — and it is the failure
|
own header, so a disagreement is real information — and it is the failure
|
||||||
@ -868,7 +868,7 @@ let check_structs ~env ~(structs : (string * Ast.field list) list) (d : dump) =
|
|||||||
| None -> None)
|
| None -> None)
|
||||||
in
|
in
|
||||||
(* Names and widths both. Order is what a permuted [defstruct] gets wrong and
|
(* Names and widths both. Order is what a permuted [defstruct] gets wrong and
|
||||||
what BUILT.md says only a test can catch; width is the other half of the
|
what docs/BUILT.md says only a test can catch; width is the other half of the
|
||||||
same hazard and the one it calls out by name — [f64] where the library
|
same hazard and the one it calls out by name — [f64] where the library
|
||||||
says [float] lays out eight bytes where there are four, and every field
|
says [float] lays out eight bytes where there are four, and every field
|
||||||
after it moves. Comparing the rendered Flan type rather than the C
|
after it moves. Comparing the rendered Flan type rather than the C
|
||||||
@ -1268,7 +1268,7 @@ let header ~loc ~header:h ~flags ~known_structs ~known_enums ~taken ~bound_syms
|
|||||||
|
|
||||||
(* ── Printing a declaration back as source ─────────────────────────── *)
|
(* ── Printing a declaration back as source ─────────────────────────── *)
|
||||||
|
|
||||||
(* Which makes the third option in DISCUSS.md item 6 available at no extra
|
(* Which makes the third option in docs/DISCUSS.md item 6 available at no extra
|
||||||
cost: generate the declarations from the header, *commit the result*, and
|
cost: generate the declarations from the header, *commit the result*, and
|
||||||
regenerate when the library moves. That trade — explicit in the source,
|
regenerate when the library moves. That trade — explicit in the source,
|
||||||
checked against reality, no header read at build time — is a real one, and
|
checked against reality, no header read at build time — is a real one, and
|
||||||
@ -1309,7 +1309,7 @@ let decl_source (d : Ast.decl) =
|
|||||||
something more specific for a reason it recorded.
|
something more specific for a reason it recorded.
|
||||||
|
|
||||||
What is left after those is a real disagreement about a width, an arity or a
|
What is left after those is a real disagreement about a width, an arity or a
|
||||||
direction — which is exactly the class of bug BUILT.md warns about, where
|
direction — which is exactly the class of bug docs/BUILT.md warns about, where
|
||||||
[f64] against the library's [float] reads as garbage rather than as a link
|
[f64] against the library's [float] reads as garbage rather than as a link
|
||||||
error. *)
|
error. *)
|
||||||
|
|
||||||
@ -1378,7 +1378,7 @@ let diff_bound ~env ~(bound : (Ast.fn * string) list) (d : dump) =
|
|||||||
|
|
||||||
(* Generate once, commit the result, regenerate when the library moves.
|
(* Generate once, commit the result, regenerate when the library moves.
|
||||||
|
|
||||||
What that buys is in DISCUSS.md item 6 and it is not caching — the dump is
|
What that buys is in docs/DISCUSS.md item 6 and it is not caching — the dump is
|
||||||
already cached on disk and in memory, so a build that reads the header pays
|
already cached on disk and in memory, so a build that reads the header pays
|
||||||
for it once either way. It is that no header is needed by *anybody*: the
|
for it once either way. It is that no header is needed by *anybody*: the
|
||||||
declarations are in the repository, so they are greppable, they diff when
|
declarations are in the repository, so they are greppable, they diff when
|
||||||
@ -1398,7 +1398,7 @@ let diff_bound ~env ~(bound : (Ast.fn * string) list) (d : dump) =
|
|||||||
they come from, because the one function that writes the file is this one
|
they come from, because the one function that writes the file is this one
|
||||||
and it refuses when the two disagree. A regeneration that quietly rewrote
|
and it refuses when the two disagree. A regeneration that quietly rewrote
|
||||||
the bindings against a header the library does not match would produce
|
the bindings against a header the library does not match would produce
|
||||||
exactly the failure BUILT.md warns about — a permuted struct read as five
|
exactly the failure docs/BUILT.md warns about — a permuted struct read as five
|
||||||
plausible numbers rather than as a link error — and it would produce it in a
|
plausible numbers rather than as a link error — and it would produce it in a
|
||||||
committed file that looks reviewed.
|
committed file that looks reviewed.
|
||||||
|
|
||||||
|
|||||||
@ -1017,7 +1017,7 @@ let locals t ~frame =
|
|||||||
refused) ]))
|
refused) ]))
|
||||||
|
|
||||||
(* [(:op "inspect" :frame N :slot I :path (...))] — the inspector's second
|
(* [(:op "inspect" :frame N :slot I :path (...))] — the inspector's second
|
||||||
rooting mode. [BUILT.md]'s "Two ways to root a walk" says what each root
|
rooting mode. [docs/BUILT.md]'s "Two ways to root a walk" says what each root
|
||||||
can and cannot do; this is the half that names a frame.
|
can and cannot do; this is the half that names a frame.
|
||||||
|
|
||||||
[i] in the break buffer used to send a local's *name* to be evaluated as an
|
[i] in the break buffer used to send a local's *name* to be evaluated as an
|
||||||
@ -1080,7 +1080,7 @@ let inspect t ~frame ~slot ~path =
|
|||||||
|
|
||||||
(* ── The allocation registry, read from this end ───────────────────── *)
|
(* ── The allocation registry, read from this end ───────────────────── *)
|
||||||
|
|
||||||
(* [BUILT.md]'s "An address answers with a type" is what the table is and why.
|
(* [docs/BUILT.md]'s "An address answers with a type" is what the table is and why.
|
||||||
What follows is the reader: three verbs that ask the agent for what is
|
What follows is the reader: three verbs that ask the agent for what is
|
||||||
recorded, and one of them turns a recorded *name* back into a type.
|
recorded, and one of them turns a recorded *name* back into a type.
|
||||||
|
|
||||||
@ -2530,7 +2530,7 @@ let two_process ?(debug = false) ~file ~sock () =
|
|||||||
(* Everything above this line works the same either way. What follows is the
|
(* Everything above this line works the same either way. What follows is the
|
||||||
merged build: one executable that is the compiled Flan program *and* holds
|
merged build: one executable that is the compiled Flan program *and* holds
|
||||||
the whole OCaml compiler, with the editor's socket served from a thread
|
the whole OCaml compiler, with the editor's socket served from a thread
|
||||||
inside it. DISCUSS.md item 14 is the spike this is built from.
|
inside it. docs/DISCUSS.md item 14 is the spike this is built from.
|
||||||
|
|
||||||
The shape, and it is this way round for a reason:
|
The shape, and it is this way round for a reason:
|
||||||
|
|
||||||
|
|||||||
@ -164,7 +164,7 @@ CAMLprim value flan_peek_bytes(value p, value off, value n) {
|
|||||||
*
|
*
|
||||||
* The runtime system is released across the call. A delivery does a [dlopen],
|
* The runtime system is released across the call. A delivery does a [dlopen],
|
||||||
* which is milliseconds of relocation and the loader lock, and holding OCaml's
|
* which is milliseconds of relocation and the loader lock, and holding OCaml's
|
||||||
* lock through it stalls every other OCaml thread for no reason — DISCUSS.md
|
* lock through it stalls every other OCaml thread for no reason — docs/DISCUSS.md
|
||||||
* §14's third cost, in the one place this lane creates it. Nothing the agent
|
* §14's third cost, in the one place this lane creates it. Nothing the agent
|
||||||
* does touches an OCaml value, so there is nothing to keep alive across it. */
|
* does touches an OCaml value, so there is nothing to keep alive across it. */
|
||||||
extern char *flan_agent_request(const char *line, uint64_t *len)
|
extern char *flan_agent_request(const char *line, uint64_t *len)
|
||||||
|
|||||||
@ -1034,7 +1034,7 @@ and value_at f (e : Tast.expr) : string =
|
|||||||
same name would do, at the point the *address* is taken rather than at the
|
same name would do, at the point the *address* is taken rather than at the
|
||||||
call. What that does not give is a value taken before a redefinition and
|
call. What that does not give is a value taken before a redefinition and
|
||||||
called after it: that one is still the old body, because there is nothing
|
called after it: that one is still the old body, because there is nothing
|
||||||
left to re-resolve once the address is in a slot. Named in BUILT.md rather
|
left to re-resolve once the address is in a slot. Named in docs/BUILT.md rather
|
||||||
than papered over with a trampoline. *)
|
than papered over with a trampoline. *)
|
||||||
| Tast.FnAddr (Tast.Fnval n) -> body_of f n
|
| Tast.FnAddr (Tast.Fnval n) -> body_of f n
|
||||||
| Tast.Addr p -> fst (place f p)
|
| Tast.Addr p -> fst (place f p)
|
||||||
@ -2121,7 +2121,7 @@ and prim f (e : Tast.expr) (p : Tast.prim) (args : Tast.expr list) =
|
|||||||
only [Rt] symbols that can transfer, so they are the only ones that take
|
only [Rt] symbols that can transfer, so they are the only ones that take
|
||||||
the channel and the only ones guarded — everything else in this family
|
the channel and the only ones guarded — everything else in this family
|
||||||
is arithmetic over a container header and cannot reach a handler. A Vec
|
is arithmetic over a container header and cannot reach a handler. A Vec
|
||||||
is checked inside the runtime rather than in emitted IR (BUILT.md), so
|
is checked inside the runtime rather than in emitted IR (docs/BUILT.md), so
|
||||||
this is where (at v i) gets what (at arr i) gets from [check_at]. *)
|
this is where (at v i) gets what (at arr i) gets from [check_at]. *)
|
||||||
let signals =
|
let signals =
|
||||||
String.equal sym "flan_vec_at" || String.equal sym "flan_vec_as_slice"
|
String.equal sym "flan_vec_at" || String.equal sym "flan_vec_as_slice"
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
(** Macro expansion: the pass between the reader and [Parse].
|
(** Macro expansion: the pass between the reader and [Parse].
|
||||||
|
|
||||||
There is no interpreter and there is not going to be one (BUILT.md, "Why
|
There is no interpreter and there is not going to be one (docs/BUILT.md, "Why
|
||||||
there is no interpreter"), so running a macro at compile time means
|
there is no interpreter"), so running a macro at compile time means
|
||||||
compiling it and loading it into this process. Every piece of that is
|
compiling it and loading it into this process. Every piece of that is
|
||||||
already built and measured — [Emit.macro_thunk], [Build.macro_module],
|
already built and measured — [Emit.macro_thunk], [Build.macro_module],
|
||||||
|
|||||||
@ -341,7 +341,7 @@ let qualify_decl owned alias (d : Ast.decl) : Ast.decl =
|
|||||||
[(Form.Sym {.s "begin"})] whose name is a *string in an argument* rather
|
[(Form.Sym {.s "begin"})] whose name is a *string in an argument* rather
|
||||||
than a name anything would rename. That is not an accident to work around:
|
than a name anything would rename. That is not an accident to work around:
|
||||||
it is the property [Macro]'s walk depends on, the one that makes a
|
it is the property [Macro]'s walk depends on, the one that makes a
|
||||||
quasiquoted call output rather than a compile-order dependency (BUILT.md,
|
quasiquoted call output rather than a compile-order dependency (docs/BUILT.md,
|
||||||
"A call inside a quasiquote is output, not a dependency"). It is also
|
"A call inside a quasiquote is output, not a dependency"). It is also
|
||||||
exactly what puts the name out of a rename's reach.
|
exactly what puts the name out of a rename's reach.
|
||||||
|
|
||||||
@ -421,7 +421,7 @@ let rec rename_form owned alias bound (f : Form.t) : Form.t =
|
|||||||
Desugared on the way out, because [Macro.program] is handed forms that
|
Desugared on the way out, because [Macro.program] is handed forms that
|
||||||
[Parse.parse_forms] has already run [Expand.quasiquote] over and its rounds
|
[Parse.parse_forms] has already run [Expand.quasiquote] over and its rounds
|
||||||
read them with that assumed. An un-desugared one would make a quasiquoted
|
read them with that assumed. An un-desugared one would make a quasiquoted
|
||||||
call look like a real one, which is the false ring BUILT.md records the
|
call look like a real one, which is the false ring docs/BUILT.md records the
|
||||||
first cycle test walking into. *)
|
first cycle test walking into. *)
|
||||||
let qualify_macro owned alias (f : Form.t) : Form.t option =
|
let qualify_macro owned alias (f : Form.t) : Form.t option =
|
||||||
match f.Form.v with
|
match f.Form.v with
|
||||||
@ -704,7 +704,7 @@ let words line =
|
|||||||
nothing if it is not".
|
nothing if it is not".
|
||||||
|
|
||||||
That marker is what lets a package offer the check without requiring it.
|
That marker is what lets a package offer the check without requiring it.
|
||||||
[vendor/raylib] builds today against a shared library alone — BUILT.md's "no
|
[vendor/raylib] builds today against a shared library alone — docs/BUILT.md's "no
|
||||||
raylib headers are needed", which is a real property: a build needs
|
raylib headers are needed", which is a real property: a build needs
|
||||||
libraylib linkable and not raylib-devel installed. A required header would
|
libraylib linkable and not raylib-devel installed. A required header would
|
||||||
take that away from everyone in order to give the check to the people who
|
take that away from everyone in order to give the check to the people who
|
||||||
@ -969,7 +969,7 @@ let rec import ~seen ~open_ ~loc alias dir =
|
|||||||
the header is the package's own claim about what it binds; a
|
the header is the package's own claim about what it binds; a
|
||||||
[defstruct] that disagrees with it lays fields out in the
|
[defstruct] that disagrees with it lays fields out in the
|
||||||
wrong order and reads as five plausible numbers rather than as
|
wrong order and reads as five plausible numbers rather than as
|
||||||
a link error, which is the failure BUILT.md says only a test
|
a link error, which is the failure docs/BUILT.md says only a test
|
||||||
can catch. Continuing past a known-wrong layout to produce a
|
can catch. Continuing past a known-wrong layout to produce a
|
||||||
program that will read garbage is the shape the house rule
|
program that will read garbage is the shape the house rule
|
||||||
against swallowing things exists to prevent.
|
against swallowing things exists to prevent.
|
||||||
|
|||||||
@ -1466,7 +1466,7 @@ let source = {flan|
|
|||||||
;; site attached to what a macro produces", and it is what the queued
|
;; site attached to what a macro produces", and it is what the queued
|
||||||
;; structured-error work will read.
|
;; structured-error work will read.
|
||||||
;;
|
;;
|
||||||
;; Case order is the tag order (BUILT.md, unions), so this list is a layout
|
;; Case order is the tag order (docs/BUILT.md, unions), so this list is a layout
|
||||||
;; contract with lib/expand.ml's marshaller and may not be reordered.
|
;; contract with lib/expand.ml's marshaller and may not be reordered.
|
||||||
(defunion Form
|
(defunion Form
|
||||||
[(Sym [s string])
|
[(Sym [s string])
|
||||||
|
|||||||
@ -87,7 +87,7 @@ let rec same_const (a : Tast.expr) (b : Tast.expr) =
|
|||||||
desugars a package's macro on its way out for the same reason — but
|
desugars a package's macro on its way out for the same reason — but
|
||||||
[Parse.imported_macros] is read by [Macro.program] directly, past that map.
|
[Parse.imported_macros] is read by [Macro.program] directly, past that map.
|
||||||
An undesugared body still has its quasiquote in it, which makes a
|
An undesugared body still has its quasiquote in it, which makes a
|
||||||
quasiquoted call look like a real one: the false ring BUILT.md records the
|
quasiquoted call look like a real one: the false ring docs/BUILT.md records the
|
||||||
first cycle test walking into.
|
first cycle test walking into.
|
||||||
|
|
||||||
Unqualified, and that is the point: a buffer writes its own macro's bare
|
Unqualified, and that is the point: a buffer writes its own macro's bare
|
||||||
@ -345,7 +345,7 @@ type change = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
(* [pause] is [C-u C-c C-c]: the position, in the source just sent, of the form
|
(* [pause] is [C-u C-c C-c]: the position, in the source just sent, of the form
|
||||||
the program should stop at — DISCUSS.md §9. It arrives as a separate field
|
the program should stop at — docs/DISCUSS.md §9. It arrives as a separate field
|
||||||
rather than spliced into [src], because splicing text would move every
|
rather than spliced into [src], because splicing text would move every
|
||||||
location after it, and it is applied below to the *declarations*, once
|
location after it, and it is applied below to the *declarations*, once
|
||||||
parsing has attached those locations and [Load] has qualified the names.
|
parsing has attached those locations and [Load] has qualified the names.
|
||||||
|
|||||||
12
lib/x86.ml
12
lib/x86.ml
@ -7,7 +7,7 @@
|
|||||||
|
|
||||||
{1 The internal calling convention}
|
{1 The internal calling convention}
|
||||||
|
|
||||||
The spike's report (DISCUSS.md item 15) called the internal convention the
|
The spike's report (docs/DISCUSS.md item 15) called the internal convention the
|
||||||
sharpest obstacle, because LLVM's answer for a first-class struct is an
|
sharpest obstacle, because LLVM's answer for a first-class struct is an
|
||||||
implementation detail discoverable only by disassembly — a 24-byte struct
|
implementation detail discoverable only by disassembly — a 24-byte struct
|
||||||
comes back in [rax]:[rdx]:[rcx], and [rcx] is a register SysV never uses
|
comes back in [rax]:[rdx]:[rcx], and [rcx] is a register SysV never uses
|
||||||
@ -745,7 +745,7 @@ let addr_sym f ~dst s =
|
|||||||
holds the cell's *address*. Collapsing them was this lane's one real bug,
|
holds the cell's *address*. Collapsing them was this lane's one real bug,
|
||||||
and it looked exactly right in the disassembly: [mov r11, cell@GOTPCREL(%rip)]
|
and it looked exactly right in the disassembly: [mov r11, cell@GOTPCREL(%rip)]
|
||||||
beside [call *%r11] reads as "call through the cell" and in fact calls the
|
beside [call *%r11] reads as "call through the cell" and in fact calls the
|
||||||
cell. DISCUSS.md item 15 said this is how hand-encoding fails. *)
|
cell. docs/DISCUSS.md item 15 said this is how hand-encoding fails. *)
|
||||||
let load_sym f ~dst s =
|
let load_sym f ~dst s =
|
||||||
if f.ext s then begin
|
if f.ext s then begin
|
||||||
load_int f.b ~dst ~mm:(Got s) ~size:8 ~signed:false;
|
load_int f.b ~dst ~mm:(Got s) ~size:8 ~signed:false;
|
||||||
@ -1118,7 +1118,7 @@ and lower_at f (e : Tast.expr) (dst : loc) : unit =
|
|||||||
| Tast.None_ -> zero_value f dst t
|
| Tast.None_ -> zero_value f dst t
|
||||||
(* Reading an uninitialised value gives whatever the slot held: stable
|
(* Reading an uninitialised value gives whatever the slot held: stable
|
||||||
garbage rather than LLVM's [poison]. The one construct where the two
|
garbage rather than LLVM's [poison]. The one construct where the two
|
||||||
backends are meant to differ — DISCUSS.md item 15, question 4. *)
|
backends are meant to differ — docs/DISCUSS.md item 15, question 4. *)
|
||||||
| Tast.Uninit _ -> ()
|
| Tast.Uninit _ -> ()
|
||||||
| Tast.Local _ | Tast.Global _ | Tast.Field _ | Tast.Deref _ ->
|
| Tast.Local _ | Tast.Global _ | Tast.Field _ | Tast.Deref _ ->
|
||||||
let src = lvalue f e in
|
let src = lvalue f e in
|
||||||
@ -1877,9 +1877,9 @@ and check_slice f (base : loc) (ty : Types.t) (loc : Loc.t) (lo : Tast.expr)
|
|||||||
bounds_call f "flan_slice_error" loc [ a; b; c ];
|
bounds_call f "flan_slice_error" loc [ a; b; c ];
|
||||||
lbl f.b ok)
|
lbl f.b ok)
|
||||||
|
|
||||||
(* [emit.ml]'s [check_div] and [check_cast], item 3 of HANDOFF-x86-rt.md's
|
(* [emit.ml]'s [check_div] and [check_cast], item 3 of docs/handoffs/HANDOFF-x86-rt.md's
|
||||||
list, and the one item on it that was blocked on a language decision rather
|
list, and the one item on it that was blocked on a language decision rather
|
||||||
than on code. That decision is in HANDOFF-arith.md: a divide or remainder by
|
than on code. That decision is in docs/handoffs/HANDOFF-arith.md: a divide or remainder by
|
||||||
zero, the one division that overflows, and a float to integer cast whose
|
zero, the one division that overflows, and a float to integer cast whose
|
||||||
value does not fit all signal ArithError, exactly as a bad index signals
|
value does not fit all signal ArithError, exactly as a bad index signals
|
||||||
BoundsError.
|
BoundsError.
|
||||||
@ -2112,7 +2112,7 @@ and call_c f ~sym ~args ~rty dst =
|
|||||||
[Rt] symbols that can transfer, so they are the only ones that take the
|
[Rt] symbols that can transfer, so they are the only ones that take the
|
||||||
channel and the only ones guarded — everything else in this family is
|
channel and the only ones guarded — everything else in this family is
|
||||||
arithmetic over a container header and cannot reach a handler. A Vec is
|
arithmetic over a container header and cannot reach a handler. A Vec is
|
||||||
checked inside the runtime rather than in emitted code (BUILT.md), so this
|
checked inside the runtime rather than in emitted code (docs/BUILT.md), so this
|
||||||
is where [(at v i)] gets what [(at arr i)] gets from [check_at]. *)
|
is where [(at v i)] gets what [(at arr i)] gets from [check_at]. *)
|
||||||
and rt_signals sym =
|
and rt_signals sym =
|
||||||
String.equal sym "flan_vec_at" || String.equal sym "flan_vec_as_slice"
|
String.equal sym "flan_vec_at" || String.equal sym "flan_vec_as_slice"
|
||||||
|
|||||||
@ -608,7 +608,7 @@ void flan_dev_watch_end(void) {
|
|||||||
* four [flan_dev_watch_emit_*] above are the emitter it would be pointed at,
|
* four [flan_dev_watch_emit_*] above are the emitter it would be pointed at,
|
||||||
* shaped exactly like the [print] arm's. What is missing is the
|
* shaped exactly like the [print] arm's. What is missing is the
|
||||||
* [(watch "hp" hp)] arm in check.ml that joins the two, which is a file this
|
* [(watch "hp" hp)] arm in check.ml that joins the two, which is a file this
|
||||||
* change does not own. BUILT.md says what that arm is. */
|
* change does not own. docs/BUILT.md says what that arm is. */
|
||||||
int32_t flan_dev_watch_i64(const char *name, int64_t x) {
|
int32_t flan_dev_watch_i64(const char *name, int64_t x) {
|
||||||
if (!flan_dev_watch_begin(name)) return 0;
|
if (!flan_dev_watch_begin(name)) return 0;
|
||||||
flan_dev_watch_emit_i64(x);
|
flan_dev_watch_emit_i64(x);
|
||||||
@ -642,7 +642,7 @@ int32_t flan_dev_watch_str(const char *name, const char *s) {
|
|||||||
/* The scalar watch above keeps one value per name, and from a hot inner loop
|
/* The scalar watch above keeps one value per name, and from a hot inner loop
|
||||||
* that is nearly useless: you see whichever of the 91,200 cells happened to
|
* that is nearly useless: you see whichever of the 91,200 cells happened to
|
||||||
* run last. This is the other half — the port of [spy-num] from the author's
|
* run last. This is the other half — the port of [spy-num] from the author's
|
||||||
* watch.clj, which exists for exactly that reason and is the piece PORTING.md
|
* watch.clj, which exists for exactly that reason and is the piece docs/PORTING.md
|
||||||
* calls the least obvious and the most valuable.
|
* calls the least obvious and the most valuable.
|
||||||
*
|
*
|
||||||
* **What a slot keeps: count, min, max, last, mean.** Five numbers, and the
|
* **What a slot keeps: count, min, max, last, mean.** Five numbers, and the
|
||||||
@ -1053,7 +1053,7 @@ static int flan_reg_full; /* something found no slot */
|
|||||||
* flan_rt.c are called unconditionally and begin with this load and a
|
* flan_rt.c are called unconditionally and begin with this load and a
|
||||||
* not-taken branch, because flan_dev.c is linked into every build and a
|
* not-taken branch, because flan_dev.c is linked into every build and a
|
||||||
* second version of the allocator gated on a build flag is worse than a
|
* second version of the allocator gated on a build flag is worse than a
|
||||||
* branch. That is a real cost and not zero; BUILT.md says so rather than
|
* branch. That is a real cost and not zero; docs/BUILT.md says so rather than
|
||||||
* repeating the claim that a release build carries nothing. */
|
* repeating the claim that a release build carries nothing. */
|
||||||
static void flan_reg_report(void); /* the exit report, at the bottom */
|
static void flan_reg_report(void); /* the exit report, at the bottom */
|
||||||
|
|
||||||
@ -1378,7 +1378,7 @@ int64_t flan_dev_reg_by_type(int32_t live_only, int64_t *counts,
|
|||||||
* Registered by [flan_dev_reg_enable] and therefore only in a dev build,
|
* Registered by [flan_dev_reg_enable] and therefore only in a dev build,
|
||||||
* which is the point: a file-scope destructor would run in *every* build,
|
* which is the point: a file-scope destructor would run in *every* build,
|
||||||
* because this file is compiled into every build, and that would be a third
|
* because this file is compiled into every build, and that would be a third
|
||||||
* place a release build is not free. BUILT.md names two and only two.
|
* place a release build is not free. docs/BUILT.md names two and only two.
|
||||||
*
|
*
|
||||||
* Off unless FLAN_DEV_LEAKS is set, and that is not timidity. The acceptance
|
* Off unless FLAN_DEV_LEAKS is set, and that is not timidity. The acceptance
|
||||||
* table reads programs/registry.flan's output with stderr folded in, so a
|
* table reads programs/registry.flan's output with stderr folded in, so a
|
||||||
|
|||||||
@ -774,7 +774,7 @@ static int flan_over_budget(flan_allocator *a, int64_t size) {
|
|||||||
* an address, or a range of them. So this half is unconditional and calls into
|
* an address, or a range of them. So this half is unconditional and calls into
|
||||||
* flan_dev.c, which is linked into every build and begins each of these with a
|
* flan_dev.c, which is linked into every build and begins each of these with a
|
||||||
* load of a flag that only a dev build ever sets. A release build pays a load
|
* load of a flag that only a dev build ever sets. A release build pays a load
|
||||||
* and a not-taken branch per free, which is not nothing, and BUILT.md says so.
|
* and a not-taken branch per free, which is not nothing, and docs/BUILT.md says so.
|
||||||
*/
|
*/
|
||||||
void flan_dev_reg_note(void *base, int64_t bytes, int64_t elem,
|
void flan_dev_reg_note(void *base, int64_t bytes, int64_t elem,
|
||||||
const char *type, int64_t typelen);
|
const char *type, int64_t typelen);
|
||||||
@ -905,7 +905,7 @@ static flan_allocator flan_heap = {
|
|||||||
/* -- The arena: one fixed backing buffer and a bump offset. ----------
|
/* -- The arena: one fixed backing buffer and a bump offset. ----------
|
||||||
*
|
*
|
||||||
* `free-all` is retain-capacity: offset = 0, the pages stay. That is an
|
* `free-all` is retain-capacity: offset = 0, the pages stay. That is an
|
||||||
* announced amendment to spec-memory.md's operation table (see BUILT.md) and
|
* announced amendment to spec-memory.md's operation table (see docs/BUILT.md) and
|
||||||
* it is what Odin's arena_free_all already does in effect. Handing the pages
|
* it is what Odin's arena_free_all already does in effect. Handing the pages
|
||||||
* back is `arena-destroy`, a separate operation, because a frame arena reset
|
* back is `arena-destroy`, a separate operation, because a frame arena reset
|
||||||
* every frame must not return memory only to ask for it again.
|
* every frame must not return memory only to ask for it again.
|
||||||
@ -998,7 +998,7 @@ static void *flan_arena_proc(flan_allocator *a, int32_t mode, void *p,
|
|||||||
* signature. The spec calls it part of the calling convention; taking that
|
* signature. The spec calls it part of the calling convention; taking that
|
||||||
* literally would touch every function signature, the FFI shim, the dev
|
* literally would touch every function signature, the FFI shim, the dev
|
||||||
* trampolines and the reload ABI, for the same observable behaviour. The
|
* trampolines and the reload ABI, for the same observable behaviour. The
|
||||||
* literal reading is deferred and BUILT.md says so.
|
* literal reading is deferred and docs/BUILT.md says so.
|
||||||
*
|
*
|
||||||
* There are no threads in Flan, so a plain global is the whole of it. */
|
* There are no threads in Flan, so a plain global is the whole of it. */
|
||||||
|
|
||||||
@ -1133,7 +1133,7 @@ _Noreturn void flan_free_all_fail(const uint8_t *loc, int64_t loclen) {
|
|||||||
*
|
*
|
||||||
* ptr len cap allocator the release layout spec-memory.md fixes
|
* ptr len cap allocator the release layout spec-memory.md fixes
|
||||||
* gen bumped on every reallocation — the stale-slice
|
* gen bumped on every reallocation — the stale-slice
|
||||||
* word. It has no reader yet; see BUILT.md.
|
* word. It has no reader yet; see docs/BUILT.md.
|
||||||
* epoch the allocator's epoch when this Vec last
|
* epoch the allocator's epoch when this Vec last
|
||||||
* touched it. Any operation on a container whose
|
* touched it. Any operation on a container whose
|
||||||
* recorded epoch has moved traps.
|
* recorded epoch has moved traps.
|
||||||
@ -1142,7 +1142,7 @@ _Noreturn void flan_free_all_fail(const uint8_t *loc, int64_t loclen) {
|
|||||||
* is not laziness: a redefinition module is built by llc and ld against a host
|
* is not laziness: a redefinition module is built by llc and ld against a host
|
||||||
* that was built separately, and nothing makes the two agree on a struct size.
|
* that was built separately, and nothing makes the two agree on a struct size.
|
||||||
* A layout that changes with a build flag is a layout that can disagree across
|
* A layout that changes with a build flag is a layout that can disagree across
|
||||||
* that boundary silently. Dropping them in release is deferred and BUILT.md
|
* that boundary silently. Dropping them in release is deferred and docs/BUILT.md
|
||||||
* says what it is blocked on.
|
* says what it is blocked on.
|
||||||
*
|
*
|
||||||
* Every entry point returns int8_t 1/0 for "did it fit", and never reports
|
* Every entry point returns int8_t 1/0 for "did it fit", and never reports
|
||||||
@ -1243,7 +1243,7 @@ static int8_t flan_vec_grow(flan_vec *v, int64_t want, int64_t size,
|
|||||||
v->ptr = p;
|
v->ptr = p;
|
||||||
v->cap = cap;
|
v->cap = cap;
|
||||||
/* Any slice taken before this points at storage that may have moved. The
|
/* Any slice taken before this points at storage that may have moved. The
|
||||||
* word is bumped here and read nowhere yet; see BUILT.md. */
|
* word is bumped here and read nowhere yet; see docs/BUILT.md. */
|
||||||
v->gen++;
|
v->gen++;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -95,4 +95,4 @@ int64_t spike_probe_align(int64_t x) {
|
|||||||
* omission: check.ml rejects an aggregate in a [declare] signature and the
|
* omission: check.ml rejects an aggregate in a [declare] signature and the
|
||||||
* generated shim flattens every one, so no Flan-emitted call ever passes a
|
* generated shim flattens every one, so no Flan-emitted call ever passes a
|
||||||
* struct to C. The aggregate problem is real but it is on the Flan-to-Flan
|
* struct to C. The aggregate problem is real but it is on the Flan-to-Flan
|
||||||
* side, which is measured in DISCUSS.md item 15 and not from here. */
|
* side, which is measured in docs/DISCUSS.md item 15 and not from here. */
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
# What the hand-written x86-64 backend costs
|
# What the hand-written x86-64 backend costs
|
||||||
|
|
||||||
`survey.sh` has said for three handoffs that this backend agrees with LLVM on all 97 corpus programs it can build.
|
`survey.sh` has said for three handoffs that this backend agrees with LLVM on all 97 corpus programs it can build.
|
||||||
Item 7 of `HANDOFF-x86-rt.md` is the other half of that sentence — nobody had a number for what the agreement
|
Item 7 of `docs/handoffs/HANDOFF-x86-rt.md` is the other half of that sentence — nobody had a number for what the agreement
|
||||||
costs — and it came with a list of suspects: a guard after every call, three frame temporaries per bounds check,
|
costs — and it came with a list of suspects: a guard after every call, three frame temporaries per bounds check,
|
||||||
every intermediate in memory, `rep movsb` block copies, and an extra load per call site in a dev build. This is
|
every intermediate in memory, `rep movsb` block copies, and an extra load per call site in a dev build. This is
|
||||||
the measurement. It does not change anything; two of the five suspects turn out not to matter, and the one that
|
the measurement. It does not change anything; two of the five suspects turn out not to matter, and the one that
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
# What does the hand-written backend cost, against LLVM, on the same programs?
|
# What does the hand-written backend cost, against LLVM, on the same programs?
|
||||||
#
|
#
|
||||||
# survey.sh answers "does it agree". This answers "what does agreeing cost",
|
# survey.sh answers "does it agree". This answers "what does agreeing cost",
|
||||||
# which is item 7 of HANDOFF-x86-rt.md and the one thing about this backend
|
# which is item 7 of docs/handoffs/HANDOFF-x86-rt.md and the one thing about this backend
|
||||||
# nobody had a number for. It builds each program the same two ways the
|
# nobody had a number for. It builds each program the same two ways the
|
||||||
# survey does, and for each records three sizes and a time:
|
# survey does, and for each records three sizes and a time:
|
||||||
#
|
#
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
# Does the hand-written backend agree with LLVM?
|
# Does the hand-written backend agree with LLVM?
|
||||||
#
|
#
|
||||||
# The only honest test of a hand-encoded backend is what the program prints and
|
# The only honest test of a hand-encoded backend is what the program prints and
|
||||||
# what it exits with -- DISCUSS.md item 15 and item 16 both say so, and both
|
# what it exits with -- docs/DISCUSS.md item 15 and item 16 both say so, and both
|
||||||
# say it after a disassembly that read perfectly beside a wrong answer. So this
|
# say it after a disassembly that read perfectly beside a wrong answer. So this
|
||||||
# builds every program in test/programs twice, runs both, and diffs stdout,
|
# builds every program in test/programs twice, runs both, and diffs stdout,
|
||||||
# stderr and the exit status. objdump is for after a program already has the
|
# stderr and the exit status. objdump is for after a program already has the
|
||||||
|
|||||||
@ -6,7 +6,7 @@
|
|||||||
;;;; with it and the session is the thing the project is built around never
|
;;;; with it and the session is the thing the project is built around never
|
||||||
;;;; having to restart. And the route in is the most ordinary one there is: a
|
;;;; having to restart. And the route in is the most ordinary one there is: a
|
||||||
;;;; grid indexed from a mouse position is out of bounds the first time the
|
;;;; grid indexed from a mouse position is out of bounds the first time the
|
||||||
;;;; pointer leaves the window (PORTING.md, §3).
|
;;;; pointer leaves the window (docs/PORTING.md, §3).
|
||||||
;;;;
|
;;;;
|
||||||
;;;; So a failed bounds check signals BoundsError with `error`, the same way a
|
;;;; So a failed bounds check signals BoundsError with `error`, the same way a
|
||||||
;;;; failed allocation signals StorageExhausted, and dies with the old message
|
;;;; failed allocation signals StorageExhausted, and dies with the old message
|
||||||
@ -28,7 +28,7 @@
|
|||||||
;;;;
|
;;;;
|
||||||
;;;; 1. The frame is abandoned and the program carries on. `frames` counts
|
;;;; 1. The frame is abandoned and the program carries on. `frames` counts
|
||||||
;;;; the ones that finished and `skipped` the ones that did not.
|
;;;; the ones that finished and `skipped` the ones that did not.
|
||||||
;;;; 2. **Defers run.** A trap ran none, which BUILT.md recorded as following
|
;;;; 2. **Defers run.** A trap ran none, which docs/BUILT.md recorded as following
|
||||||
;;;; from the noreturn-then-unreachable shape rather than as a decision.
|
;;;; from the noreturn-then-unreachable shape rather than as a decision.
|
||||||
;;;; The shape changed, so the question had to be answered rather than
|
;;;; The shape changed, so the question had to be answered rather than
|
||||||
;;;; inherited: an *answered* bounds failure leaves through the same
|
;;;; inherited: an *answered* bounds failure leaves through the same
|
||||||
|
|||||||
@ -7,7 +7,7 @@
|
|||||||
;;;; editor picks up a stopped program with the stack, the locals and the
|
;;;; editor picks up a stopped program with the stack, the locals and the
|
||||||
;;;; globals readable and the restarts on offer.
|
;;;; globals readable and the restarts on offer.
|
||||||
;;;;
|
;;;;
|
||||||
;;;; That is the claim `PORTING.md` said was missing, and it is worth testing
|
;;;; That is the claim `docs/PORTING.md` said was missing, and it is worth testing
|
||||||
;;;; end to end rather than reasoning about: before this, a bad index called
|
;;;; end to end rather than reasoning about: before this, a bad index called
|
||||||
;;;; exit(134), and with `flan dev` running as one process that took the
|
;;;; exit(134), and with `flan dev` running as one process that took the
|
||||||
;;;; compiler and the session with it.
|
;;;; compiler and the session with it.
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
;;;; Frame rollback: the half of the frame loop that `continue` does not do.
|
;;;; Frame rollback: the half of the frame loop that `continue` does not do.
|
||||||
;;;;
|
;;;;
|
||||||
;;;; PORTING.md Tier 1 item 6. Not a language feature — restart-case, struct
|
;;;; docs/PORTING.md Tier 1 item 6. Not a language feature — restart-case, struct
|
||||||
;;;; assignment and fixed-arrays-as-values are all built. This is the worked
|
;;;; assignment and fixed-arrays-as-values are all built. This is the worked
|
||||||
;;;; example, the way sand.flan is the worked example for the loop itself.
|
;;;; example, the way sand.flan is the worked example for the loop itself.
|
||||||
;;;;
|
;;;;
|
||||||
|
|||||||
@ -10,7 +10,7 @@
|
|||||||
;;;; It is all one function because a Pool is move-only exactly as a Vec is,
|
;;;; It is all one function because a Pool is move-only exactly as a Vec is,
|
||||||
;;;; so passing one to a helper *consumes* it — there is no borrowing
|
;;;; so passing one to a helper *consumes* it — there is no borrowing
|
||||||
;;;; parameter in the language yet. That is not a pool question and this
|
;;;; parameter in the language yet. That is not a pool question and this
|
||||||
;;;; program does not work around it; see BUILT.md.
|
;;;; program does not work around it; see docs/BUILT.md.
|
||||||
|
|
||||||
(defstruct Enemy [hp i32 kind i32])
|
(defstruct Enemy [hp i32 kind i32])
|
||||||
|
|
||||||
|
|||||||
@ -18,7 +18,7 @@
|
|||||||
;;;;
|
;;;;
|
||||||
;;;; Nothing here introduces a name the host was not built with. X86.redefinition
|
;;;; Nothing here introduces a name the host was not built with. X86.redefinition
|
||||||
;;;; refuses those by name — that is the registry path, and it is item 1 of
|
;;;; refuses those by name — that is the registry path, and it is item 1 of
|
||||||
;;;; HANDOFF-x86-redef.md's "what remains" rather than anything to do with
|
;;;; docs/handoffs/HANDOFF-x86-redef.md's "what remains" rather than anything to do with
|
||||||
;;;; aggregates.
|
;;;; aggregates.
|
||||||
|
|
||||||
(defstruct Pair [a i64 b i64])
|
(defstruct Pair [a i64 b i64])
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
;;;; The aggregate case across the reload boundary, v1 (HANDOFF-x86-redef.md,
|
;;;; The aggregate case across the reload boundary, v1 (docs/handoffs/HANDOFF-x86-redef.md,
|
||||||
;;;; item 4).
|
;;;; item 4).
|
||||||
;;;;
|
;;;;
|
||||||
;;;; `reload.flan' proves that a redefined body is reached; every signature in
|
;;;; `reload.flan' proves that a redefined body is reached; every signature in
|
||||||
|
|||||||
@ -1053,7 +1053,7 @@ let () =
|
|||||||
out of 54 is a fact about the Iroha that a lost byte anywhere in that
|
out of 54 is a fact about the Iroha that a lost byte anywhere in that
|
||||||
chain would change. The two walk rows are what stands in for
|
chain would change. The two walk rows are what stands in for
|
||||||
GetCodepointPrevious, which cannot be called from Flan at all — see
|
GetCodepointPrevious, which cannot be called from Flan at all — see
|
||||||
PORTING.md, and the file's own header for what each row fails on. *)
|
docs/PORTING.md, and the file's own header for what each row fails on. *)
|
||||||
let raylib_codepoints_out =
|
let raylib_codepoints_out =
|
||||||
"codepoints 54\n\
|
"codepoints 54\n\
|
||||||
unique 49\n\
|
unique 49\n\
|
||||||
@ -2799,7 +2799,7 @@ ERR@7 unexpected token: not the kind the caller was reading
|
|||||||
offset its own alignment allows, so the offset of field 1 in
|
offset its own alignment allows, so the offset of field 1 in
|
||||||
{ i8, T } *is* alignof(T). Reading [2 x i64] out of the emitted type and
|
{ i8, T } *is* alignof(T). Reading [2 x i64] out of the emitted type and
|
||||||
concluding 8 would be asserting the layout against itself, which is the
|
concluding 8 would be asserting the layout against itself, which is the
|
||||||
circularity BUILT.md already rejected for _Static_assert. *)
|
circularity docs/BUILT.md already rejected for _Static_assert. *)
|
||||||
let llvm_align ir sname =
|
let llvm_align ir sname =
|
||||||
let sty = Printf.sprintf "%%\"%s\"" sname in
|
let sty = Printf.sprintf "%%\"%s\"" sname in
|
||||||
let b = Buffer.create 512 in
|
let b = Buffer.create 512 in
|
||||||
|
|||||||
@ -1768,7 +1768,7 @@ let () =
|
|||||||
The redefinition binds a local, deliberately, because that is what
|
The redefinition binds a local, deliberately, because that is what
|
||||||
the detector can see. [Emit.slot_fingerprint] hashes a body's
|
the detector can see. [Emit.slot_fingerprint] hashes a body's
|
||||||
*slots*, so a new body with the same slots and different global
|
*slots*, so a new body with the same slots and different global
|
||||||
references is not caught — the hole is stated in BUILT.md, and a
|
references is not caught — the hole is stated in docs/BUILT.md, and a
|
||||||
test that asserted otherwise would be asserting a mechanism that is
|
test that asserted otherwise would be asserting a mechanism that is
|
||||||
not there. *)
|
not there. *)
|
||||||
let r =
|
let r =
|
||||||
@ -2421,7 +2421,7 @@ let () =
|
|||||||
|
|
||||||
(* ── Marking a form with (pause), from the editor's side ───────── *)
|
(* ── Marking a form with (pause), from the editor's side ───────── *)
|
||||||
|
|
||||||
(* DISCUSS.md §9: C-u before an evaluation marks a form so the program
|
(* docs/DISCUSS.md §9: C-u before an evaluation marks a form so the program
|
||||||
stops when it runs. The mark travels as a *position* beside the code
|
stops when it runs. The mark travels as a *position* beside the code
|
||||||
rather than spliced into it — splicing text would move every line and
|
rather than spliced into it — splicing text would move every line and
|
||||||
column after the insertion, and the error overlays, the break loop's
|
column after the insertion, and the error overlays, the break loop's
|
||||||
|
|||||||
@ -1632,7 +1632,7 @@ let () =
|
|||||||
(* The struct check, which is the point of reading a header the generator
|
(* The struct check, which is the point of reading a header the generator
|
||||||
does not otherwise need: the defstruct and the header's record have
|
does not otherwise need: the defstruct and the header's record have
|
||||||
different authors, so a disagreement is real information. A
|
different authors, so a disagreement is real information. A
|
||||||
_Static_assert was rejected in BUILT.md as circular for want of exactly
|
_Static_assert was rejected in docs/BUILT.md as circular for want of exactly
|
||||||
that. *)
|
that. *)
|
||||||
let structs_of ds =
|
let structs_of ds =
|
||||||
List.filter_map
|
List.filter_map
|
||||||
@ -1642,7 +1642,7 @@ let () =
|
|||||||
in
|
in
|
||||||
check "a defstruct that matches the header is not reported"
|
check "a defstruct that matches the header is not reported"
|
||||||
(Cimport.check_structs ~env ~structs:(structs_of fixture_ds) dump = []);
|
(Cimport.check_structs ~env ~structs:(structs_of fixture_ds) dump = []);
|
||||||
(* Permuted: the failure BUILT.md says only a test can catch, because every
|
(* Permuted: the failure docs/BUILT.md says only a test can catch, because every
|
||||||
field still reads as a plausible number. *)
|
field still reads as a plausible number. *)
|
||||||
check "a permuted defstruct is reported"
|
check "a permuted defstruct is reported"
|
||||||
(match
|
(match
|
||||||
@ -1651,7 +1651,7 @@ let () =
|
|||||||
with
|
with
|
||||||
| [ ("Pair", why) ] -> contains why "field order"
|
| [ ("Pair", why) ] -> contains why "field order"
|
||||||
| _ -> false);
|
| _ -> false);
|
||||||
(* Widened: the other half of the same hazard and the one BUILT.md names —
|
(* Widened: the other half of the same hazard and the one docs/BUILT.md names —
|
||||||
f64 where the library says float lays out eight bytes where there are
|
f64 where the library says float lays out eight bytes where there are
|
||||||
four, and every field after it moves. *)
|
four, and every field after it moves. *)
|
||||||
check "a widened field is reported"
|
check "a widened field is reported"
|
||||||
@ -1684,7 +1684,7 @@ let () =
|
|||||||
~structs:(structs_of (program "(defstruct Feel [mood i32 n i32])\n")) dump
|
~structs:(structs_of (program "(defstruct Feel [mood i32 n i32])\n")) dump
|
||||||
= []);
|
= []);
|
||||||
(* And the whole point of the check survives it. The tolerance is for a
|
(* And the whole point of the check survives it. The tolerance is for a
|
||||||
32-bit integer and nothing else, so the width hazard BUILT.md names — f64
|
32-bit integer and nothing else, so the width hazard docs/BUILT.md names — f64
|
||||||
where the library says float — still fails, in the very struct whose
|
where the library says float — still fails, in the very struct whose
|
||||||
other field is an enum. *)
|
other field is an enum. *)
|
||||||
check "a widened field beside an enum field is still reported"
|
check "a widened field beside an enum field is still reported"
|
||||||
|
|||||||
@ -201,7 +201,7 @@ let () =
|
|||||||
fail "reload\n got: %S (exit %d)\n wanted: %S" text code want;
|
fail "reload\n got: %S (exit %d)\n wanted: %S" text code want;
|
||||||
|
|
||||||
(* The same thing again, compiled by the dev backend end to end (x86.ml's
|
(* The same thing again, compiled by the dev backend end to end (x86.ml's
|
||||||
header, HANDOFF-x86-rt.md item 1). Both halves, host and module, because
|
header, docs/handoffs/HANDOFF-x86-rt.md item 1). Both halves, host and module, because
|
||||||
the two backends' conventions agree on every scalar and disagree on
|
the two backends' conventions agree on every scalar and disagree on
|
||||||
every aggregate: an LLVM-built module dlopened into an --x86 host would
|
every aggregate: an LLVM-built module dlopened into an --x86 host would
|
||||||
be correct until the first redefined function took or returned a struct.
|
be correct until the first redefined function took or returned a struct.
|
||||||
@ -213,7 +213,7 @@ let () =
|
|||||||
flan_dev_global lookups that needs are refused there by name.
|
flan_dev_global lookups that needs are refused there by name.
|
||||||
|
|
||||||
Read by running, not by reading. A disassembly reads correctly beside a
|
Read by running, not by reading. A disassembly reads correctly beside a
|
||||||
wrong answer often enough (DISCUSS.md item 15) that only the printed
|
wrong answer often enough (docs/DISCUSS.md item 15) that only the printed
|
||||||
transcript settles it: [outer] is compiled once into the host and never
|
transcript settles it: [outer] is compiled once into the host and never
|
||||||
rebuilt, so "after2 1204" can only mean its call site followed a body
|
rebuilt, so "after2 1204" can only mean its call site followed a body
|
||||||
that this backend emitted, published through a cell it reached via the
|
that this backend emitted, published through a cell it reached via the
|
||||||
@ -365,7 +365,7 @@ let () =
|
|||||||
segfaults with this guard in place, re-measured after it landed. The
|
segfaults with this guard in place, re-measured after it landed. The
|
||||||
guard catches a caller holding one option record; it cannot catch a
|
guard catches a caller holding one option record; it cannot catch a
|
||||||
caller holding two, and [flan reload] is exactly that caller. See
|
caller holding two, and [flan reload] is exactly that caller. See
|
||||||
HANDOFF-x86-aggregates.md. *)
|
docs/handoffs/HANDOFF-x86-aggregates.md. *)
|
||||||
(match Build.shared ~opts:x86 ~ir:"" ~out:(tmp "never.so") () with
|
(match Build.shared ~opts:x86 ~ir:"" ~out:(tmp "never.so") () with
|
||||||
| _ -> fail "Build.shared accepted an --x86 option record"
|
| _ -> fail "Build.shared accepted an --x86 option record"
|
||||||
| exception Failure m when has m "--x86" -> ()
|
| exception Failure m when has m "--x86" -> ()
|
||||||
|
|||||||
@ -13,7 +13,7 @@
|
|||||||
* settles it. Memcheck answers both, and needs no instrumentation whatever:
|
* settles it. Memcheck answers both, and needs no instrumentation whatever:
|
||||||
* it works on the binary, so hand-written IR, clang-compiled C and libc all
|
* it works on the binary, so hand-written IR, clang-compiled C and libc all
|
||||||
* arrive on the same footing. Nothing in [Emit] has to cooperate, which is
|
* arrive on the same footing. Nothing in [Emit] has to cooperate, which is
|
||||||
* the exact opposite of the sanitize_address attribute story in BUILT.md.
|
* the exact opposite of the sanitize_address attribute story in docs/BUILT.md.
|
||||||
*
|
*
|
||||||
* The two tools are not ordered, they are complementary, and the measurement
|
* The two tools are not ordered, they are complementary, and the measurement
|
||||||
* that shows it is bounds.flan: ASan catches three of its six deliberate
|
* that shows it is bounds.flan: ASan catches three of its six deliberate
|
||||||
|
|||||||
@ -181,7 +181,7 @@ let () =
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
(* ── raylib in the browser ────────────────────────────────────────
|
(* ── raylib in the browser ────────────────────────────────────────
|
||||||
The claim BUILT.md left open. core-basic-window.flan is built for the
|
The claim docs/BUILT.md left open. core-basic-window.flan is built for the
|
||||||
web unchanged — no edit to its `until` loop, which is the whole point
|
web unchanged — no edit to its `until` loop, which is the whole point
|
||||||
of choosing asyncify over emscripten_set_main_loop — and the module is
|
of choosing asyncify over emscripten_set_main_loop — and the module is
|
||||||
then read for the two things that prove the claim rather than assert
|
then read for the two things that prove the claim rather than assert
|
||||||
@ -237,7 +237,7 @@ let () =
|
|||||||
no DOM and no WebGL, so the module instantiates, main runs, and
|
no DOM and no WebGL, so the module instantiates, main runs, and
|
||||||
InitWindow dies inside glfwInit on `window is not defined` — which
|
InitWindow dies inside glfwInit on `window is not defined` — which
|
||||||
says the module is live but says nothing about whether the canvas
|
says the module is live but says nothing about whether the canvas
|
||||||
paints. Only a human opening it can say that; BUILT.md carries the
|
paints. Only a human opening it can say that; docs/BUILT.md carries the
|
||||||
commands. *)
|
commands. *)
|
||||||
let out = Filename.concat scratch "flan-web-sand.html" in
|
let out = Filename.concat scratch "flan-web-sand.html" in
|
||||||
(match web_build "../sand.flan" out with
|
(match web_build "../sand.flan" out with
|
||||||
|
|||||||
@ -16,7 +16,7 @@
|
|||||||
# malloc(cap), so every byte in it — handed out, padding, or still past
|
# malloc(cap), so every byte in it — handed out, padding, or still past
|
||||||
# the offset — is one allocation to memcheck. It never learns that a
|
# the offset — is one allocation to memcheck. It never learns that a
|
||||||
# sub-object ended, so it has nothing to complain about and equally
|
# sub-object ended, so it has nothing to complain about and equally
|
||||||
# nothing to catch. Recorded as a coverage ceiling in BUILT.md, not as a
|
# nothing to catch. Recorded as a coverage ceiling in docs/BUILT.md, not as a
|
||||||
# clean bill of health.
|
# clean bill of health.
|
||||||
#
|
#
|
||||||
# What *is* caught is definedness rather than addressability, and that
|
# What *is* caught is definedness rather than addressability, and that
|
||||||
|
|||||||
2
vendor/raylib/bindings
vendored
2
vendor/raylib/bindings
vendored
@ -67,7 +67,7 @@ name IsAudioStreamProcessed audio-stream-processed?
|
|||||||
|
|
||||||
# Hand-written in raylib.flan, so excluded here: a second declare-c for one C
|
# Hand-written in raylib.flan, so excluded here: a second declare-c for one C
|
||||||
# symbol is refused for the whole program. These three are on a game's
|
# symbol is refused for the whole program. These three are on a game's
|
||||||
# per-frame path (PORTING.md), and a hand-written line is what the signature
|
# per-frame path (docs/PORTING.md), and a hand-written line is what the signature
|
||||||
# check has to compare against -- generated output agrees with the header by
|
# check has to compare against -- generated output agrees with the header by
|
||||||
# construction, so it can only check the hand-written half.
|
# construction, so it can only check the hand-written half.
|
||||||
exclude DrawTexturePro
|
exclude DrawTexturePro
|
||||||
|
|||||||
4
vendor/raylib/build-web.sh
vendored
4
vendor/raylib/build-web.sh
vendored
@ -12,7 +12,7 @@
|
|||||||
#
|
#
|
||||||
# The output is a plain static archive plus nothing else: no headers are
|
# The output is a plain static archive plus nothing else: no headers are
|
||||||
# installed, because the generated FFI shim declares the prototypes it uses
|
# installed, because the generated FFI shim declares the prototypes it uses
|
||||||
# (see BUILT.md, "No raylib headers are needed").
|
# (see docs/BUILT.md, "No raylib headers are needed").
|
||||||
#
|
#
|
||||||
# sh vendor/raylib/build-web.sh
|
# sh vendor/raylib/build-web.sh
|
||||||
#
|
#
|
||||||
@ -54,7 +54,7 @@ else
|
|||||||
|
|
||||||
# GRAPHICS_API_OPENGL_ES2 is what WebGL is. PLATFORM_WEB makes rcore.c
|
# GRAPHICS_API_OPENGL_ES2 is what WebGL is. PLATFORM_WEB makes rcore.c
|
||||||
# include platforms/rcore_web.c, whose WindowShouldClose() is an
|
# include platforms/rcore_web.c, whose WindowShouldClose() is an
|
||||||
# emscripten_sleep that returns false — see BUILT.md on why that is the whole
|
# emscripten_sleep that returns false — see docs/BUILT.md on why that is the whole
|
||||||
# reason a Flan `until` loop needs no rewriting for the browser.
|
# reason a Flan `until` loop needs no rewriting for the browser.
|
||||||
#
|
#
|
||||||
# rglfw.c is not in the list: the web platform uses emscripten's own GLFW
|
# rglfw.c is not in the list: the web platform uses emscripten's own GLFW
|
||||||
|
|||||||
2
vendor/raylib/modes.flan
vendored
2
vendor/raylib/modes.flan
vendored
@ -39,7 +39,7 @@
|
|||||||
;;;;
|
;;;;
|
||||||
;;;; The obvious fix is `defer`, and it is not available here. `defer` is a
|
;;;; The obvious fix is `defer`, and it is not available here. `defer` is a
|
||||||
;;;; compile-time construct — the forms are copied into the function's exit
|
;;;; compile-time construct — the forms are copied into the function's exit
|
||||||
;;;; paths — so BUILT.md refuses it inside a loop or a branch, and a
|
;;;; paths — so docs/BUILT.md refuses it inside a loop or a branch, and a
|
||||||
;;;; begin/end pair lives inside the game loop essentially always. Were it
|
;;;; begin/end pair lives inside the game loop essentially always. Were it
|
||||||
;;;; permitted there it would be wrong in the worse direction: one EndDrawing
|
;;;; permitted there it would be wrong in the worse direction: one EndDrawing
|
||||||
;;;; at function exit for N BeginDrawings. A macro expanding to a defer would
|
;;;; at function exit for N BeginDrawings. A macro expanding to a defer would
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user