Merge branch 'master' into worktree-agent-acca0e216df6ca366
This commit is contained in:
commit
22401a6521
143
CLAUDE.md
143
CLAUDE.md
@ -1,125 +1,54 @@
|
|||||||
# Working in this repository
|
# Working in this repository
|
||||||
|
|
||||||
For any agent working here, including a lane in its own worktree. These are
|
Standing rules for any agent here, including a lane in its own worktree.
|
||||||
standing rules, not preferences. Where a rule has a reason, the reason is given
|
|
||||||
once — the rules without one are the ones that have already cost something.
|
|
||||||
|
|
||||||
## Never
|
## Never
|
||||||
|
|
||||||
- **Never touch anything under `/home/joe/Development/fnm/`.** That is the
|
- **Touch anything under `/home/joe/Development/fnm/`.** The author's live
|
||||||
author's own working copy of the falling-sand game, open in an editor with a
|
working copy, with an editor session attached. This repository's `sand.flan`
|
||||||
live session attached. `fnm/flan/sand.flan` is not the same file as this
|
is a different file and may be edited normally.
|
||||||
repository's `sand.flan` and is never to be read-and-written-back, moved or
|
- **Execute `examples/*.flan`, `sand.flan`, or anything linking raylib.** They
|
||||||
edited. The copy in this repository is ordinary tracked source and may be
|
open a window that strobes the author's desktop. Compile, emit, diff — never run.
|
||||||
edited like any other file.
|
- **Run `dune clean`.** It escapes a worktree and deletes the main checkout's
|
||||||
- **Never execute `examples/*.flan`, `sand.flan`, or anything that links
|
`_build`. Run `dune` with `--root .` from inside your own worktree.
|
||||||
raylib.** They open a window on the author's desktop, which strobes it.
|
- **Kill a `flan dev` daemon you did not start.** The author keeps one attached
|
||||||
Compile them, emit them, diff them — never run them.
|
to their editor.
|
||||||
- **Never run `dune clean`.** It walks up out of a worktree and deletes the main
|
- **Put `Co-Authored-By`, a `Claude-Session` trailer or any watermark in a commit.**
|
||||||
checkout's `_build`, which takes the author's `flan` binary with it. This has
|
|
||||||
happened. Run `dune` with `--root .` from inside your own worktree.
|
|
||||||
- **Never kill a `flan dev` daemon you did not start.** The author keeps a live
|
|
||||||
one attached to their editor all day. Orphans from finished lanes are fair
|
|
||||||
game; anything whose cwd is under `fnm/` is not.
|
|
||||||
- **Never put a `Co-Authored-By`, a `Claude-Session` trailer, or any other
|
|
||||||
watermark in a commit message.**
|
|
||||||
|
|
||||||
## Commits and branches
|
## Commits
|
||||||
|
|
||||||
`master` is the trunk and tracks `origin/master`. Lanes work in their own git
|
`master` is the trunk. Lanes work in their own worktree and never merge or push;
|
||||||
worktree off it and do not merge or push — merges are resolved by the session
|
the dispatching session merges. A commit message is one declarative sentence
|
||||||
that dispatched the lane.
|
saying what is now true, not what was done.
|
||||||
|
|
||||||
A commit message is a single declarative sentence in the repository's voice,
|
|
||||||
saying what is now true rather than what was done: "A thunk named for the order
|
|
||||||
it was minted in is a different signature after a reorder", not "fix thunk
|
|
||||||
naming bug". A body is for the reasoning, when there is any.
|
|
||||||
|
|
||||||
## Tests
|
## Tests
|
||||||
|
|
||||||
`dune test --root .` is the suite and takes seconds. Run it constantly; it must
|
`dune test --root .` must be green before a lane reports; grep its output for
|
||||||
be green before a lane reports.
|
FAIL, since the exit code alone has lied. `@checks` (`@page`, `@x86`, `@cells`),
|
||||||
|
`@sanitize` and `@valgrind` are slow and run once between batches of lanes, with
|
||||||
`dune build @checks` is `@page`, `@x86` and `@cells` — the reference page's
|
the author's permission, never inside a lane. ASan misses uninitialised stack
|
||||||
examples still compile and print what the page says, the hand-written x86
|
reads; `@valgrind` catches them.
|
||||||
backend still agrees with LLVM, and a `--dev` build still calls through its
|
|
||||||
indirection cells. `@sanitize` and `@valgrind` run the corpus under ASan/UBSan
|
|
||||||
and memcheck and take tens of minutes.
|
|
||||||
|
|
||||||
Those three stay out of a lane's own run. They are swept in a batch after
|
|
||||||
several lanes have merged, and the fixes are batched with them. Keeping the
|
|
||||||
default run fast is deliberate: a suite that takes tens of minutes is a suite
|
|
||||||
nobody runs.
|
|
||||||
|
|
||||||
Note that ASan does not see a stack-lifetime bug — uninitialised stack reads
|
|
||||||
need `@valgrind`.
|
|
||||||
|
|
||||||
## Evidence
|
## Evidence
|
||||||
|
|
||||||
Read the source, do not recall it. `docs/REFERENCES.md` lists the reference
|
Read the source, do not recall it — this repository and the reference clones
|
||||||
clones on this machine — Odin, SBCL, Zig, Carp, clojure-mode, CIDER, raylib and
|
listed in `docs/REFERENCES.md`. Verify a brief's facts before building on them.
|
||||||
the rest — and what each one answers. A claim in these notes that came from one
|
|
||||||
of them was read out of the clone; the ones that were recalled instead have been
|
|
||||||
wrong before.
|
|
||||||
|
|
||||||
The same applies to this repository. Cite a file and a line because you opened
|
## Records
|
||||||
it. When a brief hands you a list of facts, verify them before building on them
|
|
||||||
— a brief written from a stale tree has sent a lane a full day in the wrong
|
|
||||||
direction.
|
|
||||||
|
|
||||||
## Diagnostics
|
Keep only what the code cannot say.
|
||||||
|
|
||||||
Elm's shape: the source line, a caret, what the compiler understood, and the fix
|
- `TODO.org` — one `**` heading per item under a subsystem: `TODO` a gap, `NEXT`
|
||||||
named. Beyond that:
|
decided and queued, `WAIT` blocked (say on what), `CANCELLED` rejected with a
|
||||||
|
one-line reason so it is not re-proposed, `DONE` only when the decision is not
|
||||||
|
obvious from the code (two lines, what it rules out). On a merge conflict keep
|
||||||
|
both sides.
|
||||||
|
- The reason for non-obvious code goes in a comment beside it.
|
||||||
|
- `docs/BUILT.md` holds only reasoning that spans several files.
|
||||||
|
- No handoff files.
|
||||||
|
|
||||||
- A message is written for someone who has never used Flan and does not know its
|
## Reviews
|
||||||
history. Never "X is now Y", never "X was renamed", never our rationale. If
|
|
||||||
`defvar` no longer exists, the message says `defvar` does not exist — not that
|
|
||||||
it became something else.
|
|
||||||
- The clauses come in one order: what the compiler understood, then what
|
|
||||||
conflicts with it, then the fix — "expected i32, found string".
|
|
||||||
- Every suggestion a message prints must compile.
|
|
||||||
- An assertion about the compiler's own invariants is prefixed `internal:` and
|
|
||||||
says it is a compiler bug. A user never caused one.
|
|
||||||
|
|
||||||
## Writing
|
Every lane gets an independent adversarial review before it merges: build and
|
||||||
|
run rather than read, measure both sides of a claimed fix, and reproduce any
|
||||||
User-facing prose — the README, `web/index.html`, the Emacs manual — is plain.
|
number a lane reports.
|
||||||
Odin's website is the reference: declarative rather than second-person, the
|
|
||||||
concept defined before the mechanics, the code example after the prose that
|
|
||||||
frames it, and rationale given its own subsection rather than mixed in.
|
|
||||||
|
|
||||||
No aphorisms, no closing lines built for effect, no rhetorical inversions. If a
|
|
||||||
sentence's only content is its own style, cut it. This applies to reports and
|
|
||||||
commit messages as much as to documentation.
|
|
||||||
|
|
||||||
## The records
|
|
||||||
|
|
||||||
- `TODO.org` — every decision, question and known gap, one `**` heading each
|
|
||||||
under a subsystem heading, with an org keyword saying where it stands: `TODO`
|
|
||||||
for a gap, `NEXT` for what is queued, `WAIT` for what is blocked and on what,
|
|
||||||
`DONE` for what was settled, `CANCELLED` for an idea considered and rejected.
|
|
||||||
A lane records its decision here, as a few lines saying what was decided and
|
|
||||||
what it rules out — never the argument and never the measurements. On a merge
|
|
||||||
conflict in this file, keep both sides: two lanes recording two decisions is
|
|
||||||
not a conflict.
|
|
||||||
- `docs/BUILT.md` — why the parts that exist are shaped the way they are. The
|
|
||||||
largest and most load-bearing document here. Reasoning that will not fit in a
|
|
||||||
few lines goes here, and `TODO.org` carries one line pointing at it.
|
|
||||||
- `docs/handoffs/` — one report per finished work session.
|
|
||||||
- `docs/README.md` indexes all of it.
|
|
||||||
|
|
||||||
A `CANCELLED` entry is not housekeeping. An idea rejected without a record is an
|
|
||||||
idea that gets re-proposed, so the one-line reason is the whole value of it.
|
|
||||||
|
|
||||||
## The shape of the work
|
|
||||||
|
|
||||||
The author dogfoods the language in a separate project, hits friction, and
|
|
||||||
reports it. Work is dispatched as parallel lanes in isolated worktrees; every
|
|
||||||
lane is reviewed by an independent agent before it merges; the dispatching
|
|
||||||
session resolves the merges.
|
|
||||||
|
|
||||||
A review is adversarial. Verify by building and running rather than by reading,
|
|
||||||
measure both sides of a claimed fix, and say what you actually measured. A lane
|
|
||||||
that reports a number you did not reproduce is a lane with a number you should
|
|
||||||
reproduce.
|
|
||||||
|
|||||||
91
TODO.org
91
TODO.org
@ -501,7 +501,8 @@ capturing value. Two things for it to know: a widening thunk's environment holds
|
|||||||
code pointer rather than a GC object, and capturing a dyn stays refused until a
|
code pointer rather than a GC object, and capturing a dyn stays refused until a
|
||||||
synthesised environment has a descriptor.
|
synthesised environment has a descriptor.
|
||||||
|
|
||||||
** TODO CFn and C's calling convention
|
** WAIT CFn and C's calling convention
|
||||||
|
Decided 2026-09-25: waits with C callbacks, until a program needs one.
|
||||||
A Flan function's signature ends with the transfer channel and a C caller knows
|
A Flan function's signature ends with the transfer channel and a C caller knows
|
||||||
nothing about one, so a =CFn= is not a C callback today. Under a future
|
nothing about one, so a =CFn= is not a C callback today. Under a future
|
||||||
=--no-conditions= flag a =CFn= signature could drop the channel and reach C's
|
=--no-conditions= flag a =CFn= signature could drop the channel and reach C's
|
||||||
@ -524,7 +525,8 @@ dispatch values. With single dispatch on literal values there is no specificity
|
|||||||
question, and inheritance or multiple dispatch would create one. Unknown-slot
|
question, and inheritance or multiple dispatch would create one. Unknown-slot
|
||||||
checking needs class-typed tracking the dyn side deliberately does not have.
|
checking needs class-typed tracking the dyn side deliberately does not have.
|
||||||
|
|
||||||
** TODO update-instance-for-redefined-class, the user hook
|
** NEXT update-instance-for-redefined-class, the user hook
|
||||||
|
Decided 2026-09-25: build it after typed class slots land, shaped for the REPL — written and installed from a live session as a one-time "here is how to migrate this", without restarting. It receives the instance with the added and discarded slots and their old values, and runs at each instance's lazy migration. A hook that signals parks in the break buffer with a restart that falls back to name-matching migration.
|
||||||
Left out of v1 because name matching is the half that makes redefinition usable
|
Left out of v1 because name matching is the half that makes redefinition usable
|
||||||
and the hook is what makes it expressive. The obvious spelling is a generic riding
|
and the hook is what makes it expressive. The obvious spelling is a generic riding
|
||||||
the dispatch that exists, and the migration already computes both the added and
|
the dispatch that exists, and the migration already computes both the added and
|
||||||
@ -736,10 +738,12 @@ call site that asked for that type. The data is there — =instantiation_origin=
|
|||||||
exists and the session already uses it — and wiring it into every failure under an
|
exists and the session already uses it — and wiring it into every failure under an
|
||||||
instantiation is a lane of its own.
|
instantiation is a lane of its own.
|
||||||
|
|
||||||
** TODO Generics across a real compilation-unit boundary
|
** DONE A program is one compilation, so a generic's body is always visible
|
||||||
It works today because =Load= flattens imports before checking. A package boundary
|
CLOSED: [2026-09-25]
|
||||||
that ever becomes a real unit boundary needs the generic's body to cross it, which
|
Odin's and Zig's model: packages are never compiled separately. The cost is build
|
||||||
separate compilation cannot do — which is why C++ puts templates in headers.
|
time proportional to the whole program and no binary-only packages. If separate
|
||||||
|
compilation is ever wanted, Rust's answer is the one to take — a compiled package
|
||||||
|
carries its generics' checked bodies and the user instantiates them.
|
||||||
|
|
||||||
** DONE Collapsing the prelude buys 27 to 15, not 27 to 6
|
** DONE Collapsing the prelude buys 27 to 15, not 27 to 6
|
||||||
CLOSED: [2026-09-13]
|
CLOSED: [2026-09-13]
|
||||||
@ -824,7 +828,8 @@ the losing side meets the strict =bool= boundary and traps —
|
|||||||
=(or false (box "s"))= is the case. Whether a =bool= arm and a =dyn= arm should
|
=(or false (box "s"))= is the case. Whether a =bool= arm and a =dyn= arm should
|
||||||
join as =dyn= is the author's call and is not settled.
|
join as =dyn= is the author's call and is not settled.
|
||||||
|
|
||||||
** TODO A truthiness failure re-runs the whole failing subtree
|
** NEXT A truthiness failure re-runs the whole failing subtree
|
||||||
|
Decided 2026-09-25: fix it without changing any message — the retry reuses what the first pass settled for each subtree (memoised by node), so nested =not= is linear. Test with a deep nest that must fail fast and with the existing message tests unchanged.
|
||||||
The retry exists to keep a refused literal's message unchanged and re-runs the
|
The retry exists to keep a refused literal's message unchanged and re-runs the
|
||||||
subtree rather than the leaf, which is exponential in nested =not= depth on a
|
subtree rather than the leaf, which is exponential in nested =not= depth on a
|
||||||
program that does not type-check. Moot for anything that compiles; only the
|
program that does not type-check. Moot for anything that compiles; only the
|
||||||
@ -864,7 +869,8 @@ correct code, so any per-push flag is a false positive by the language's own
|
|||||||
semantics; the refined version needs liveness across control flow, which is the
|
semantics; the refined version needs liveness across control flow, which is the
|
||||||
flow tracking that was repealed.
|
flow tracking that was repealed.
|
||||||
|
|
||||||
** TODO Catching a use-after-release statically
|
** NEXT Catching a use-after-release statically
|
||||||
|
Decided 2026-09-25: a study, not a build — how arena memory escapes in real Flan code, and whether a sound lexical check would catch most of it. The result goes in docs/BUILT.md; nothing is built on it without the author.
|
||||||
Open, and for the first time with evidence available: the epoch trap is built, and
|
Open, and for the first time with evidence available: the epoch trap is built, and
|
||||||
there is a =Vec= to write real arena programs with, so whether the escapes that
|
there is a =Vec= to write real arena programs with, so whether the escapes that
|
||||||
actually occur are lexical can now be answered. The next thing to look at, not the
|
actually occur are lexical can now be answered. The next thing to look at, not the
|
||||||
@ -1051,7 +1057,8 @@ Every program in the corpus that compiles, has a =main= and terminates agrees wi
|
|||||||
the LLVM build down to stderr. =docs/BUILT.md=, "The hand-written x86 backend, and
|
the LLVM build down to stderr. =docs/BUILT.md=, "The hand-written x86 backend, and
|
||||||
the four measurements behind it", is the account.
|
the four measurements behind it", is the account.
|
||||||
|
|
||||||
** TODO Nothing pins the LLVM side at -O0 when the two backends are compared
|
** NEXT Nothing pins the LLVM side at -O0 when the two backends are compared
|
||||||
|
Decided 2026-09-25: the x86 parity survey compares against LLVM at -O0 only; -O2 is never its target. The acceptance suite's paired -O2/-O0 rows stay, being the check for undefined behaviour in emitted IR, which is a different question.
|
||||||
The survey builds both sides at the default =-O2=, so a construct LLVM folds is
|
The survey builds both sides at the default =-O2=, so a construct LLVM folds is
|
||||||
compared as a constant rather than as a lowering. That is how the float =%= gap
|
compared as a constant rather than as a lowering. That is how the float =%= gap
|
||||||
survived. Two things would close it: an =-O0= pass of the sweep, and something
|
survived. Two things would close it: an =-O0= pass of the sweep, and something
|
||||||
@ -1116,7 +1123,8 @@ The module links and runs. What is not proved is a collection running while a li
|
|||||||
instance of a dyn-holding struct sits in a frame of a body that module delivered.
|
instance of a dyn-holding struct sits in a frame of a body that module delivered.
|
||||||
For the next sweep rather than for a lane.
|
For the next sweep rather than for a lane.
|
||||||
|
|
||||||
** TODO A sliced string loses the trailing NUL
|
** NEXT A sliced string loses the trailing NUL
|
||||||
|
Decided 2026-09-25: both backends emit a NUL after every string literal, and a declare-c wrapper passes a literal argument to C without the copy it makes for any other string. A string is still pointer and length; no slice is promised a NUL. Rules out a NUL guarantee on every string.
|
||||||
The x86 backend emits a NUL after every string constant and the LLVM one does not,
|
The x86 backend emits a NUL after every string constant and the LLVM one does not,
|
||||||
so a =declare-c= wrapper leaning on the courtesy is already backend-dependent as
|
so a =declare-c= wrapper leaning on the courtesy is already backend-dependent as
|
||||||
well as slice-dependent. The contract is pointer and length, and nothing promised
|
well as slice-dependent. The contract is pointer and length, and nothing promised
|
||||||
@ -1127,7 +1135,8 @@ Decided 2026-09-25: emit the x86 backend's =.cfi= directives in every build. No
|
|||||||
They are correct in every build and free at runtime, and a release build is where
|
They are correct in every build and free at runtime, and a release build is where
|
||||||
a crash would most want them. One =if= in three places.
|
a crash would most want them. One =if= in three places.
|
||||||
|
|
||||||
** TODO A !DILexicalBlock per Let
|
** WAIT A !DILexicalBlock per Let
|
||||||
|
Decided 2026-09-25: waits until Flan is debugged in gdb or lldb; the break buffer, which reads the shadow stack, already answers correctly.
|
||||||
Inside nested =let=s that bind the same name, a debugger still answers with the
|
Inside nested =let=s that bind the same name, a debugger still answers with the
|
||||||
outer one. The disambiguating suffix makes both visible, which is not the same as
|
outer one. The disambiguating suffix makes both visible, which is not the same as
|
||||||
making the answer right. It needs block structure the typed IR does not carry, and
|
making the answer right. It needs block structure the typed IR does not carry, and
|
||||||
@ -1241,7 +1250,8 @@ build, because a layout that changes with a build flag can disagree silently
|
|||||||
across the reload boundary. One addition: a budget, because =retry= needs a
|
across the reload boundary. One addition: a budget, because =retry= needs a
|
||||||
handler that can make the same request succeed.
|
handler that can make the same request succeed.
|
||||||
|
|
||||||
** TODO The Vec generation word has no reader
|
** NEXT The Vec generation word has no reader
|
||||||
|
Decided 2026-09-25: remove the word, and in a dev build fill a Vec's old buffer with the dead-beef pattern when a push moves it, so a stale slice reads visibly wrong values. No slice layout change; a release build is untouched. Rules out a dev-only word on every slice.
|
||||||
It is bumped on reallocation and read by nothing. The stale-slice trap it exists
|
It is bumped on reallocation and read by nothing. The stale-slice trap it exists
|
||||||
for needs a slice that can carry the Vec's identity, and a slice is pointer and
|
for needs a slice that can carry the Vec's identity, and a slice is pointer and
|
||||||
length — so either slices grow a word in a dev build or the trap does not exist.
|
length — so either slices grow a word in a dev build or the trap does not exist.
|
||||||
@ -1254,7 +1264,8 @@ live bytes, 0 for none, that a =retry= handler raises. The failure bullet says
|
|||||||
"raises the allocator's budget" where it said "grows the arena", since no arena
|
"raises the allocator's budget" where it said "grows the arena", since no arena
|
||||||
grows. A growable arena is not ruled out; nothing here asks for one.
|
grows. A growable arena is not ruled out; nothing here asks for one.
|
||||||
|
|
||||||
** TODO The Vec header is not the size the spec fixes
|
** NEXT The Vec header is not the size the spec fixes
|
||||||
|
Decided 2026-09-25: five words in every build, the epoch included, so a release build still traps on a container whose region was released. The spec changes to match the code; nothing else does.
|
||||||
Five words in every build rather than the spec's four, and for a stated reason: a
|
Five words in every build rather than the spec's four, and for a stated reason: a
|
||||||
redefinition module is built separately from its host and nothing makes the two
|
redefinition module is built separately from its host and nothing makes the two
|
||||||
agree on a struct size. Give the reload path a way to carry the build flags and
|
agree on a struct size. Give the reload path a way to carry the build flags and
|
||||||
@ -1321,7 +1332,8 @@ until something touches it. The registry is advisory: a key the class never
|
|||||||
declared is dropped by the next migration, which is data loss with no enforcement
|
declared is dropped by the next migration, which is data loss with no enforcement
|
||||||
behind it.
|
behind it.
|
||||||
|
|
||||||
** TODO A class registry keeps one slot list per class, not one per layout version
|
** WAIT A class registry keeps one slot list per class, not one per layout version
|
||||||
|
Decided 2026-09-25: waits for a case name-matching migration to the current list gets wrong.
|
||||||
"A redefined class's old instances stay resolvable" needs every version's metadata
|
"A redefined class's old instances stay resolvable" needs every version's metadata
|
||||||
retained for as long as any instance holds it, the way nothing is ever
|
retained for as long as any instance holds it, the way nothing is ever
|
||||||
=dlclose=d. What exists is one current slot list and one generation per class, and
|
=dlclose=d. What exists is one current slot list and one generation per class, and
|
||||||
@ -1399,7 +1411,8 @@ through a pointer into it is answerable; memcheck is told the same fact, so the
|
|||||||
same read is reported. The two stay two claims — different tools reaching
|
same read is reported. The two stay two claims — different tools reaching
|
||||||
different people.
|
different people.
|
||||||
|
|
||||||
** TODO The leak question across the corpus
|
** NEXT The leak question across the corpus
|
||||||
|
Decided 2026-09-25: one pass over the whole corpus with LeakSanitizer and memcheck's leak check on. Memory an allocator holds by design is set aside; memory nothing owns is a leak and is fixed. The sweeps' default stays leak-checking off.
|
||||||
Both sweeps run with leak checking off, because allocate-once-never-free is this
|
Both sweeps run with leak checking off, because allocate-once-never-free is this
|
||||||
runtime's design and a leak check produces a suppression list. A green sweep
|
runtime's design and a leak check produces a suppression list. A green sweep
|
||||||
therefore says nothing about who frees the newly allocating =(bytes s)=. Worth
|
therefore says nothing about who frees the newly allocating =(bytes s)=. Worth
|
||||||
@ -1499,7 +1512,8 @@ A finished program parks instead of dying, and a daemon op wakes it and re-enter
|
|||||||
Globals are not reset between runs — the process never died. Rules out a fresh
|
Globals are not reset between runs — the process never died. Rules out a fresh
|
||||||
process per run.
|
process per run.
|
||||||
|
|
||||||
** TODO Re-run does not work under --two-process
|
** NEXT Re-run does not work under --two-process
|
||||||
|
Decided 2026-09-25: re-run under =--two-process= starts a fresh child, installed redefinitions included, and says that globals start over because the process is new.
|
||||||
A finished child process is genuinely gone, so there is nothing to wake. Re-run is
|
A finished child process is genuinely gone, so there is nothing to wake. Re-run is
|
||||||
merged-build only, and since the default backend runs merged it is no longer the
|
merged-build only, and since the default backend runs merged it is no longer the
|
||||||
blocked case.
|
blocked case.
|
||||||
@ -1539,7 +1553,8 @@ was delivered" is a generation number rather than a name, so evaluating from
|
|||||||
inside a break into a thunk that stops on the same condition class is settled by
|
inside a break into a thunk that stops on the same condition class is settled by
|
||||||
comparing two integers.
|
comparing two integers.
|
||||||
|
|
||||||
** TODO Whose break it is, which no counter answers
|
** NEXT Whose break it is, which no counter answers
|
||||||
|
Decided 2026-09-25: fix it. A stop records whether the thread that stopped was running the evaluation's thunk or the program's own code, so the sentence is decided by the frame and not by the generation counter.
|
||||||
A game loop that signals during the build or the wait bumps the generation exactly
|
A game loop that signals during the build or the wait bumps the generation exactly
|
||||||
as a thunk would. The machine-readable fields stay right; what is wrong is the
|
as a thunk would. The machine-readable fields stay right; what is wrong is the
|
||||||
sentence. The per-frame program-or-eval label is computed by the daemon from
|
sentence. The per-frame program-or-eval label is computed by the daemon from
|
||||||
@ -1592,7 +1607,8 @@ that polls or waits. Full invisibility — a dev build linking the agent whether
|
|||||||
not the source says so — needs the package force-linked and is a decision about
|
not the source says so — needs the package force-linked and is a decision about
|
||||||
what =--dev= means.
|
what =--dev= means.
|
||||||
|
|
||||||
** TODO FLAN_AGENT_SOCKET in a shell's environment steals the socket
|
** NEXT FLAN_AGENT_SOCKET in a shell's environment steals the socket
|
||||||
|
Decided 2026-09-25: narrow the gate. The daemon also exports its own pid, and the constructor binds the socket only when that pid is the program's parent (or the program itself, in a merged build).
|
||||||
Binding unlinks the path first, and before the constructor that unlink was reached
|
Binding unlinks the path first, and before the constructor that unlink was reached
|
||||||
only by an explicit call. A sentence about the shape of the gate rather than an
|
only by an explicit call. A sentence about the shape of the gate rather than an
|
||||||
observed problem: only the daemon sets the variable and it never runs release
|
observed problem: only the daemon sets the variable and it never runs release
|
||||||
@ -1656,7 +1672,8 @@ on the frame, the restart listing carrying the signature, and the daemon compili
|
|||||||
each argument against the declared type and writing the values into the frame's
|
each argument against the declared type and writing the values into the frame's
|
||||||
buffer before aiming the channel.
|
buffer before aiming the channel.
|
||||||
|
|
||||||
** TODO The type identity of a local is not qualified
|
** NEXT The type identity of a local is not qualified
|
||||||
|
Decided 2026-09-25: a local's type prints package-qualified in the break buffer and the inspector, as a field's and a condition's already do.
|
||||||
Settled for conditions and for structs, because =Load= qualifies every declaration
|
Settled for conditions and for structs, because =Load= qualifies every declaration
|
||||||
at import. Still open for locals, where the debug information gives a bare name and
|
at import. Still open for locals, where the debug information gives a bare name and
|
||||||
nothing qualifies it.
|
nothing qualifies it.
|
||||||
@ -1748,7 +1765,8 @@ nothing orders the two. The read raised on a closed socket and the test binary
|
|||||||
exited 1 with no failure line, which is the worst shape a failure can have when
|
exited 1 with no failure line, which is the worst shape a failure can have when
|
||||||
a lane is judged on the exit status.
|
a lane is judged on the exit status.
|
||||||
|
|
||||||
** TODO A program driven by a real flan dev daemon under a sanitizer
|
** NEXT A program driven by a real flan dev daemon under a sanitizer
|
||||||
|
Decided 2026-09-25: =flan dev --sanitize= builds the host under ASan/UBSan on the LLVM backend (refused by name with =--x86=), and the @sanitize alias gains a case driving a real session through reloads and a break.
|
||||||
The daemon builds its host through its own path and the CLI has no way to pass a
|
The daemon builds its host through its own path and the CLI has no way to pass a
|
||||||
sanitizer flag to it. Named as the check worth adding next; a day rather than an
|
sanitizer flag to it. Named as the check worth adding next; a day rather than an
|
||||||
hour. The x86 backend is not a gap here — that pair is refused by name, because
|
hour. The x86 backend is not a gap here — that pair is refused by name, because
|
||||||
@ -1835,10 +1853,15 @@ pass. Deriving from clojure-mode at runtime stays rejected: it would add an
|
|||||||
external dependency to a mode that ships in this repository and needs nothing
|
external dependency to a mode that ships in this repository and needs nothing
|
||||||
beyond stock Emacs, and that community is mid-transition to a tree-sitter mode.
|
beyond stock Emacs, and that community is mid-transition to a tree-sitter mode.
|
||||||
|
|
||||||
** TODO 373 lines in 20 files still reindent differently
|
** DONE Every tracked .flan file reindents to itself
|
||||||
Concentrated in four files, untouched by the Emacs pass and untouched before it.
|
CLOSED: [2026-09-25]
|
||||||
The indenter and the hand-formatting there disagree about shapes nothing has
|
clojure-mode decided each shape. The indenter was wrong on one: a =with-= head,
|
||||||
looked at.
|
and a qualified =def…= or =with-= head, now indents as a body, and a qualified
|
||||||
|
name finds its unqualified part's spec. The rest was hand formatting and was
|
||||||
|
reindented: a =cond= or =match= result on its own line sits under its test, and
|
||||||
|
an ordinary call's later arguments align under its first. A lone =;= comment
|
||||||
|
line goes to =comment-column= in every Lisp mode, so continuation comments are
|
||||||
|
written as =;;= lines above the code instead.
|
||||||
|
|
||||||
** DONE C-c C-i inspects the expression at point
|
** DONE C-c C-i inspects the expression at point
|
||||||
No prompt, because the expression is already written in the buffer. =C-u= opens
|
No prompt, because the expression is already written in the buffer. =C-u= opens
|
||||||
@ -1962,6 +1985,12 @@ motion states in that mode; every other key, including what =special-mode-map=
|
|||||||
binds, stays Evil's. The other special-mode buffers (inspect, watch, doc, disassembly,
|
binds, stays Evil's. The other special-mode buffers (inspect, watch, doc, disassembly,
|
||||||
diagnostics, lower) have the same exposure and are not changed.
|
diagnostics, lower) have the same exposure and are not changed.
|
||||||
|
|
||||||
|
** NEXT C-x C-e in a package's file resolves names in that package
|
||||||
|
Decided 2026-09-25: CIDER's rule — an evaluation sent from a file resolves names
|
||||||
|
as code written in that file would, so =(integrate 1.0)= in =physics/step.flan=
|
||||||
|
reaches the package's own functions, =defn-= included. Today it answers
|
||||||
|
"unknown function", resolving as the program's main file.
|
||||||
|
|
||||||
** NEXT Evil takes the keys in the other Flan buffers
|
** NEXT Evil takes the keys in the other Flan buffers
|
||||||
The inspect, watch, doc, disassembly, diagnostics and lower buffers get the break
|
The inspect, watch, doc, disassembly, diagnostics and lower buffers get the break
|
||||||
buffer's treatment: the keys each binds itself go to Evil's normal and motion
|
buffer's treatment: the keys each binds itself go to Evil's normal and motion
|
||||||
@ -2047,7 +2076,8 @@ host built with no user program, and a load-file op — the reload machinery
|
|||||||
already builds a file as a module. Open: what =flan-rerun= does with no =main=,
|
already builds a file as a module. Open: what =flan-rerun= does with no =main=,
|
||||||
and a half-loaded file. =C-c C-k= is taken by the inspector.
|
and a half-loaded file. =C-c C-k= is taken by the inspector.
|
||||||
|
|
||||||
** TODO The daemon buffer is navigable but not coloured
|
** NEXT The daemon buffer is navigable but not coloured
|
||||||
|
Decided 2026-09-25: errors, warnings and notes take compilation-mode's faces, and the program's own output takes a face of its own so it reads apart from the compiler's.
|
||||||
=*flan*= is all plain text. =compilation-minor-mode= is on (=emacs/flan.el:822=)
|
=*flan*= is all plain text. =compilation-minor-mode= is on (=emacs/flan.el:822=)
|
||||||
so =next-error= works, but a minor mode installs no font-lock. Open: whether the
|
so =next-error= works, but a minor mode installs no font-lock. Open: whether the
|
||||||
program's output should look different from the compiler's.
|
program's output should look different from the compiler's.
|
||||||
@ -2212,7 +2242,8 @@ The five that run — =macros=, =macro-params=, =macro-unless=, =pkg-macro=,
|
|||||||
out with the other negative cases. The list stays explicit rather than a glob.
|
out with the other negative cases. The list stays explicit rather than a glob.
|
||||||
Not yet run under the sweep: that waits for the batched =@sanitize=.
|
Not yet run under the sweep: that waits for the batched =@sanitize=.
|
||||||
|
|
||||||
** TODO The mutation pass has not been re-run
|
** NEXT The mutation pass has not been re-run
|
||||||
|
Decided 2026-09-25: re-run it once after the second batch of 2026-09-25 merges, with the heavy sweeps, after asking the author.
|
||||||
Sixty mutations, nineteen of which left the whole suite green; all nineteen are
|
Sixty mutations, nineteen of which left the whole suite green; all nineteen are
|
||||||
closed, each re-planted and watched fail against the new test. What is open is
|
closed, each re-planted and watched fail against the new test. What is open is
|
||||||
that the pass has not been run again, so nineteen is the old number.
|
that the pass has not been run again, so nineteen is the old number.
|
||||||
@ -2232,10 +2263,10 @@ it kept; without =keep= that file is gone and the second half is =None=. The
|
|||||||
two-process daemon moves the host's IR from the path it is given and no longer
|
two-process daemon moves the host's IR from the path it is given and no longer
|
||||||
recomputes =Build.workdir=.
|
recomputes =Build.workdir=.
|
||||||
|
|
||||||
** TODO The 2MB OFL font is not vendored
|
** CANCELLED The 2MB OFL font is not vendored
|
||||||
One example wants a font that is OFL and redistributable; it says on screen when
|
CLOSED: [2026-09-25]
|
||||||
it is missing and runs either way. A call about the repository, not about the
|
Two megabytes of history for one example that already says on screen when the
|
||||||
port.
|
font is missing and runs without it.
|
||||||
|
|
||||||
** DONE old-ocaml/ and the built executables are untracked on purpose
|
** DONE old-ocaml/ and the built executables are untracked on purpose
|
||||||
The executables are what a build drops beside their sources. =old-ocaml/= is the
|
The executables are what a build drops beside their sources. =old-ocaml/= is the
|
||||||
|
|||||||
@ -581,12 +581,27 @@ For `syntax-propertize-function'."
|
|||||||
("declare" . 1)
|
("declare" . 1)
|
||||||
("declare-c" . 1))
|
("declare-c" . 1))
|
||||||
"How each form indents, by name.
|
"How each form indents, by name.
|
||||||
Anything not named here that begins with `def' is treated as `:defn' by
|
A qualified name falls back to the entry for its unqualified part. Anything
|
||||||
`flan-indent-function'; anything else indents as a function call.")
|
still unnamed that begins with `def' (but not `default') or `with-' indents as
|
||||||
|
`:defn' in `flan-indent-function'; anything else indents as a function call.")
|
||||||
|
|
||||||
(defun flan--indent-spec (name)
|
(defun flan--indent-spec (name)
|
||||||
"The indent spec for the form called NAME, or nil."
|
"The indent spec for the form called NAME, or nil.
|
||||||
(and name (cdr (assoc name flan-indent-specs))))
|
A qualified name falls back to its unqualified part, so `rl/when' would find
|
||||||
|
the entry for `when' — `clojure--get-indent-method' does the same."
|
||||||
|
(and name
|
||||||
|
(cdr (or (assoc name flan-indent-specs)
|
||||||
|
(and (string-match "/\\([^/]+\\)\\'" name)
|
||||||
|
(assoc (match-string 1 name) flan-indent-specs))))))
|
||||||
|
|
||||||
|
(defun flan--definer-p (name)
|
||||||
|
"Non-nil if NAME indents as a definition or a `with-' form.
|
||||||
|
Either may be qualified: `rl/with-drawing' is a `with-' form. This is
|
||||||
|
`clojure-indent-function''s fallback for a head with no spec, regexp and all;
|
||||||
|
`default…' is excluded there because it is not a definer, and here too."
|
||||||
|
(and name
|
||||||
|
(string-match "\\`\\(?:\\S +/\\)?\\(def[a-z]*\\|with-\\)" name)
|
||||||
|
(not (string-match-p "\\`default" (match-string 1 name)))))
|
||||||
|
|
||||||
(defconst flan--labelled-forms '("dotimes" "while" "until")
|
(defconst flan--labelled-forms '("dotimes" "while" "until")
|
||||||
"Loops that may carry a label, which `break' and `continue' name.
|
"Loops that may carry a label, which `break' and `continue' name.
|
||||||
@ -755,8 +770,9 @@ decision to `calculate-lisp-indent'."
|
|||||||
;; No spec. Anything else spelled `def…' is a definition and indents
|
;; No spec. Anything else spelled `def…' is a definition and indents
|
||||||
;; like one, which covers `defstruct', `defdata', `defunion',
|
;; like one, which covers `defstruct', `defdata', `defunion',
|
||||||
;; `defenum', `defonce', `defconst' and `defalias' without naming
|
;; `defenum', `defonce', `defconst' and `defalias' without naming
|
||||||
;; them.
|
;; them. A `with-' form is a body too — `rl/with-drawing',
|
||||||
((and name (string-match-p "\\`def" name))
|
;; `rl/with-mode-2d camera' — whatever it takes before the body.
|
||||||
|
((flan--definer-p name)
|
||||||
(+ lisp-body-indent head-column))
|
(+ lisp-body-indent head-column))
|
||||||
;; A clause: `(name [params] body…)'. `handler-bind', `handler-case'
|
;; A clause: `(name [params] body…)'. `handler-bind', `handler-case'
|
||||||
;; and `restart-case' all write their clauses this way, and the head is
|
;; and `restart-case' all write their clauses this way, and the head is
|
||||||
|
|||||||
@ -326,6 +326,54 @@
|
|||||||
y 2.0]
|
y 2.0]
|
||||||
(print y))")
|
(print y))")
|
||||||
|
|
||||||
|
;; A `with-' form is a body, qualified or not, whatever it takes on the head's
|
||||||
|
;; line — `clojure-indent-function''s fallback. From `examples/core-2d-camera.flan'.
|
||||||
|
(test-flan-mode--check
|
||||||
|
"a qualified with- form indents its body by two past an argument"
|
||||||
|
"(rl/with-mode-2d camera
|
||||||
|
(rl/draw-rectangle-rec player rl/red)
|
||||||
|
(rl/draw-grid 10 1.0))")
|
||||||
|
|
||||||
|
(test-flan-mode--check
|
||||||
|
"a qualified def form indents its body by two"
|
||||||
|
"(m/defthing name
|
||||||
|
(body))")
|
||||||
|
|
||||||
|
;; A qualified name finds the spec of its unqualified part.
|
||||||
|
(test-flan-mode--check
|
||||||
|
"a qualified when keeps when's spec"
|
||||||
|
"(rl/when (ready?)
|
||||||
|
(go))")
|
||||||
|
|
||||||
|
;; `default…' begins with `def' and is not a definer.
|
||||||
|
(test-flan-mode--check
|
||||||
|
"a default-prefixed call aligns its arguments"
|
||||||
|
"(default-color a
|
||||||
|
b)")
|
||||||
|
|
||||||
|
;; A cond result on its own line sits under its test, not deeper.
|
||||||
|
(test-flan-mode--check
|
||||||
|
"a cond result on its own line aligns with its test"
|
||||||
|
"(cond
|
||||||
|
(= k 1)
|
||||||
|
(one)
|
||||||
|
:else
|
||||||
|
(other))")
|
||||||
|
|
||||||
|
(test-flan-mode--check
|
||||||
|
"a match result on its own line aligns with its pattern"
|
||||||
|
"(match v
|
||||||
|
(Int n) n
|
||||||
|
(List items)
|
||||||
|
(length items))")
|
||||||
|
|
||||||
|
;; A trailing argument of an ordinary call aligns under the first argument,
|
||||||
|
;; even when it is long; only a `with-', `def' or specced head gives a body.
|
||||||
|
(test-flan-mode--check
|
||||||
|
"an ordinary call's arguments align under the first one"
|
||||||
|
"(push missing
|
||||||
|
`(when (ok) (go)))")
|
||||||
|
|
||||||
|
|
||||||
;;; Font lock
|
;;; Font lock
|
||||||
|
|
||||||
|
|||||||
@ -65,13 +65,13 @@
|
|||||||
;; to corner.
|
;; to corner.
|
||||||
(set (at textures 0)
|
(set (at textures 0)
|
||||||
(upload (rl/gen-image-gradient-linear screen-width screen-height 0
|
(upload (rl/gen-image-gradient-linear screen-width screen-height 0
|
||||||
rl/red rl/blue)))
|
rl/red rl/blue)))
|
||||||
(set (at textures 1)
|
(set (at textures 1)
|
||||||
(upload (rl/gen-image-gradient-linear screen-width screen-height 90
|
(upload (rl/gen-image-gradient-linear screen-width screen-height 90
|
||||||
rl/red rl/blue)))
|
rl/red rl/blue)))
|
||||||
(set (at textures 2)
|
(set (at textures 2)
|
||||||
(upload (rl/gen-image-gradient-linear screen-width screen-height 45
|
(upload (rl/gen-image-gradient-linear screen-width screen-height 45
|
||||||
rl/red rl/blue)))
|
rl/red rl/blue)))
|
||||||
;; density 0 means the falloff reaches the edge of the image.
|
;; density 0 means the falloff reaches the edge of the image.
|
||||||
(set (at textures 3)
|
(set (at textures 3)
|
||||||
(upload (rl/gen-image-gradient-radial screen-width screen-height 0.0
|
(upload (rl/gen-image-gradient-radial screen-width screen-height 0.0
|
||||||
|
|||||||
@ -13,8 +13,8 @@
|
|||||||
;; Normative references: spec-memory.md (ownership, containers, places,
|
;; Normative references: spec-memory.md (ownership, containers, places,
|
||||||
;; generics, function values) and spec-conditions.md (restart semantics).
|
;; generics, function values) and spec-conditions.md (restart semantics).
|
||||||
|
|
||||||
(import rl "vendor:raylib") ; directory = package, declaration optional;
|
;; Imports are always qualified: rl/foo.
|
||||||
; imports are always qualified rl/foo
|
(import rl "vendor:raylib") ; directory = package, declaration optional
|
||||||
|
|
||||||
;; ── Type notation ─────────────────────────────────────────────────────
|
;; ── Type notation ─────────────────────────────────────────────────────
|
||||||
;; [4 f32] fixed array — a value, copies on assignment
|
;; [4 f32] fixed array — a value, copies on assignment
|
||||||
|
|||||||
@ -28,82 +28,82 @@
|
|||||||
(let [which (if (> (length args) 1) (i32 (bytes->i64 (bytes-view (at args 1)))) 0)]
|
(let [which (if (> (length args) 1) (i32 (bytes->i64 (bytes-view (at args 1)))) 0)]
|
||||||
(cond
|
(cond
|
||||||
(= which 1)
|
(= which 1)
|
||||||
;; The refusal. The context here is the heap, which can free one
|
;; The refusal. The context here is the heap, which can free one
|
||||||
;; block, and a (Vec Value) against it is a free that would release
|
;; block, and a (Vec Value) against it is a free that would release
|
||||||
;; the slots and strand every inner Vec — so the construction dies
|
;; the slots and strand every inner Vec — so the construction dies
|
||||||
;; rather than the free three hundred lines later.
|
;; rather than the free three hundred lines later.
|
||||||
(let [bad (vec-new Value)]
|
(let [bad (vec-new Value)]
|
||||||
(println (length bad)))
|
(println (length bad)))
|
||||||
|
|
||||||
(= which 2)
|
(= which 2)
|
||||||
;; Use after free-all, which is a different mechanism and worth
|
;; Use after free-all, which is a different mechanism and worth
|
||||||
;; pinning separately: the allocator's epoch moves on every free-all
|
;; pinning separately: the allocator's epoch moves on every free-all
|
||||||
;; and every container records the epoch it was made at. The header
|
;; and every container records the epoch it was made at. The header
|
||||||
;; below was copied *out* of the arena container into a local before
|
;; below was copied *out* of the arena container into a local before
|
||||||
;; the release, which is the case the check has to cover and the
|
;; the release, which is the case the check has to cover and the
|
||||||
;; reason spec-memory.md makes an Allocator a pointer rather than a
|
;; reason spec-memory.md makes an Allocator a pointer rather than a
|
||||||
;; copied value — a copied allocator would carry its own epoch and
|
;; copied value — a copied allocator would carry its own epoch and
|
||||||
;; the copy would never notice.
|
;; the copy would never notice.
|
||||||
(let [outer (vec-new Value frame)]
|
(let [outer (vec-new Value frame)]
|
||||||
(let [inner (vec-new Value frame)]
|
(let [inner (vec-new Value frame)]
|
||||||
(push inner (Value.Int {.n (i64 7)}))
|
(push inner (Value.Int {.n (i64 7)}))
|
||||||
(push outer (Value.List {.items inner})))
|
(push outer (Value.List {.items inner})))
|
||||||
(match (at outer 0)
|
(match (at outer 0)
|
||||||
(List items)
|
(List items)
|
||||||
(do (println (length items))
|
(do (println (length items))
|
||||||
(free-all frame)
|
(free-all frame)
|
||||||
(println (length items)))
|
(println (length items)))
|
||||||
_ (println 0)))
|
_ (println 0)))
|
||||||
|
|
||||||
(= which 3)
|
(= which 3)
|
||||||
;; ZII, which is the hole a guard only at the construction would have
|
;; ZII, which is the hole a guard only at the construction would have
|
||||||
;; left. The items field is omitted from the literal, so it is a zeroed
|
;; left. The items field is omitted from the literal, so it is a zeroed
|
||||||
;; Vec with no allocator at all — it never went near (vec-new) — and
|
;; Vec with no allocator at all — it never went near (vec-new) — and
|
||||||
;; the first push is what adopts the context. So the branch is emitted
|
;; the first push is what adopts the context. So the branch is emitted
|
||||||
;; at every growth too, and there it asks the container, which answers
|
;; at every growth too, and there it asks the container, which answers
|
||||||
;; from the allocator it will adopt when it has none of its own.
|
;; from the allocator it will adopt when it has none of its own.
|
||||||
(let [v (Value.List {})]
|
(let [v (Value.List {})]
|
||||||
(match v
|
(match v
|
||||||
(List items)
|
(List items)
|
||||||
(do (push items (Value.Int {.n (i64 1)}))
|
(do (push items (Value.Int {.n (i64 1)}))
|
||||||
(println (length items)))
|
(println (length items)))
|
||||||
_ (println 0)))
|
_ (println 0)))
|
||||||
|
|
||||||
:else
|
:else
|
||||||
(do
|
(do
|
||||||
;; The control, and it is the case the frame tier exists for: a
|
;; The control, and it is the case the frame tier exists for: a
|
||||||
;; (Vec (Vec i32)) owns storage at two levels and is perfectly happy
|
;; (Vec (Vec i32)) owns storage at two levels and is perfectly happy
|
||||||
;; in a region, because free-all releases every block the region
|
;; in a region, because free-all releases every block the region
|
||||||
;; handed out and the inner ones are among them. The rule asks about
|
;; handed out and the inner ones are among them. The rule asks about
|
||||||
;; the *allocator*, never "does this element own anything", so this
|
;; the *allocator*, never "does this element own anything", so this
|
||||||
;; must be built without complaint.
|
;; must be built without complaint.
|
||||||
(with-allocator frame
|
(with-allocator frame
|
||||||
(let [rows (vec-new Row)]
|
(let [rows (vec-new Row)]
|
||||||
(let [row (vec-new i32)]
|
(let [row (vec-new i32)]
|
||||||
(push row 1)
|
(push row 1)
|
||||||
(push row 2)
|
(push row 2)
|
||||||
(push rows row))
|
(push rows row))
|
||||||
(println (length rows))
|
(println (length rows))
|
||||||
(println (length (at rows 0)))))
|
(println (length (at rows 0)))))
|
||||||
(free-all frame)
|
(free-all frame)
|
||||||
;; And the same container against the heap dies — asserted from the
|
;; And the same container against the heap dies — asserted from the
|
||||||
;; other side in run 1 above; here the point is only that the region
|
;; other side in run 1 above; here the point is only that the region
|
||||||
;; run above got no complaint.
|
;; run above got no complaint.
|
||||||
(with-allocator frame
|
(with-allocator frame
|
||||||
(let [vs (vec-new Value)]
|
(let [vs (vec-new Value)]
|
||||||
(push vs (Value.Int {.n (i64 41)}))
|
(push vs (Value.Int {.n (i64 41)}))
|
||||||
(println (length vs))))
|
(println (length vs))))
|
||||||
(free-all frame)
|
(free-all frame)
|
||||||
;; And the zeroed field of run 3, this time in the region: the growth
|
;; And the zeroed field of run 3, this time in the region: the growth
|
||||||
;; guard has to pass here as surely as it has to fail there, or every
|
;; guard has to pass here as surely as it has to fail there, or every
|
||||||
;; ZII container in an arena would be unusable.
|
;; ZII container in an arena would be unusable.
|
||||||
(with-allocator frame
|
(with-allocator frame
|
||||||
(let [v (Value.List {})]
|
(let [v (Value.List {})]
|
||||||
(match v
|
(match v
|
||||||
(List items)
|
(List items)
|
||||||
(do (push items (Value.Int {.n (i64 1)}))
|
(do (push items (Value.Int {.n (i64 1)}))
|
||||||
(println (length items)))
|
(println (length items)))
|
||||||
_ (println 0))))
|
_ (println 0))))
|
||||||
(free-all frame))))
|
(free-all frame))))
|
||||||
(arena-destroy frame)
|
(arena-destroy frame)
|
||||||
0)
|
0)
|
||||||
|
|||||||
@ -51,13 +51,13 @@
|
|||||||
(match v
|
(match v
|
||||||
(Int n) n
|
(Int n) n
|
||||||
(List items)
|
(List items)
|
||||||
(let [t (i64 0)]
|
(let [t (i64 0)]
|
||||||
(dotimes [i (length items)]
|
(dotimes [i (length items)]
|
||||||
(set t (+ t (total (at items i)))))
|
(set t (+ t (total (at items i)))))
|
||||||
t)
|
t)
|
||||||
(Table entries)
|
(Table entries)
|
||||||
(+ (match (get entries "xs") (Some x) (total x) None (i64 0))
|
(+ (match (get entries "xs") (Some x) (total x) None (i64 0))
|
||||||
(match (get entries "ys") (Some y) (total y) None (i64 0)))
|
(match (get entries "ys") (Some y) (total y) None (i64 0)))
|
||||||
_ (i64 0)))
|
_ (i64 0)))
|
||||||
|
|
||||||
(defn build [] i64
|
(defn build [] i64
|
||||||
|
|||||||
@ -213,8 +213,9 @@
|
|||||||
|
|
||||||
;; ── The refusals, each asserted on its own reason ─────────────────
|
;; ── The refusals, each asserted on its own reason ─────────────────
|
||||||
(refusal "\"a\\nb\"") ; an escape inside a string
|
(refusal "\"a\\nb\"") ; an escape inside a string
|
||||||
(refusal "\"a\\\"b\"") ; an escaped quote — the case where a wrong
|
;; An escaped quote is the case where a wrong version returns `a\` and
|
||||||
; version returns `a\` and leaves `b"` behind
|
;; leaves `b"` behind.
|
||||||
|
(refusal "\"a\\\"b\"") ; an escaped quote
|
||||||
(refusal "\"unterminated") ; not a refusal, but the other string failure
|
(refusal "\"unterminated") ; not a refusal, but the other string failure
|
||||||
;; A set is read now, so what is left to refuse about one is its balance. A
|
;; A set is read now, so what is left to refuse about one is its balance. A
|
||||||
;; `#{` that pushed nothing would answer "no error" for both of these.
|
;; `#{` that pushed nothing would answer "no error" for both of these.
|
||||||
@ -228,8 +229,8 @@
|
|||||||
(refusal "\\a") ; a character literal
|
(refusal "\\a") ; a character literal
|
||||||
(refusal "12x") ; starts like a number, is not one
|
(refusal "12x") ; starts like a number, is not one
|
||||||
(refusal "[1 :]") ; a colon with no name
|
(refusal "[1 :]") ; a colon with no name
|
||||||
(refusal "@") ; not the start of any value — and the case a
|
;; `@` is the case a scan-to-delimiter reads as a one-byte symbol.
|
||||||
; scan-to-delimiter reads as a one-byte symbol
|
(refusal "@") ; not the start of any value
|
||||||
(refusal "`x") ; a Clojure reader macro, not EDN
|
(refusal "`x") ; a Clojure reader macro, not EDN
|
||||||
(refusal "[1 2}") ; the wrong closer
|
(refusal "[1 2}") ; the wrong closer
|
||||||
(refusal "]") ; a closer with nothing open
|
(refusal "]") ; a closer with nothing open
|
||||||
|
|||||||
@ -154,7 +154,7 @@
|
|||||||
(do (update-frame col)
|
(do (update-frame col)
|
||||||
(set frames (+ frames 1)))
|
(set frames (+ frames 1)))
|
||||||
(continue [] (restore)
|
(continue [] (restore)
|
||||||
(set skipped (+ skipped 1)))))
|
(set skipped (+ skipped 1)))))
|
||||||
|
|
||||||
(defn main [] i32
|
(defn main [] i32
|
||||||
(set (.brush world) 1)
|
(set (.brush world) 1)
|
||||||
|
|||||||
@ -118,41 +118,41 @@
|
|||||||
(defn read-value [c (Ptr json/Cursor) t json/Token] Value
|
(defn read-value [c (Ptr json/Cursor) t json/Token] Value
|
||||||
(cond
|
(cond
|
||||||
(= (.kind t) json/tok-bool)
|
(= (.kind t) json/tok-bool)
|
||||||
(Value.Bool {.b (match (json/bool-of t) (Some v) v None false)})
|
(Value.Bool {.b (match (json/bool-of t) (Some v) v None false)})
|
||||||
(= (.kind t) json/tok-int)
|
(= (.kind t) json/tok-int)
|
||||||
(Value.Int {.n (match (json/int-of t) (Some v) v None (i64 0))})
|
(Value.Int {.n (match (json/int-of t) (Some v) v None (i64 0))})
|
||||||
(= (.kind t) json/tok-float)
|
(= (.kind t) json/tok-float)
|
||||||
(Value.Float {.x (match (json/float-of t) (Some v) v None 0.0)})
|
(Value.Float {.x (match (json/float-of t) (Some v) v None 0.0)})
|
||||||
(= (.kind t) json/tok-string)
|
(= (.kind t) json/tok-string)
|
||||||
(Value.Text {.s (match (json/string-of t) (Some s) s None "")})
|
(Value.Text {.s (match (json/string-of t) (Some s) s None "")})
|
||||||
|
|
||||||
(= (.kind t) json/tok-array-open)
|
(= (.kind t) json/tok-array-open)
|
||||||
(let [items (vec-new Value)
|
(let [items (vec-new Value)
|
||||||
u (json/next c)
|
u (json/next c)
|
||||||
more (and (json/ok? c) (!= (.kind u) json/tok-array-close))]
|
more (and (json/ok? c) (!= (.kind u) json/tok-array-close))]
|
||||||
(while more
|
(while more
|
||||||
(push items (read-value c u))
|
(push items (read-value c u))
|
||||||
(let [sep (json/next c)]
|
(let [sep (json/next c)]
|
||||||
(cond
|
(cond
|
||||||
(not (json/ok? c)) (set more false)
|
(not (json/ok? c)) (set more false)
|
||||||
(= (.kind sep) json/tok-array-close) (set more false)
|
(= (.kind sep) json/tok-array-close) (set more false)
|
||||||
(!= (.kind sep) json/tok-comma)
|
(!= (.kind sep) json/tok-comma)
|
||||||
(do (json/fail c json/err-unexpected-token (.pos sep))
|
(do (json/fail c json/err-unexpected-token (.pos sep))
|
||||||
(set more false))
|
(set more false))
|
||||||
:else
|
:else
|
||||||
(do (set u (json/next c))
|
(do (set u (json/next c))
|
||||||
;; A comma and then the closer. Named, because a trailing
|
;; A comma and then the closer. Named, because a trailing
|
||||||
;; comma is legal JSON5 and a reader that quietly allowed
|
;; comma is legal JSON5 and a reader that quietly allowed
|
||||||
;; it would be reading a different format than it claims.
|
;; it would be reading a different format than it claims.
|
||||||
;;
|
;;
|
||||||
;; The fail is what ends the loop, through the ok? test
|
;; The fail is what ends the loop, through the ok? test
|
||||||
;; below it and not on its own — so these two are in this
|
;; below it and not on its own — so these two are in this
|
||||||
;; order on purpose, and swapping them spins.
|
;; order on purpose, and swapping them spins.
|
||||||
(when (= (.kind u) json/tok-array-close)
|
(when (= (.kind u) json/tok-array-close)
|
||||||
(json/fail c json/err-trailing-comma (.pos u)))
|
(json/fail c json/err-trailing-comma (.pos u)))
|
||||||
(when (not (json/ok? c))
|
(when (not (json/ok? c))
|
||||||
(set more false))))))
|
(set more false))))))
|
||||||
(Value.Array {.items items}))
|
(Value.Array {.items items}))
|
||||||
|
|
||||||
;; An object key is a quoted string and nothing else — an unquoted one was
|
;; An object key is a quoted string and nothing else — an unquoted one was
|
||||||
;; already refused by the tokenizer as a bare word, so what reaches here is
|
;; already refused by the tokenizer as a bare word, so what reaches here is
|
||||||
@ -160,41 +160,41 @@
|
|||||||
;; same string-of the values use, so the map owns its keys and the source
|
;; same string-of the values use, so the map owns its keys and the source
|
||||||
;; buffer is not in the picture.
|
;; buffer is not in the picture.
|
||||||
(= (.kind t) json/tok-object-open)
|
(= (.kind t) json/tok-object-open)
|
||||||
(let [entries (map-new string Value)
|
(let [entries (map-new string Value)
|
||||||
k (json/next c)
|
k (json/next c)
|
||||||
more (and (json/ok? c) (!= (.kind k) json/tok-object-close))]
|
more (and (json/ok? c) (!= (.kind k) json/tok-object-close))]
|
||||||
(while more
|
(while more
|
||||||
(if (!= (.kind k) json/tok-string)
|
(if (!= (.kind k) json/tok-string)
|
||||||
(do (json/fail c json/err-unexpected-token (.pos k))
|
(do (json/fail c json/err-unexpected-token (.pos k))
|
||||||
(set more false))
|
(set more false))
|
||||||
(let [key (match (json/string-of k) (Some s) s None "")]
|
(let [key (match (json/string-of k) (Some s) s None "")]
|
||||||
(json/expect c json/tok-colon)
|
(json/expect c json/tok-colon)
|
||||||
(if (not (json/ok? c))
|
(if (not (json/ok? c))
|
||||||
(set more false)
|
(set more false)
|
||||||
(let [v (json/next c)]
|
(let [v (json/next c)]
|
||||||
(if (not (json/ok? c))
|
(if (not (json/ok? c))
|
||||||
(set more false)
|
(set more false)
|
||||||
(do
|
(do
|
||||||
(put entries key (read-value c v))
|
(put entries key (read-value c v))
|
||||||
(let [sep (json/next c)]
|
(let [sep (json/next c)]
|
||||||
(cond
|
(cond
|
||||||
(not (json/ok? c)) (set more false)
|
(not (json/ok? c)) (set more false)
|
||||||
(= (.kind sep) json/tok-object-close) (set more false)
|
(= (.kind sep) json/tok-object-close) (set more false)
|
||||||
(!= (.kind sep) json/tok-comma)
|
(!= (.kind sep) json/tok-comma)
|
||||||
(do (json/fail c json/err-unexpected-token (.pos sep))
|
(do (json/fail c json/err-unexpected-token (.pos sep))
|
||||||
(set more false))
|
(set more false))
|
||||||
:else
|
:else
|
||||||
;; Same two steps, same order, same reason as the
|
;; Same two steps, same order, same reason as the
|
||||||
;; array arm: the fail ends the loop through the
|
;; array arm: the fail ends the loop through the
|
||||||
;; ok? test under it, and it has to, because the
|
;; ok? test under it, and it has to, because the
|
||||||
;; next pass would otherwise ask string-of for the
|
;; next pass would otherwise ask string-of for the
|
||||||
;; text of a closing brace.
|
;; text of a closing brace.
|
||||||
(do (set k (json/next c))
|
(do (set k (json/next c))
|
||||||
(when (= (.kind k) json/tok-object-close)
|
(when (= (.kind k) json/tok-object-close)
|
||||||
(json/fail c json/err-trailing-comma (.pos k)))
|
(json/fail c json/err-trailing-comma (.pos k)))
|
||||||
(when (not (json/ok? c))
|
(when (not (json/ok? c))
|
||||||
(set more false))))))))))))
|
(set more false))))))))))))
|
||||||
(Value.Object {.entries entries}))
|
(Value.Object {.entries entries}))
|
||||||
|
|
||||||
:else Value.Null))
|
:else Value.Null))
|
||||||
|
|
||||||
@ -204,34 +204,34 @@
|
|||||||
(defn count-leaves [v Value] i32
|
(defn count-leaves [v Value] i32
|
||||||
(match v
|
(match v
|
||||||
(Array items)
|
(Array items)
|
||||||
(let [n 0]
|
(let [n 0]
|
||||||
(dotimes [i (length items)]
|
(dotimes [i (length items)]
|
||||||
(set n (+ n (count-leaves (at items i)))))
|
(set n (+ n (count-leaves (at items i)))))
|
||||||
n)
|
n)
|
||||||
;; map-next fills an out-parameter with a copy of the value's bytes, which
|
;; map-next fills an out-parameter with a copy of the value's bytes, which
|
||||||
;; for a Value holding a container is a second header over the same block.
|
;; for a Value holding a container is a second header over the same block.
|
||||||
;; In a region that is an alias and not a second owner, so walking a map is
|
;; In a region that is an alias and not a second owner, so walking a map is
|
||||||
;; the ordinary iteration and needs no accessor of its own.
|
;; the ordinary iteration and needs no accessor of its own.
|
||||||
(Object entries)
|
(Object entries)
|
||||||
(let [n 0
|
(let [n 0
|
||||||
cur (i64 0)
|
cur (i64 0)
|
||||||
k ""
|
k ""
|
||||||
e Value.Null]
|
e Value.Null]
|
||||||
(while (map-next entries (addr cur) (addr k) (addr e))
|
(while (map-next entries (addr cur) (addr k) (addr e))
|
||||||
(set n (+ n (count-leaves e))))
|
(set n (+ n (count-leaves e))))
|
||||||
n)
|
n)
|
||||||
_ 1))
|
_ 1))
|
||||||
|
|
||||||
(defn sum-ints [v Value] i64
|
(defn sum-ints [v Value] i64
|
||||||
(match v
|
(match v
|
||||||
(Int n) n
|
(Int n) n
|
||||||
(Array items)
|
(Array items)
|
||||||
(let [t (i64 0)]
|
(let [t (i64 0)]
|
||||||
(dotimes [i (length items)]
|
(dotimes [i (length items)]
|
||||||
(set t (+ t (sum-ints (at items i)))))
|
(set t (+ t (sum-ints (at items i)))))
|
||||||
t)
|
t)
|
||||||
(Object entries)
|
(Object entries)
|
||||||
(match (get entries "xs") (Some x) (sum-ints x) None (i64 0))
|
(match (get entries "xs") (Some x) (sum-ints x) None (i64 0))
|
||||||
_ (i64 0)))
|
_ (i64 0)))
|
||||||
|
|
||||||
(defn describe [v Value] string
|
(defn describe [v Value] string
|
||||||
@ -244,9 +244,9 @@
|
|||||||
(defn text-at [v Value key string] string
|
(defn text-at [v Value key string] string
|
||||||
(match v
|
(match v
|
||||||
(Object entries)
|
(Object entries)
|
||||||
(match (get entries key)
|
(match (get entries key)
|
||||||
(Some x) (match x (Text s) s _ "<not a string>")
|
(Some x) (match x (Text s) s _ "<not a string>")
|
||||||
None "<missing>")
|
None "<missing>")
|
||||||
_ "<not an object>"))
|
_ "<not an object>"))
|
||||||
|
|
||||||
(defn read-doc [src [u8]] Value
|
(defn read-doc [src [u8]] Value
|
||||||
@ -413,7 +413,7 @@
|
|||||||
(println (sum-ints v)) ; [1 2 3]
|
(println (sum-ints v)) ; [1 2 3]
|
||||||
(println (describe (match v (Object e) (match (get e "gravity")
|
(println (describe (match v (Object e) (match (get e "gravity")
|
||||||
(Some g) g None Value.Null)
|
(Some g) g None Value.Null)
|
||||||
_ Value.Null)))
|
_ Value.Null)))
|
||||||
;; The escapes, resolved. The quotes in `name` never existed as bytes
|
;; The escapes, resolved. The quotes in `name` never existed as bytes
|
||||||
;; in the source; é is two bytes out of six and the emoji is four out
|
;; in the source; é is two bytes out of six and the emoji is four out
|
||||||
;; of twelve; and the eight one-character escapes are eight bytes.
|
;; of twelve; and the eight one-character escapes are eight bytes.
|
||||||
|
|||||||
@ -25,8 +25,8 @@
|
|||||||
(match t
|
(match t
|
||||||
(Leaf n) n
|
(Leaf n) n
|
||||||
(Branch kids)
|
(Branch kids)
|
||||||
(let [s (i64 0)]
|
(let [s (i64 0)]
|
||||||
(dotimes [i (length kids)]
|
(dotimes [i (length kids)]
|
||||||
(set s (+ s (total (at kids i)))))
|
(set s (+ s (total (at kids i)))))
|
||||||
s)
|
s)
|
||||||
Empty (i64 0)))
|
Empty (i64 0)))
|
||||||
|
|||||||
@ -102,9 +102,9 @@
|
|||||||
(show-dec (slice lone-cont 0 1)) ; a continuation byte leading
|
(show-dec (slice lone-cont 0 1)) ; a continuation byte leading
|
||||||
(show-dec (slice overlong2 0 2)) ; overlong "/"
|
(show-dec (slice overlong2 0 2)) ; overlong "/"
|
||||||
(show-dec (slice overlong3 0 3)) ; overlong "/" again, three bytes
|
(show-dec (slice overlong3 0 3)) ; overlong "/" again, three bytes
|
||||||
(show-dec (slice overlong4 0 4)) ; and four. Added after a mutation run:
|
;; Added after a mutation run: relaxing 0xf0's floor to 0x80 left the
|
||||||
; relaxing 0xf0's floor to 0x80 left the
|
;; whole suite green without this line.
|
||||||
; whole suite green without this line.
|
(show-dec (slice overlong4 0 4)) ; and four
|
||||||
(show-dec (slice surrogate 0 3)) ; U+D800
|
(show-dec (slice surrogate 0 3)) ; U+D800
|
||||||
(show-dec (slice above-max 0 4)) ; U+110000
|
(show-dec (slice above-max 0 4)) ; U+110000
|
||||||
(show-dec (slice lead-f5 0 4)) ; 0xf5 leads nothing
|
(show-dec (slice lead-f5 0 4)) ; 0xf5 leads nothing
|
||||||
|
|||||||
112
vendor/edn/provide.flan
vendored
112
vendor/edn/provide.flan
vendored
@ -216,8 +216,8 @@
|
|||||||
(let [t (next c)]
|
(let [t (next c)]
|
||||||
(when (not (ok? c))
|
(when (not (ok? c))
|
||||||
(return (derived-bad
|
(return (derived-bad
|
||||||
(joined3 "the data file could not be read at " (where src (error-pos c))
|
(joined3 "the data file could not be read at " (where src (error-pos c))
|
||||||
(joined ": " (error-message (.err c)))))))
|
(joined ": " (error-message (.err c)))))))
|
||||||
(cond
|
(cond
|
||||||
(= (.kind t) tok-int) (ok-derived `i64 (form-nil) `(need-int c))
|
(= (.kind t) tok-int) (ok-derived `i64 (form-nil) `(need-int c))
|
||||||
(= (.kind t) tok-float) (ok-derived `f64 (form-nil) `(need-float c))
|
(= (.kind t) tok-float) (ok-derived `f64 (form-nil) `(need-float c))
|
||||||
@ -231,12 +231,12 @@
|
|||||||
(= (.kind t) tok-nil)
|
(= (.kind t) tok-nil)
|
||||||
(derived-bad
|
(derived-bad
|
||||||
(joined3 "the nil at " (where src (.pos t))
|
(joined3 "the nil at " (where src (.pos t))
|
||||||
" has no type to derive — a field that is sometimes absent is not something a struct can hold, so give it a value in the file or take the key out"))
|
" has no type to derive — a field that is sometimes absent is not something a struct can hold, so give it a value in the file or take the key out"))
|
||||||
|
|
||||||
:else
|
:else
|
||||||
(derived-bad
|
(derived-bad
|
||||||
(joined3 "the value at " (where src (.pos t))
|
(joined3 "the value at " (where src (.pos t))
|
||||||
" is not one defedn derives a type from — a map, a vector, a set, an integer, a float, a boolean or a string")))))
|
" is not one defedn derives a type from — a map, a vector, a set, an integer, a float, a boolean or a string")))))
|
||||||
|
|
||||||
;; A vector, whose elements must all come to the same type. The first element
|
;; A vector, whose elements must all come to the same type. The first element
|
||||||
;; decides; every one after it is compared against that decision and both
|
;; decides; every one after it is compared against that decision and both
|
||||||
@ -245,8 +245,8 @@
|
|||||||
(defn- derive-vec [c (Ptr Cursor) name string at-pos i32 src [u8]] Derived
|
(defn- derive-vec [c (Ptr Cursor) name string at-pos i32 src [u8]] Derived
|
||||||
(when (at-byte? c \])
|
(when (at-byte? c \])
|
||||||
(return (derived-bad
|
(return (derived-bad
|
||||||
(joined3 "the empty vector at " (where src at-pos)
|
(joined3 "the empty vector at " (where src at-pos)
|
||||||
" has no element to derive an element type from — defedn reads the shape out of the data, and an empty collection carries none"))))
|
" has no element to derive an element type from — defedn reads the shape out of the data, and an empty collection carries none"))))
|
||||||
(let [head (derive c (joined name "-item") src)]
|
(let [head (derive c (joined name "-item") src)]
|
||||||
(when (bad? head)
|
(when (bad? head)
|
||||||
(return head))
|
(return head))
|
||||||
@ -266,12 +266,12 @@
|
|||||||
cn (Form.Sym {.s (joined name "-new")})]
|
cn (Form.Sym {.s (joined name "-new")})]
|
||||||
(ok-derived ty (with-decl (.decls head) `(defn ~cn [a Allocator] ~ty
|
(ok-derived ty (with-decl (.decls head) `(defn ~cn [a Allocator] ~ty
|
||||||
(vec-new a)))
|
(vec-new a)))
|
||||||
`(let [xs (~cn a)]
|
`(let [xs (~cn a)]
|
||||||
(expect c tok-vec-open)
|
(expect c tok-vec-open)
|
||||||
(while (and (ok? c) (not (at-byte? c \])))
|
(while (and (ok? c) (not (at-byte? c \])))
|
||||||
(push xs ~read1))
|
(push xs ~read1))
|
||||||
(expect c tok-vec-close)
|
(expect c tok-vec-close)
|
||||||
xs))))))
|
xs))))))
|
||||||
|
|
||||||
;; Why every collection gets a one-line constructor of its own.
|
;; Why every collection gets a one-line constructor of its own.
|
||||||
;;
|
;;
|
||||||
@ -294,8 +294,8 @@
|
|||||||
(defn- derive-set [c (Ptr Cursor) name string at-pos i32 src [u8]] Derived
|
(defn- derive-set [c (Ptr Cursor) name string at-pos i32 src [u8]] Derived
|
||||||
(when (at-byte? c \})
|
(when (at-byte? c \})
|
||||||
(return (derived-bad
|
(return (derived-bad
|
||||||
(joined3 "the empty set at " (where src at-pos)
|
(joined3 "the empty set at " (where src at-pos)
|
||||||
" has no element to derive an element type from"))))
|
" has no element to derive an element type from"))))
|
||||||
(let [head (derive-key c (joined name "-key") src)]
|
(let [head (derive-key c (joined name "-key") src)]
|
||||||
(when (bad? head)
|
(when (bad? head)
|
||||||
(return head))
|
(return head))
|
||||||
@ -315,12 +315,12 @@
|
|||||||
cn (Form.Sym {.s (joined name "-new")})]
|
cn (Form.Sym {.s (joined name "-new")})]
|
||||||
(ok-derived ty (with-decl (.decls head) `(defn ~cn [a Allocator] ~ty
|
(ok-derived ty (with-decl (.decls head) `(defn ~cn [a Allocator] ~ty
|
||||||
(map-new a)))
|
(map-new a)))
|
||||||
`(let [tbl (~cn a)]
|
`(let [tbl (~cn a)]
|
||||||
(expect c tok-set-open)
|
(expect c tok-set-open)
|
||||||
(while (and (ok? c) (not (at-byte? c \})))
|
(while (and (ok? c) (not (at-byte? c \})))
|
||||||
(put tbl ~read1 true))
|
(put tbl ~read1 true))
|
||||||
(expect c tok-map-close)
|
(expect c tok-map-close)
|
||||||
tbl))))))
|
tbl))))))
|
||||||
|
|
||||||
;; One element of a set. The scalars that are map keys pass; a vector becomes a
|
;; One element of a set. The scalars that are map keys pass; a vector becomes a
|
||||||
;; fixed array, which is one where a Vec is not; anything else is refused here
|
;; fixed array, which is one where a Vec is not; anything else is refused here
|
||||||
@ -334,8 +334,8 @@
|
|||||||
(return d))
|
(return d))
|
||||||
(when (not (key-type? (.ty d)))
|
(when (not (key-type? (.ty d)))
|
||||||
(return (derived-bad
|
(return (derived-bad
|
||||||
(joined3 "a set of " (render (.ty d))
|
(joined3 "a set of " (render (.ty d))
|
||||||
" is not something this builds: a set becomes a (Map T bool), so its elements are map keys. Integers, booleans, strings and vectors of those are"))))
|
" is not something this builds: a set becomes a (Map T bool), so its elements are map keys. Integers, booleans, strings and vectors of those are"))))
|
||||||
d))
|
d))
|
||||||
|
|
||||||
;; A vector in key position. Its length is part of its type, so every element
|
;; A vector in key position. Its length is part of its type, so every element
|
||||||
@ -346,8 +346,8 @@
|
|||||||
(let [open (next c)]
|
(let [open (next c)]
|
||||||
(when (at-byte? c \])
|
(when (at-byte? c \])
|
||||||
(return (derived-bad
|
(return (derived-bad
|
||||||
(joined3 "the empty vector at " (where src (.pos open))
|
(joined3 "the empty vector at " (where src (.pos open))
|
||||||
" is inside a set, and an empty fixed array has no element type and no length"))))
|
" is inside a set, and an empty fixed array has no element type and no length"))))
|
||||||
(let [head (derive c (joined name "-item") src)]
|
(let [head (derive c (joined name "-item") src)]
|
||||||
(when (bad? head)
|
(when (bad? head)
|
||||||
(return head))
|
(return head))
|
||||||
@ -364,30 +364,30 @@
|
|||||||
(expect c tok-vec-close)
|
(expect c tok-vec-close)
|
||||||
(when (not (key-type? (.ty head)))
|
(when (not (key-type? (.ty head)))
|
||||||
(return (derived-bad
|
(return (derived-bad
|
||||||
(joined3 "a set of vectors of " (render (.ty head))
|
(joined3 "a set of vectors of " (render (.ty head))
|
||||||
" is not something this builds: the vector becomes a fixed array, which is a map key only when its elements are compared bytewise"))))
|
" is not something this builds: the vector becomes a fixed array, which is a map key only when its elements are compared bytewise"))))
|
||||||
(let [elem (.ty head)
|
(let [elem (.ty head)
|
||||||
read1 (.reader head)
|
read1 (.reader head)
|
||||||
count (Form.Int {.i n})]
|
count (Form.Int {.i n})]
|
||||||
(ok-derived `[~count ~elem] (.decls head)
|
(ok-derived `[~count ~elem] (.decls head)
|
||||||
`(let [arr (array ~count ~elem)
|
`(let [arr (array ~count ~elem)
|
||||||
i 0]
|
i 0]
|
||||||
(expect c tok-vec-open)
|
(expect c tok-vec-open)
|
||||||
(while (and (ok? c) (not (at-byte? c \])) (< i ~count))
|
(while (and (ok? c) (not (at-byte? c \])) (< i ~count))
|
||||||
(set (at arr i) ~read1)
|
(set (at arr i) ~read1)
|
||||||
(set i (+ i 1)))
|
(set i (+ i 1)))
|
||||||
(expect c tok-vec-close)
|
(expect c tok-vec-close)
|
||||||
arr)))))))
|
arr)))))))
|
||||||
|
|
||||||
(defn- disagreement [what string src [u8] at-pos i32 n i64
|
(defn- disagreement [what string src [u8] at-pos i32 n i64
|
||||||
first Form second Form] string
|
first Form second Form] string
|
||||||
(joined3 (joined3 "the " what " at ")
|
(joined3 (joined3 "the " what " at ")
|
||||||
(where src at-pos)
|
(where src at-pos)
|
||||||
(joined3 (joined3 " holds more than one shape: its first element is "
|
(joined3 (joined3 " holds more than one shape: its first element is "
|
||||||
(render first) " and element ")
|
(render first) " and element ")
|
||||||
(i64->string n)
|
(i64->string n)
|
||||||
(joined3 " is " (render second)
|
(joined3 " is " (render second)
|
||||||
". Every element has to be the same shape, because the type this becomes has one element type"))))
|
". Every element has to be the same shape, because the type this becomes has one element type"))))
|
||||||
|
|
||||||
;; ── A map, which is a struct ────────────────────────────────────────
|
;; ── A map, which is a struct ────────────────────────────────────────
|
||||||
;;
|
;;
|
||||||
@ -403,8 +403,8 @@
|
|||||||
(defn- derive-map [c (Ptr Cursor) name string at-pos i32 src [u8]] Derived
|
(defn- derive-map [c (Ptr Cursor) name string at-pos i32 src [u8]] Derived
|
||||||
(when (at-byte? c \})
|
(when (at-byte? c \})
|
||||||
(return (derived-bad
|
(return (derived-bad
|
||||||
(joined3 "the empty map at " (where src at-pos)
|
(joined3 "the empty map at " (where src at-pos)
|
||||||
" has no keys to derive fields from — a struct with no fields is not a shape anything can be read into"))))
|
" has no keys to derive fields from — a struct with no fields is not a shape anything can be read into"))))
|
||||||
(let [fields (vec-new Form) ; the defstruct's [name type ...] vector
|
(let [fields (vec-new Form) ; the defstruct's [name type ...] vector
|
||||||
clauses (vec-new Form) ; the reader's cond: test, body, test, body
|
clauses (vec-new Form) ; the reader's cond: test, body, test, body
|
||||||
missing (vec-new Form) ; one per field, checked when the map closes
|
missing (vec-new Form) ; one per field, checked when the map closes
|
||||||
@ -414,14 +414,14 @@
|
|||||||
(let [k (next c)]
|
(let [k (next c)]
|
||||||
(when (not (ok? c))
|
(when (not (ok? c))
|
||||||
(return (derived-bad
|
(return (derived-bad
|
||||||
(joined3 "the data file could not be read at "
|
(joined3 "the data file could not be read at "
|
||||||
(where src (error-pos c))
|
(where src (error-pos c))
|
||||||
(joined ": " (error-message (.err c)))))))
|
(joined ": " (error-message (.err c)))))))
|
||||||
(when (!= (.kind k) tok-keyword)
|
(when (!= (.kind k) tok-keyword)
|
||||||
(return (derived-bad
|
(return (derived-bad
|
||||||
(joined3 (joined3 "the map at " (where src at-pos) " has a key at ")
|
(joined3 (joined3 "the map at " (where src at-pos) " has a key at ")
|
||||||
(where src (.pos k))
|
(where src (.pos k))
|
||||||
" that is not a keyword. A struct's fields are named, so every key of a map defedn reads has to be one — :name, not \"name\" and not 1"))))
|
" that is not a keyword. A struct's fields are named, so every key of a map defedn reads has to be one — :name, not \"name\" and not 1"))))
|
||||||
(let [fname (copy-text (.text k))
|
(let [fname (copy-text (.text k))
|
||||||
d (derive c (joined3 name "-" fname) src)]
|
d (derive c (joined3 name "-" fname) src)]
|
||||||
(when (bad? d)
|
(when (bad? d)
|
||||||
@ -441,11 +441,11 @@
|
|||||||
;; bit is decided here, where the field is, so the two cannot fall
|
;; bit is decided here, where the field is, so the two cannot fall
|
||||||
;; out of step the way a parallel list of names would.
|
;; out of step the way a parallel list of names would.
|
||||||
(push missing
|
(push missing
|
||||||
`(when (= (bit-and seen ~bit) 0)
|
`(when (= (bit-and seen ~bit) 0)
|
||||||
(signal (SchemaDrift {.field ~lit
|
(signal (SchemaDrift {.field ~lit
|
||||||
.struct ~(Form.Str {.s name})
|
.struct ~(Form.Str {.s name})
|
||||||
.extra? false
|
.extra? false
|
||||||
.pos (.pos k)})))))
|
.pos (.pos k)})))))
|
||||||
(set idx (+ idx 1)))))
|
(set idx (+ idx 1)))))
|
||||||
(expect c tok-map-close)
|
(expect c tok-map-close)
|
||||||
;; An unknown key. The hand-written reader skips one, which is right when a
|
;; An unknown key. The hand-written reader skips one, which is right when a
|
||||||
@ -455,12 +455,12 @@
|
|||||||
;; handle the condition still reads the rest.
|
;; handle the condition still reads the rest.
|
||||||
(push clauses `:else)
|
(push clauses `:else)
|
||||||
(push clauses
|
(push clauses
|
||||||
`(do (signal (SchemaDrift {.field (copy-text (.text k))
|
`(do (signal (SchemaDrift {.field (copy-text (.text k))
|
||||||
.struct ~(Form.Str {.s name})
|
.struct ~(Form.Str {.s name})
|
||||||
.extra? true
|
.extra? true
|
||||||
.pos (.pos k)}))
|
.pos (.pos k)}))
|
||||||
(when (not (skip-value c))
|
(when (not (skip-value c))
|
||||||
(return out))))
|
(return out))))
|
||||||
(let [sname (Form.Sym {.s name})
|
(let [sname (Form.Sym {.s name})
|
||||||
rname (Form.Sym {.s (joined "read-" name)})
|
rname (Form.Sym {.s (joined "read-" name)})
|
||||||
struct `(defstruct ~sname ~(Form.Vec {.xs (slice fields)}))
|
struct `(defstruct ~sname ~(Form.Vec {.xs (slice fields)}))
|
||||||
@ -539,7 +539,7 @@
|
|||||||
(Some src) (provide name path src)
|
(Some src) (provide name path src)
|
||||||
None (refuse
|
None (refuse
|
||||||
(joined3 "there is no file at " path
|
(joined3 "there is no file at " path
|
||||||
", read relative to the file this defedn is written in — the same place (embed \"...\") would look")))
|
", read relative to the file this defedn is written in — the same place (embed \"...\") would look")))
|
||||||
_ (refuse "defedn's first argument is the name of the struct to declare, written as a name"))
|
_ (refuse "defedn's first argument is the name of the struct to declare, written as a name"))
|
||||||
_ (refuse "defedn's second argument is the path to the data file, written as a string literal — the file is read while this is being compiled, so there is nothing here to compute a path from"))))
|
_ (refuse "defedn's second argument is the path to the data file, written as a string literal — the file is read while this is being compiled, so there is nothing here to compute a path from"))))
|
||||||
|
|
||||||
|
|||||||
52
vendor/edn/read.flan
vendored
52
vendor/edn/read.flan
vendored
@ -93,44 +93,44 @@
|
|||||||
(= (.kind t) tok-symbol) (keyword (.text t))
|
(= (.kind t) tok-symbol) (keyword (.text t))
|
||||||
|
|
||||||
(= (.kind t) tok-vec-open)
|
(= (.kind t) tok-vec-open)
|
||||||
(let [items (vec-new dyn)
|
(let [items (vec-new dyn)
|
||||||
u (next c)]
|
u (next c)]
|
||||||
(while (and (ok? c)
|
(while (and (ok? c)
|
||||||
(!= (.kind u) tok-vec-close)
|
(!= (.kind u) tok-vec-close)
|
||||||
(!= (.kind u) tok-eof))
|
(!= (.kind u) tok-eof))
|
||||||
(push items (read-value c u))
|
(push items (read-value c u))
|
||||||
(set u (next c)))
|
(set u (next c)))
|
||||||
items)
|
items)
|
||||||
|
|
||||||
;; A set ends on tok-map-close, because `}` is the byte that ends it. The
|
;; A set ends on tok-map-close, because `}` is the byte that ends it. The
|
||||||
;; dedup is the map's own: put replaces the value of an equal key, so a
|
;; dedup is the map's own: put replaces the value of an equal key, so a
|
||||||
;; set with a duplicate in it never exists and #{[0 0] [0 0]} is one
|
;; set with a duplicate in it never exists and #{[0 0] [0 0]} is one
|
||||||
;; element by structure, not by header identity.
|
;; element by structure, not by header identity.
|
||||||
(= (.kind t) tok-set-open)
|
(= (.kind t) tok-set-open)
|
||||||
(let [s {}
|
(let [s {}
|
||||||
u (next c)]
|
u (next c)]
|
||||||
(while (and (ok? c)
|
(while (and (ok? c)
|
||||||
(!= (.kind u) tok-map-close)
|
(!= (.kind u) tok-map-close)
|
||||||
(!= (.kind u) tok-eof))
|
(!= (.kind u) tok-eof))
|
||||||
(put s (read-value c u) true)
|
(put s (read-value c u) true)
|
||||||
(set u (next c)))
|
(set u (next c)))
|
||||||
s)
|
s)
|
||||||
|
|
||||||
;; A map's key is a whole value, read by the same recursion as anything
|
;; A map's key is a whole value, read by the same recursion as anything
|
||||||
;; else — :a and "a" are two keys, [0 0] can key a map, and the old
|
;; else — :a and "a" are two keys, [0 0] can key a map, and the old
|
||||||
;; (Map string Value) narrowing that collapsed them is gone with the type
|
;; (Map string Value) narrowing that collapsed them is gone with the type
|
||||||
;; that forced it.
|
;; that forced it.
|
||||||
(= (.kind t) tok-map-open)
|
(= (.kind t) tok-map-open)
|
||||||
(let [m {}
|
(let [m {}
|
||||||
k (next c)]
|
k (next c)]
|
||||||
(while (and (ok? c)
|
(while (and (ok? c)
|
||||||
(!= (.kind k) tok-map-close)
|
(!= (.kind k) tok-map-close)
|
||||||
(!= (.kind k) tok-eof))
|
(!= (.kind k) tok-eof))
|
||||||
(let [key (read-value c k)
|
(let [key (read-value c k)
|
||||||
u (next c)]
|
u (next c)]
|
||||||
(put m key (read-value c u)))
|
(put m key (read-value c u)))
|
||||||
(set k (next c)))
|
(set k (next c)))
|
||||||
m)
|
m)
|
||||||
|
|
||||||
:else nil))
|
:else nil))
|
||||||
|
|
||||||
|
|||||||
82
vendor/json/provide.flan
vendored
82
vendor/json/provide.flan
vendored
@ -177,8 +177,8 @@
|
|||||||
(let [t (next c)]
|
(let [t (next c)]
|
||||||
(when (not (ok? c))
|
(when (not (ok? c))
|
||||||
(return (derived-bad
|
(return (derived-bad
|
||||||
(joined3 "the data file could not be read at " (where src (error-pos c))
|
(joined3 "the data file could not be read at " (where src (error-pos c))
|
||||||
(joined ": " (error-message (.err c)))))))
|
(joined ": " (error-message (.err c)))))))
|
||||||
(cond
|
(cond
|
||||||
(= (.kind t) tok-int) (ok-derived `i64 (form-nil) `(need-int c))
|
(= (.kind t) tok-int) (ok-derived `i64 (form-nil) `(need-int c))
|
||||||
(= (.kind t) tok-float) (ok-derived `f64 (form-nil) `(need-float c))
|
(= (.kind t) tok-float) (ok-derived `f64 (form-nil) `(need-float c))
|
||||||
@ -191,12 +191,12 @@
|
|||||||
(= (.kind t) tok-null)
|
(= (.kind t) tok-null)
|
||||||
(derived-bad
|
(derived-bad
|
||||||
(joined3 "the null at " (where src (.pos t))
|
(joined3 "the null at " (where src (.pos t))
|
||||||
" has no type to derive — a field that is sometimes absent is not something a struct can hold, so give it a value in the file or take the key out"))
|
" has no type to derive — a field that is sometimes absent is not something a struct can hold, so give it a value in the file or take the key out"))
|
||||||
|
|
||||||
:else
|
:else
|
||||||
(derived-bad
|
(derived-bad
|
||||||
(joined3 "the value at " (where src (.pos t))
|
(joined3 "the value at " (where src (.pos t))
|
||||||
" is not one defjson derives a type from — an object, an array, a number, a boolean or a string")))))
|
" is not one defjson derives a type from — an object, an array, a number, a boolean or a string")))))
|
||||||
|
|
||||||
;; An array, whose elements must all come to the same type. The first decides;
|
;; An array, whose elements must all come to the same type. The first decides;
|
||||||
;; every one after it is compared against that, and both positions are named
|
;; every one after it is compared against that, and both positions are named
|
||||||
@ -205,8 +205,8 @@
|
|||||||
(defn- derive-array [c (Ptr Cursor) name string at-pos i32 src [u8]] Derived
|
(defn- derive-array [c (Ptr Cursor) name string at-pos i32 src [u8]] Derived
|
||||||
(when (at-byte? c \])
|
(when (at-byte? c \])
|
||||||
(return (derived-bad
|
(return (derived-bad
|
||||||
(joined3 "the empty array at " (where src at-pos)
|
(joined3 "the empty array at " (where src at-pos)
|
||||||
" has no element to derive an element type from — defjson reads the shape out of the data, and an empty collection carries none"))))
|
" has no element to derive an element type from — defjson reads the shape out of the data, and an empty collection carries none"))))
|
||||||
(let [head (derive c (joined name "-item") src)]
|
(let [head (derive c (joined name "-item") src)]
|
||||||
(when (bad? head)
|
(when (bad? head)
|
||||||
(return head))
|
(return head))
|
||||||
@ -218,12 +218,12 @@
|
|||||||
(return item))
|
(return item))
|
||||||
(when (not (same-type? (.ty head) (.ty item)))
|
(when (not (same-type? (.ty head) (.ty item)))
|
||||||
(return (derived-bad
|
(return (derived-bad
|
||||||
(joined3 (joined3 "the array at " (where src at-pos)
|
(joined3 (joined3 "the array at " (where src at-pos)
|
||||||
" holds more than one shape: element 0 is ")
|
" holds more than one shape: element 0 is ")
|
||||||
(render (.ty head))
|
(render (.ty head))
|
||||||
(joined3 (joined3 " and element " (i64->string n) " is ")
|
(joined3 (joined3 " and element " (i64->string n) " is ")
|
||||||
(render (.ty item))
|
(render (.ty item))
|
||||||
". Every element of an array has to be the same shape, because the (Vec T) it becomes has one element type")))))
|
". Every element of an array has to be the same shape, because the (Vec T) it becomes has one element type")))))
|
||||||
(comma c)
|
(comma c)
|
||||||
(set n (+ n 1))))
|
(set n (+ n 1))))
|
||||||
(expect c tok-array-close)
|
(expect c tok-array-close)
|
||||||
@ -238,21 +238,21 @@
|
|||||||
;; better for it too.
|
;; better for it too.
|
||||||
(ok-derived ty (with-decl (.decls head) `(defn ~cn [a Allocator] ~ty
|
(ok-derived ty (with-decl (.decls head) `(defn ~cn [a Allocator] ~ty
|
||||||
(vec-new a)))
|
(vec-new a)))
|
||||||
`(let [xs (~cn a)]
|
`(let [xs (~cn a)]
|
||||||
(expect c tok-array-open)
|
(expect c tok-array-open)
|
||||||
(while (and (ok? c) (not (at-byte? c \])))
|
(while (and (ok? c) (not (at-byte? c \])))
|
||||||
(push xs ~read1)
|
(push xs ~read1)
|
||||||
(comma c))
|
(comma c))
|
||||||
(expect c tok-array-close)
|
(expect c tok-array-close)
|
||||||
xs))))))
|
xs))))))
|
||||||
|
|
||||||
;; ── An object, which is a struct ────────────────────────────────────
|
;; ── An object, which is a struct ────────────────────────────────────
|
||||||
|
|
||||||
(defn- derive-object [c (Ptr Cursor) name string at-pos i32 src [u8]] Derived
|
(defn- derive-object [c (Ptr Cursor) name string at-pos i32 src [u8]] Derived
|
||||||
(when (at-byte? c \})
|
(when (at-byte? c \})
|
||||||
(return (derived-bad
|
(return (derived-bad
|
||||||
(joined3 "the empty object at " (where src at-pos)
|
(joined3 "the empty object at " (where src at-pos)
|
||||||
" has no members to derive fields from — a struct with no fields is not a shape anything can be read into"))))
|
" has no members to derive fields from — a struct with no fields is not a shape anything can be read into"))))
|
||||||
(let [fields (vec-new Form) ; the defstruct's [name type ...] vector
|
(let [fields (vec-new Form) ; the defstruct's [name type ...] vector
|
||||||
clauses (vec-new Form) ; the reader's cond: test, body, test, body
|
clauses (vec-new Form) ; the reader's cond: test, body, test, body
|
||||||
missing (vec-new Form) ; one per field, checked when the object closes
|
missing (vec-new Form) ; one per field, checked when the object closes
|
||||||
@ -262,12 +262,12 @@
|
|||||||
(let [k (next c)]
|
(let [k (next c)]
|
||||||
(when (not (ok? c))
|
(when (not (ok? c))
|
||||||
(return (derived-bad
|
(return (derived-bad
|
||||||
(joined3 "the data file could not be read at " (where src (error-pos c))
|
(joined3 "the data file could not be read at " (where src (error-pos c))
|
||||||
(joined ": " (error-message (.err c)))))))
|
(joined ": " (error-message (.err c)))))))
|
||||||
(when (!= (.kind k) tok-string)
|
(when (!= (.kind k) tok-string)
|
||||||
(return (derived-bad
|
(return (derived-bad
|
||||||
(joined3 "the object at " (joined3 (where src at-pos) " has a member at " (where src (.pos k)))
|
(joined3 "the object at " (joined3 (where src at-pos) " has a member at " (where src (.pos k)))
|
||||||
" whose name is not a string, which JSON requires"))))
|
" whose name is not a string, which JSON requires"))))
|
||||||
;; The comparison in the generated reader is against the token's RAW
|
;; The comparison in the generated reader is against the token's RAW
|
||||||
;; text, which costs no allocation per key. That is only the same
|
;; text, which costs no allocation per key. That is only the same
|
||||||
;; question as "is this the field" when the name has no escape in it —
|
;; question as "is this the field" when the name has no escape in it —
|
||||||
@ -277,12 +277,12 @@
|
|||||||
(let [raw (.text k)]
|
(let [raw (.text k)]
|
||||||
(when (has-escape? raw)
|
(when (has-escape? raw)
|
||||||
(return (derived-bad
|
(return (derived-bad
|
||||||
(joined3 "the member name at " (where src (.pos k))
|
(joined3 "the member name at " (where src (.pos k))
|
||||||
" has an escape in it. A generated reader compares a key against the bytes as written, which costs nothing per key and is only the same question when the name is written plainly — so this one is refused rather than matched wrongly"))))
|
" has an escape in it. A generated reader compares a key against the bytes as written, which costs nothing per key and is only the same question when the name is written plainly — so this one is refused rather than matched wrongly"))))
|
||||||
(when (not (name-like? raw))
|
(when (not (name-like? raw))
|
||||||
(return (derived-bad
|
(return (derived-bad
|
||||||
(joined3 "the member name at " (where src (.pos k))
|
(joined3 "the member name at " (where src (.pos k))
|
||||||
" is not a name a program could write, so there is no field it can become. A struct's fields are named; letters, digits, - and ? are what a name is made of"))))
|
" is not a name a program could write, so there is no field it can become. A struct's fields are named; letters, digits, - and ? are what a name is made of"))))
|
||||||
(expect c tok-colon)
|
(expect c tok-colon)
|
||||||
(let [fname (copy-of raw)
|
(let [fname (copy-of raw)
|
||||||
d (derive c (joined3 name "-" fname) src)]
|
d (derive c (joined3 name "-" fname) src)]
|
||||||
@ -303,11 +303,11 @@
|
|||||||
;; beside the field, so the two cannot fall out of step the way a
|
;; beside the field, so the two cannot fall out of step the way a
|
||||||
;; parallel list of names would.
|
;; parallel list of names would.
|
||||||
(push missing
|
(push missing
|
||||||
`(when (= (bit-and seen ~bit) 0)
|
`(when (= (bit-and seen ~bit) 0)
|
||||||
(signal (SchemaDrift {.field ~lit
|
(signal (SchemaDrift {.field ~lit
|
||||||
.struct ~(Form.Str {.s name})
|
.struct ~(Form.Str {.s name})
|
||||||
.extra? false
|
.extra? false
|
||||||
.pos (.pos close)})))))
|
.pos (.pos close)})))))
|
||||||
(comma c)
|
(comma c)
|
||||||
(set idx (+ idx 1))))))
|
(set idx (+ idx 1))))))
|
||||||
(expect c tok-object-close)
|
(expect c tok-object-close)
|
||||||
@ -316,12 +316,12 @@
|
|||||||
;; program that declines to handle the condition still reads the rest.
|
;; program that declines to handle the condition still reads the rest.
|
||||||
(push clauses `:else)
|
(push clauses `:else)
|
||||||
(push clauses
|
(push clauses
|
||||||
`(do (signal (SchemaDrift {.field (match (string-of k) (Some s) s None "")
|
`(do (signal (SchemaDrift {.field (match (string-of k) (Some s) s None "")
|
||||||
.struct ~(Form.Str {.s name})
|
.struct ~(Form.Str {.s name})
|
||||||
.extra? true
|
.extra? true
|
||||||
.pos (.pos k)}))
|
.pos (.pos k)}))
|
||||||
(when (not (skip-value c))
|
(when (not (skip-value c))
|
||||||
(return out))))
|
(return out))))
|
||||||
(let [sname (Form.Sym {.s name})
|
(let [sname (Form.Sym {.s name})
|
||||||
rname (Form.Sym {.s (joined "read-" name)})
|
rname (Form.Sym {.s (joined "read-" name)})
|
||||||
struct `(defstruct ~sname ~(Form.Vec {.xs (slice fields)}))
|
struct `(defstruct ~sname ~(Form.Vec {.xs (slice fields)}))
|
||||||
@ -420,7 +420,7 @@
|
|||||||
(Some src) (provide name path src)
|
(Some src) (provide name path src)
|
||||||
None (refuse
|
None (refuse
|
||||||
(joined3 "there is no file at " path
|
(joined3 "there is no file at " path
|
||||||
", read relative to the file this defjson is written in — the same place (embed \"...\") would look")))
|
", read relative to the file this defjson is written in — the same place (embed \"...\") would look")))
|
||||||
_ (refuse "defjson's first argument is the name of the struct to declare, written as a name"))
|
_ (refuse "defjson's first argument is the name of the struct to declare, written as a name"))
|
||||||
_ (refuse "defjson's second argument is the path to the data file, written as a string literal — the file is read while this is being compiled, so there is nothing here to compute a path from"))))
|
_ (refuse "defjson's second argument is the path to the data file, written as a string literal — the file is read while this is being compiled, so there is nothing here to compute a path from"))))
|
||||||
|
|
||||||
|
|||||||
24
vendor/raylib/raylib.flan
vendored
24
vendor/raylib/raylib.flan
vendored
@ -551,7 +551,7 @@
|
|||||||
"CheckCollisionCircleRec")
|
"CheckCollisionCircleRec")
|
||||||
|
|
||||||
(declare-c collision-circle-line? [center Vector2 radius f32
|
(declare-c collision-circle-line? [center Vector2 radius f32
|
||||||
p1 Vector2 p2 Vector2] bool "CheckCollisionCircleLine")
|
p1 Vector2 p2 Vector2] bool "CheckCollisionCircleLine")
|
||||||
|
|
||||||
(declare-c collision-point-rec?
|
(declare-c collision-point-rec?
|
||||||
[point Vector2 rec Rectangle] bool
|
[point Vector2 rec Rectangle] bool
|
||||||
@ -562,13 +562,13 @@
|
|||||||
"CheckCollisionPointCircle")
|
"CheckCollisionPointCircle")
|
||||||
|
|
||||||
(declare-c collision-point-triangle? [point Vector2 a Vector2 b Vector2
|
(declare-c collision-point-triangle? [point Vector2 a Vector2 b Vector2
|
||||||
c Vector2] bool "CheckCollisionPointTriangle")
|
c Vector2] bool "CheckCollisionPointTriangle")
|
||||||
|
|
||||||
;; `threshold` is in pixels, and it is not optional in practice: raylib's test
|
;; `threshold` is in pixels, and it is not optional in practice: raylib's test
|
||||||
;; is a distance comparison in floats, so a point exactly on the line fails at
|
;; is a distance comparison in floats, so a point exactly on the line fails at
|
||||||
;; a threshold of 0. 1 is the useful smallest value.
|
;; a threshold of 0. 1 is the useful smallest value.
|
||||||
(declare-c collision-point-line? [point Vector2 p1 Vector2 p2 Vector2
|
(declare-c collision-point-line? [point Vector2 p1 Vector2 p2 Vector2
|
||||||
threshold i32] bool "CheckCollisionPointLine")
|
threshold i32] bool "CheckCollisionPointLine")
|
||||||
|
|
||||||
;; The one binding whose Flan face is not raylib's, and one of only two in
|
;; The one binding whose Flan face is not raylib's, and one of only two in
|
||||||
;; this file with a hand-written wrapper on top. A Flan slice crosses as
|
;; this file with a hand-written wrapper on top. A Flan slice crosses as
|
||||||
@ -685,12 +685,12 @@
|
|||||||
"DrawTextureV")
|
"DrawTextureV")
|
||||||
|
|
||||||
(declare-c draw-texture-ex [texture Texture2D position Vector2 rotation f32
|
(declare-c draw-texture-ex [texture Texture2D position Vector2 rotation f32
|
||||||
scale f32 tint Color] "DrawTextureEx")
|
scale f32 tint Color] "DrawTextureEx")
|
||||||
|
|
||||||
;; A negative source width or height flips the sprite, which is how a sheet is
|
;; A negative source width or height flips the sprite, which is how a sheet is
|
||||||
;; drawn facing the other way without a second image.
|
;; drawn facing the other way without a second image.
|
||||||
(declare-c draw-texture-rec [texture Texture2D source Rectangle position Vector2
|
(declare-c draw-texture-rec [texture Texture2D source Rectangle position Vector2
|
||||||
tint Color] "DrawTextureRec")
|
tint Color] "DrawTextureRec")
|
||||||
|
|
||||||
;; The two above, in one call, and the only one of the four that both takes a
|
;; The two above, in one call, and the only one of the four that both takes a
|
||||||
;; source rectangle and scales: `source` picks a cell out of an atlas, `dest`
|
;; source rectangle and scales: `source` picks a cell out of an atlas, `dest`
|
||||||
@ -933,10 +933,10 @@
|
|||||||
;; Angles are degrees, clockwise from the +x axis, and `segments` is how many
|
;; Angles are degrees, clockwise from the +x axis, and `segments` is how many
|
||||||
;; straight pieces the arc is made of — 0 lets raylib pick from the radius.
|
;; straight pieces the arc is made of — 0 lets raylib pick from the radius.
|
||||||
(declare-c draw-ring [center Vector2 inner f32 outer f32 start f32 end f32
|
(declare-c draw-ring [center Vector2 inner f32 outer f32 start f32 end f32
|
||||||
segments i32 color Color] "DrawRing")
|
segments i32 color Color] "DrawRing")
|
||||||
|
|
||||||
(declare-c draw-ring-lines [center Vector2 inner f32 outer f32 start f32 end f32
|
(declare-c draw-ring-lines [center Vector2 inner f32 outer f32 start f32 end f32
|
||||||
segments i32 color Color] "DrawRingLines")
|
segments i32 color Color] "DrawRingLines")
|
||||||
|
|
||||||
;; Counter-clockwise, and raylib means it: the clockwise winding is culled and
|
;; Counter-clockwise, and raylib means it: the clockwise winding is culled and
|
||||||
;; draws nothing at all, which looks exactly like a broken binding.
|
;; draws nothing at all, which looks exactly like a broken binding.
|
||||||
@ -968,15 +968,15 @@
|
|||||||
;; `roundness` is 0 to 1 as a fraction of the shorter side, so 0 is a plain
|
;; `roundness` is 0 to 1 as a fraction of the shorter side, so 0 is a plain
|
||||||
;; rectangle and 1 is a stadium.
|
;; rectangle and 1 is a stadium.
|
||||||
(declare-c draw-rectangle-rounded [rec Rectangle roundness f32 segments i32
|
(declare-c draw-rectangle-rounded [rec Rectangle roundness f32 segments i32
|
||||||
color Color] "DrawRectangleRounded")
|
color Color] "DrawRectangleRounded")
|
||||||
|
|
||||||
;; No thickness here — see the section note. The `-ex` form below is the one
|
;; No thickness here — see the section note. The `-ex` form below is the one
|
||||||
;; that takes it.
|
;; that takes it.
|
||||||
(declare-c draw-rectangle-rounded-lines [rec Rectangle roundness f32 segments i32
|
(declare-c draw-rectangle-rounded-lines [rec Rectangle roundness f32 segments i32
|
||||||
color Color] "DrawRectangleRoundedLines")
|
color Color] "DrawRectangleRoundedLines")
|
||||||
|
|
||||||
(declare-c draw-rectangle-rounded-lines-ex [rec Rectangle roundness f32
|
(declare-c draw-rectangle-rounded-lines-ex [rec Rectangle roundness f32
|
||||||
segments i32 thick f32 color Color] "DrawRectangleRoundedLinesEx")
|
segments i32 thick f32 color Color] "DrawRectangleRoundedLinesEx")
|
||||||
|
|
||||||
;; ── A slice where raylib wants a pointer and a count ─────────────────
|
;; ── A slice where raylib wants a pointer and a count ─────────────────
|
||||||
;;
|
;;
|
||||||
@ -1524,7 +1524,7 @@
|
|||||||
;; so a one-character string is unaffected by it. raylib's own DrawTextEx adds
|
;; so a one-character string is unaffected by it. raylib's own DrawTextEx adds
|
||||||
;; it the same way measure-text-ex counts it, which is why the two agree.
|
;; it the same way measure-text-ex counts it, which is why the two agree.
|
||||||
(declare-c draw-text-ex [font Font text string position Vector2
|
(declare-c draw-text-ex [font Font text string position Vector2
|
||||||
font-size f32 spacing f32 tint Color] "DrawTextEx")
|
font-size f32 spacing f32 tint Color] "DrawTextEx")
|
||||||
|
|
||||||
;; Pure arithmetic over the font — no GL, no window — and therefore the one
|
;; Pure arithmetic over the font — no GL, no window — and therefore the one
|
||||||
;; thing in this section the acceptance table can assert. See the note above:
|
;; thing in this section the acceptance table can assert. See the note above:
|
||||||
@ -1568,7 +1568,7 @@
|
|||||||
"GetGlyphAtlasRec")
|
"GetGlyphAtlasRec")
|
||||||
|
|
||||||
(declare-c draw-text-codepoint [font Font codepoint i32 position Vector2
|
(declare-c draw-text-codepoint [font Font codepoint i32 position Vector2
|
||||||
font-size f32 tint Color] "DrawTextCodepoint")
|
font-size f32 tint Color] "DrawTextCodepoint")
|
||||||
|
|
||||||
;; DrawTextCodepoints and LoadFontData are not bound. The first is the slice
|
;; DrawTextCodepoints and LoadFontData are not bound. The first is the slice
|
||||||
;; problem again and adds nothing draw-text-ex does not already do from a
|
;; problem again and adds nothing draw-text-ex does not already do from a
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user