boot2

Playing with the boostrap
git clone https://git.ryansepassi.com/git/boot2.git
Log | Files | Refs | README

commit ca311eebbda0e929da9daacc946b20770cb90489
parent 5572d18365e4e8b17a2059a5b90feb81cc42ee27
Author: Ryan Sepassi <rsepassi@gmail.com>
Date:   Sat, 25 Apr 2026 16:26:31 -0700

docs: drop scheme-shell-todo audit (gaps closed)

The audit served its purpose: spawn-via-run bug fixed, set!/cond=>/length
gaps closed in scheme1, and the test caveats it tracked are addressed
by the recent test reorg.

Diffstat:
Ddocs/scheme-shell-todo.md | 214-------------------------------------------------------------------------------
1 file changed, 0 insertions(+), 214 deletions(-)

diff --git a/docs/scheme-shell-todo.md b/docs/scheme-shell-todo.md @@ -1,214 +0,0 @@ -# scheme1 → shell.scm TODO - -Checklist for getting `lisp/shell.scm` running under scheme1. - -**Workflow:** every item is red-green TDD. Add a failing -`tests/scheme1/NN-*.scm` (with `.expected-exit` and/or `.expected`) first, -run the suite to confirm it fails for the expected reason, then -implement until green. Multi-arch suite must stay clean before moving on. - -``` -# Run 1+ specific tests -scripts/run-tests.sh --suite scheme1 --arch aarch64 70-type-predicates -``` - -# Audit: deviations and known issues - -Everything below is a real bug, hack, or spec -gap that must be addressed before calling scheme1 shippable. - -## Open bugs - -- [ ] **Prelude `spawn` reached through `run` errors with "unbound variable" - in the parent.** `(run prog)` from user code fails even though - `(spawn prog)` inline at user level with the identical body works. - Root cause not identified (`apply_build_args` walking the variadic - list, closure env capture, or env extension with the dotted-tail - param `args` are all suspects). See test - `tests/scheme1/45-shell-spawn.scm` — it works around the bug by - redefining `spawn` at user level. Until this is understood, the - prelude's `spawn` and `run` are effectively unverified. - -## Spec features still missing - -Per LISP.md and LISP-C.md, but not implemented: - -- [ ] **Special forms missing**: `set!`, `pmatch`, `cond`'s - `=>` arrow form. - -### Records: target R7RS-small semantics - -Decision: track R7RS-small `define-record-type` exactly. The form -introduces a disjoint type and binds **only** these identifiers at -runtime: - -1. The constructor name (e.g. `make-point`) — a procedure. -2. The predicate name (e.g. `point?`) — a procedure. -3. One accessor per field (e.g. `point-x`) — a procedure. -4. One mutator per `(field acc mut)` clause (e.g. `set-point-y!`) — a - procedure. - -Explicitly **not** bound: the type name itself (`point` after -`(define-record-type point …)`). It is purely syntactic; the type -descriptor is not a user-visible value. There is no `record-type-of`, -no way to grab the TD from Scheme code, no `<point-td>`-style -generated binding. R7RS does not provide reflective access; we don't -add one. - -Also **not** in the user-facing API: - -- `record?`, `record-is-a?`, `record-type?` (LISP-C.md currently lists - these — drop from the spec). -- The six `%record-*` primitives (`%make-record-td`, `%make-record`, - `%record-ref`, `%record-set!`, `%record-is-a?`, `%record-td`). - Internal only; they must not appear in `prim_table`. - -Concrete cleanup tasks: - -- [ ] Remove `%make-record-td` / `%make-record` / `%record-ref` / - `%record-set!` / `%record-is-a?` / `%record-td` rows from - `prim_table` in `scheme1/scheme1.P1pp`. The parameterized record - PRIMs (`prim_ctor_entry`, `prim_pred_entry`, `prim_field_ref_entry`, - `prim_field_set_entry`) reach the entry labels directly via the - closure data slot, so removing the public bindings is local. - Tests `38-record-internal-prims.scm` (rewritten to assert unbound) - and `39-record-typename-unbound.scm` are the red-green guards. -- [ ] Update `docs/LISP-C.md`: - - In the `define-record-type` desugaring example (currently lines - 643+), drop the generated `(define <point-td> …)` line. Replace - the `%record-is-a?` / `%record-ref` / `%make-record` references - in the desugaring body with the parameterized-PRIM mechanism, or - flag them as illustrative pseudocode. The user-visible result is - just the four kinds of bindings listed above. - - Drop `record?`, `record-is-a?`, `record-type?` from the - Predicates / equality public-primitive list (line 660–662). Adjust - the "13" predicate count to 10. - - Move the `%record-*` count from "55 user-facing primitives plus 6 - internal record ops" to keep the 6 internal but ensure no - duplication or claim of public exposure. - -Note: `equal?` on records (test 59) keeps working — it walks the -internal layout via the runtime, not via user-callable primitives. - -## Hacks and fragile invariants - -These work today but are easy to break. - -- [ ] **Bytevector NUL-termination via headroom.** `bv_capacity_for` - returns the smallest power of two strictly greater than `n`. The - byte at index `length` is the zero-init NUL terminator and we hand - the raw `data_ptr` directly to syscalls expecting C strings - (`sys-openat`, `sys-execve`, the per-arg pointers in - `build_execve_argv`). If user code calls `bytevector-u8-set!` past - `length`, that NUL is gone and the next syscall reads garbage. - Capacity is never reset by `bytevector-copy!` or any other op, so - the invariant only protects fresh / never-overwritten bytevectors. - -- [ ] **`%record-*` primitives are exposed publicly** — see the - Records: target R7RS-small semantics section above for the full - fix. Tracked there to keep desugaring + spec + tests + table - changes together. - -## Test suite caveats - -Issues *in* the test files themselves that need fixing or revisiting -before the suite can be considered authoritative. - -- [ ] **`tests/scheme1/15-dot-symbol.scm`** — defines `.foo` (a leading - `.` identifier). LISP.md says "a lone `.` is **not** a symbol — it's - reserved for dotted-pair syntax", but the spec is silent on whether - `.foo` is admissible. Behavior depends on whether the byte after `.` - is whitespace/paren (handled by `parse_list`'s peek). Useful as a - regression test for the dotted-tail detector but not necessarily - desired surface syntax. - -- [ ] **`tests/scheme1/19-letstar.scm`** — comment claims "outer x; - let*'s x must shadow inside the body" but the test only checks the - inner shadow path. Nothing exercises that the outer `x` is *not* - affected after the `let*` body returns. - -- [ ] **`tests/scheme1/20-letrec.scm`** — uses `(if n n (f #t))` to test - letrec self-reference. Recurses *once* (n=44 → truthy → returns 44) - so it doesn't actually trigger the recursive case. The comment - acknowledges the workaround ("Without numeric primitives we - terminate by passing #t at the recursive call"). Needs a real - recursion test now that the let family + arith primitives are - available; `21-letrec-recursion.scm` partially fills this. - -- [ ] **`tests/scheme1/22-named-let.scm`** — recursion is bounded by a - flag (`first`) flipping from `#t` to `#f`. Deep iteration not - exercised. - -- [ ] **`tests/scheme1/27-apply.scm`** — only tests 2-arg - `(apply f arglist)` and 3-arg `(apply f x arglist)`. `(apply f)` is - unspecified; `(apply f a b … last)` for N>3 is unverified. - -- [ ] **`tests/scheme1/40-sys-argv.scm`** — hard-codes `expected-exit = - 2`, the count of argv entries the runner happens to pass - (`./binary tests/scheme1/40-sys-argv.scm`). Any change to - `scripts/run-tests.sh`'s invocation or a wrapper that injects extra - args breaks this test silently. - -- [ ] **`tests/scheme1/41-fileio.scm`** — opens itself by reading - `(car (cdr (sys-argv)))` and passing the bytevector as a path. - Relies on the `bv_capacity_for` headroom invariant for NUL - termination (no explicit `chars->bv`). Doesn't exercise the - `(#f . errno)` branch of `sys-openat` (e.g., a non-existent path). - Hard-codes `O_RDONLY = 0` and `mode = 0` instead of using named - constants. - -- [ ] **`tests/scheme1/42-clone-wait.scm`** — bypasses `sys-wait` / - `decode-wait-status` entirely; reads `siginfo_t.si_status` (offset - 24) directly from the buffer with `bytevector-u8-ref`. Encodes - Linux-x86_64-and-aarch64 siginfo layout; non-portable to other - Linux ABIs and to any non-Linux target. - -- [ ] **`tests/scheme1/43-prelude.scm`** — verifies `for-each` only by - running `(for-each (lambda (x) x) ys)` and checking it doesn't - error; doesn't check that `for-each` actually invokes the lambda - for each element (no side-effect verification). - -- [ ] **`tests/scheme1/44-shell-run.scm`** — name is misleading. It - tests `sys-wait` + `decode-wait-status` against a `sys-clone` child - but never calls `run`. `run` is what test 45 was supposed to cover, - and it doesn't because of the spawn-via-run bug. - -- [ ] **`tests/scheme1/45-shell-spawn.scm`** — works around the prelude - spawn bug by redefining `spawn` at user level. The prelude's - `spawn` / `run` are therefore covered by zero passing tests. - -- [ ] **`tests/scheme1/38-record-internal-prims.scm`** — rewritten to - assert that `%make-record-td` is **unbound** at user level, matching - the R7RS target (see the records spec section above). Currently red: - the prim is still in `prim_table`. Goes green once the table cleanup - lands. - -- [ ] **`tests/scheme1/39-record-typename-unbound.scm`** — asserts - `(define-record-type point …)` does not bind `point` to anything at - runtime; bare reference is unbound. Currently green (matches - existing impl) and protects against regressions that would add a - hidden TD binding. - -- [ ] **No test verifies `(set-car! …)` / `(set-cdr! …)`** — the - primitives don't exist; spec requires them. - -- [ ] **No test verifies that mutating a literal pair (`'(1 2 3)`) is - UB** — undefined behavior is policy, but the policy isn't pinned - down by a test. - -- [ ] **No test verifies tail-call correctness on deep recursion** — - named let, `letrec`, and the eval/apply tail positions all rely on - `%tail`/`%tailr`, but nothing recurses thousands of times to confirm - no host-stack growth. - -- [ ] **No `(define x …)` followed by `(set! x …)` test** because - `set!` doesn't exist. - -- [ ] **No quoted-pair test (`'(1 . 2)`)** — only quoted lists are - tested. The reader handles dotted pairs but no test pins this. - -- [ ] **`tests/scheme1/16-cond.scm`** — verifies short-circuit in the - positive direction (later truthy clauses don't fire). Doesn't - verify that a `(cond)` with no matching clause and no `else` returns - UNSPEC (or whatever the policy is — currently it does, but - unspecified by spec).