boot2

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

commit e25b794c8b51b72531be053c2f73e2f7d47374df
parent f93d3f2de8178ba649e888096330c50cb1489180
Author: Ryan Sepassi <rsepassi@gmail.com>
Date:   Tue, 21 Apr 2026 16:28:03 -0700

lisp.M1 step 10h: enable map/filter/fold prelude

Make skip_ws treat NUL as whitespace so adjacent M1 "..." chunks
(each carrying a trailing NUL from the literal) stitch together,
then split the prelude across 7 chunks to fit M0's quoted-literal
buffer. _start calls eval_source on [prelude_src, prelude_src_end)
before the user script. p1_gen gets SUB r2,r2,r1 to materialize
the prelude length at the call site. tests/lisp/16-prelude.scm
added to LISP_TESTS; 13/13 pass on aarch64, amd64, riscv64.

Diffstat:
MMakefile | 4++--
Mdocs/LISP.md | 38++++++++++++++++----------------------
Msrc/lisp.M1 | 26++++++++++++++++++++++----
Msrc/p1_gen.py | 1+
4 files changed, 41 insertions(+), 28 deletions(-)

diff --git a/Makefile b/Makefile @@ -197,8 +197,8 @@ LISP_TESTS := \ tests/lisp/13-vector.scm \ tests/lisp/14-io.scm \ tests/lisp/14-tagpred.scm \ - tests/lisp/15-pred.scm -# tests/lisp/16-prelude.scm — re-enable once LISP.md step 10h unblocks + tests/lisp/15-pred.scm \ + tests/lisp/16-prelude.scm test-lisp: | $(IMAGE_STAMP) @$(MAKE) --no-print-directory PROG=lisp ARCH=$(ARCH) build/$(ARCH)/lisp diff --git a/docs/LISP.md b/docs/LISP.md @@ -504,9 +504,10 @@ Status legend: `[x]` done · `[~]` in progress · `[ ]` not started. ~400 LOC. 4. [x] **Reader (core).** End-to-end `source → sexpr` for lists, decimal fixnums, interned symbols, `;` comments, with line/col tracking for - diagnostics. Extended syntax (quotes, strings, `#t`/`#f`, `#\char`, - `#( … )`, improper `.` tail, hex/negative fixnums) and the - source-location side table land in later steps. ~500 LOC. + diagnostics. Extended syntax (quotes, `#\char`, `#( … )`, improper + `.` tail, hex/negative fixnums) and the source-location side table + land in later steps. (`#t`/`#f` landed in 10c; string literals in + 10e.) ~500 LOC. 5. [x] **Printer.** `display`, `write`, minimal `format`. Closes a read-print cycle. ~300 LOC. 6. [x] **Eval (non-tail).** Self-evaluators, lookup, `if`, `begin`, @@ -520,7 +521,7 @@ Status legend: `[x]` done · `[~]` in progress · `[ ]` not started. test-lisp` (single arch) and `make test-lisp-all` (tri-arch diff); pass = exit 0 and expected stdout. Locks in regression coverage before the feature surface grows. -10. [~] **Primitives (~40).** Broken into sub-steps; ~1200 P1 LOC total +10. [x] **Primitives (~40).** Broken into sub-steps; ~1200 P1 LOC total (~200 harness + ~1000 primitives). Earlier ~500 estimate was optimistic. - [x] **10a. FFI harness.** `make_primitive` constructor (type 5 @@ -542,8 +543,6 @@ Status legend: `[x]` done · `[~]` in progress · `[ ]` not started. length list? append reverse assoc member`. - [x] **10e. String primitives.** `string? string-length string-ref substring string-append string->symbol symbol->string`. - Bodies land and pass isolated smoke tests on aarch64; full - `12-string.scm` regression blocked on 10h. - [x] **10f. Vector primitives.** `make-vector vector-ref vector-set! vector-length vector->list list->vector`. Adds `make_vector` runtime helper (absent before 10f). `make_vector` @@ -554,22 +553,17 @@ Status legend: `[x]` done · `[~]` in progress · `[ ]` not started. `format` dispatches `~a ~s ~d ~%`. `equal?` recurses on pairs/strings/vectors; non-allocating. `apply` primitive re-enters the internal `apply` label. - - [~] **10h. Lisp prelude.** ~20 lines of Scheme defining `map`, - `filter`, `fold` in terms of the primitives above. Embedded - in BSS as a string; `_start` parses and evaluates it right - after 10b finishes. **Blocker:** enabling the prelude - `eval_source` call with any non-zero length breaks every - subsequent script eval with `error: unbound symbol`, even for - bare-literal scripts that reference no symbols. Suspects: - (a) `eval_source` save/restore of `src_*` globals misbehaves - on a second invocation, or (b) the M0 256-byte quoted-literal - buffer chops the long `(define map …)` lines. Also: post-fix, - re-run full 13-test `make ARCH=aarch64 test-lisp`, then port - to amd64 + riscv64. -11. [ ] **Reader extensions.** `'`/`` ` ``/`,`/`,@`, strings, `#\char`, - `#( … )`, improper `.` tail, hex and negative fixnums. (`#t`/`#f` - land early in 10c.) Source-location side table explicitly - deferred to step 16. + - [x] **10h. Lisp prelude.** Scheme definitions of `map`, `filter`, + `fold` embedded as adjacent `"…"` chunks between `:prelude_src` + and `:prelude_src_end`; `_start` calls `eval_source` on the span + before the script eval. M1's `"…"` form appends a NUL to each + chunk, so `skip_ws` treats `\0` as whitespace — the chunks stitch + together transparently. Gate test `16-prelude.scm` passes on all + three arches. +11. [ ] **Reader extensions.** `'`/`` ` ``/`,`/`,@`, `#\char`, `#( … )`, + improper `.` tail, hex and negative fixnums. (`#t`/`#f` landed in + 10c; string literals in 10e.) Source-location side table + explicitly deferred to step 16. 12. [ ] **Eval extensions.** `set!`, `let`/`let*`/`letrec`, `cond`, `quasiquote`; inner `define` → `letrec`-shape rewrite. 13. [ ] **Mark-sweep GC.** Mark bitmap, root discipline, sweep, size-classed diff --git a/src/lisp.M1 b/src/lisp.M1 @@ -203,7 +203,14 @@ DEFINE ZERO32 '0000000000000000000000000000000000000000000000000000000000000000' li_br &_start_reg_prim_loop b :_start_reg_prim_done - ## Prelude eval disabled pending investigation — see LISP.md step 10h. + ## Evaluate the embedded Lisp prelude (map/filter/fold) so user + ## scripts see those bindings. + li_r1 &prelude_src + li_r2 &prelude_src_end + sub_r2,r2,r1 + li_br &eval_source + call + ## Evaluate the script read from argv[1]. mov_r1,r6 mov_r2,r7 @@ -1014,6 +1021,13 @@ DEFINE ZERO32 '0000000000000000000000000000000000000000000000000000000000000000' li_br &skip_ws_done beq_r0,r1 + ## NUL (0x00) — treated as whitespace so adjacent M1 "..." chunks + ## (which each emit a trailing NUL) concatenate cleanly in the + ## embedded prelude. + li_r1 %0 + li_br &skip_ws_eat + beq_r0,r1 + ## ' ' (0x20) li_r1 %32 li_br &skip_ws_eat @@ -4464,9 +4478,13 @@ DEFINE ZERO32 '0000000000000000000000000000000000000000000000000000000000000000' :str_prim_apply "apply" :prelude_src -"(define map (lambda (f xs) (if (null? xs) (quote ()) (cons (f (car xs)) (map f (cdr xs))))))" -"(define filter (lambda (p xs) (if (null? xs) (quote ()) (if (p (car xs)) (cons (car xs) (filter p (cdr xs))) (filter p (cdr xs))))))" -"(define fold (lambda (f acc xs) (if (null? xs) acc (fold f (f acc (car xs)) (cdr xs)))))" +"(define map (lambda (f xs) (if (null? xs) (quote ()) " +"(cons (f (car xs)) (map f (cdr xs))))))" +"(define filter (lambda (p xs) (if (null? xs) (quote ()) " +"(if (p (car xs)) (cons (car xs) (filter p (cdr xs))) " +"(filter p (cdr xs))))))" +"(define fold (lambda (f acc xs) (if (null? xs) acc " +"(fold f (f acc (car xs)) (cdr xs)))))" :prelude_src_end diff --git a/src/p1_gen.py b/src/p1_gen.py @@ -966,6 +966,7 @@ RRR_TABLE = ( ('ADD','r7','r1','r2'), ('SUB','r2','r1','r6'), ('SUB','r3','r1','r6'), + ('SUB','r2','r2','r1'), # prelude length = end - start ('REM','r1','r1','r2'), # bump-pointer + accumulator updates (originally kaem-minimal; # retained in case lisp uses them — lint catches dead entries)