Files
rose-ash/plans/scheme-on-sx.md
giles 26112f1003
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 19s
plans: scheme-on-sx progress log — 11 phases done, 296 tests
Loop closer documenting what 10 feature commits landed across the
session. Phase-by-phase outcomes captured, including the SX cond
multi-expression bug found and fixed during Phase 4.

Chisel ledger:
- env.sx already EXTRACTED with Scheme as third consumer
- evaluator.sx + quoting.sx second-consumer-ready for follow-on
  kit-extraction commits
- hygiene.sx still awaits the deferred Phase 6c (scope-set work)
- combiner.sx and short-circuit.sx don't apply (Scheme has no
  fexprs and uses syntactic and/or)

Deferred phases listed: full hygiene, nested quasi-depth, R7RS
module rich features, dotted-pair syntax, full call/cc-wind
interaction.

Loop's defining feature: lib/guest CHISELLING discipline — every
commit had a chisel note, and the cumulative work satisfies the
two-consumer rule for three new kit extractions.
2026-05-14 06:53:36 +00:00

14 KiB

Scheme-on-SX: the reflective-kit second-consumer port

The kernel-on-sx loop documented six reflective API candidates; two are now live (env.sx, class-chain.sx). Three more — evaluator.sx, hygiene.sx, quoting.sx — wait on a guest with operative-free lexical scope, hygienic syntax-transformer infrastructure, and quasiquote. Scheme is exactly that guest.

A correct R7RS-small implementation acts as second consumer for those three kits in one stroke. It also confirms a third independent consumer for env.sx (after Kernel + Tcl + Smalltalk), and a candidate fourth consumer for class-chain.sx (Scheme's record types have parent fields — though OO is non-core in Scheme so the fit is weaker).

Strategic note on combiner.sx

Scheme has no fexprs. combiner.sx's applicative/operative split is Kernel-specific machinery. Scheme is not a second consumer for combiner.sx — that file stays Kernel-only until a Maru, Klisp, or CL-fexpr port arrives. The current session's earlier claim that Scheme "unlocks four more reflective kits" was over-counted; the correct number is three.

Scope decisions

  • Target dialect: R7RS-small. Source-only — no images, no FFI, no C extensions, no JIT.
  • Numbers: integers + floats. Rationals optional (defer to phase N+1). Complex out.
  • Tail-call optimisation: required. Implemented via the existing SX CEK machinery — call recursion in the evaluator uses iterative cek-call rather than host recursion.
  • Continuations: call/cc required for R7RS. Use SX's call/cc primitive directly.
  • Hygienic macros: syntax-rules required. syntax-case deferred.
  • Char/string semantics: Unicode codepoints; surface API matches R7RS section 6.
  • I/O: minimal stub (display, write, newline, read) on SX's IO surface.
  • define-library: required for module testing; implementation reuses SX's define-library if it's exposed, else hand-rolls a flat module registry.

Architecture sketch

lib/scheme/parser.sx     — reader: numbers, strings, symbols, booleans,
                            chars #\c, vectors #(...), dotted-pairs (a . b),
                            quasi-quote sugar, datum comments #;, block
                            comments #| ... |#

lib/scheme/eval.sx       — eval-expr ENV: walks AST. Symbols → env-lookup.
                            Lists → look up head; if syntactic operator
                            (if/lambda/define/set!/quote/quasiquote/
                             let/let*/letrec/begin/cond/case/and/or/when/
                             unless/do), dispatch to native handler. Else
                            apply combiner (always applicative).

                          ENV is `lib/guest/reflective/env.sx` directly
                          — Scheme is the third consumer for env.sx with
                          NO adapter cfg (canonical wire shape).

lib/scheme/runtime.sx    — Standard environment, primitives, R7RS base.
                            Variadic arithmetic, list ops, string ops,
                            char ops, vector ops, define-record-type,
                            syntax-rules, etc.

lib/scheme/tests/        — Standard pattern: parse, eval, lambda+closure,
                            macros (syntax-rules), call/cc, define-library,
                            classic programs (factorial, Y, tree-walking,
                            named let, do-loop), R7RS conformance subset.

Roadmap

Phase 1 — Parser

  • Reader for R7RS lexical syntax: integers, floats, strings (with escapes), symbols (extended-identifier-character set), booleans #t/#f/#true/#false, characters #\c #\space #\newline, vectors #(...), dotted pairs (a . b), quote/quasiquote/unquote/unquote-splicing sugar (same reader macros as Kernel).
  • Datum comments #;<datum> (skip one whole expression).
  • Block comments #| ... |# (nestable).
  • Tests in lib/scheme/tests/parse.sx.

Phase 2 — Evaluator + env

  • scheme-eval EXPR ENV — primary entry, uses lib/guest/reflective/env.sx directly as the canonical scope chain. Third consumer for env.sx.
  • Self-evaluating: numbers, booleans, strings, chars, vectors.
  • Symbol lookup → refl-env-lookup-with.
  • List → look up head; syntactic operators dispatch natively; otherwise applicative call with evaluated args.
  • Tests in lib/scheme/tests/eval.sx.

Phase 3 — Syntactic operators

  • if, quote, set!, define (top-level + internal).
  • lambda — fixed-arity, rest-arg via dot, multi-body via implicit begin.
  • let, let*, letrec, letrec* — including named-let.
  • begin — implicit + explicit.
  • cond, case, when, unless, and, or, do.
  • Tests for each.

Phase 4 — Standard environment

  • Variadic + - * / and chained comparison.
  • Type predicates (R7RS number?, pair?, null?, symbol?, string?, procedure?, vector?, char?, boolean?).
  • List ops: cons car cdr caar cadr ... cddddr (or just a subset), list length reverse append map filter fold-left fold-right for-each.
  • String ops: string-length string-ref substring string-append string=? string<? char->integer integer->char.
  • Char ops: char->integer integer->char char-alphabetic? char-numeric? etc.
  • Vector ops: vector make-vector vector-length vector-ref vector-set! vector->list list->vector.
  • I/O: display write newline read.
  • Numerical: abs floor ceiling round truncate min max modulo quotient remainder gcd lcm expt.
  • Classic programs: factorial, fib, list reversal, tree map.

Phase 5 — call/cc + dynamic-wind

  • call-with-current-continuation / call/cc.
  • dynamic-wind.
  • with-exception-handler, raise, error.
  • Tests: escape continuations, multi-shot via call/cc (chosen via host SX call/cc).

Phase 6 — syntax-rules + hygiene

  • define-syntax, let-syntax, letrec-syntax.
  • syntax-rules pattern matching, ellipsis, template instantiation.
  • Hygiene: scope-set / lifted-symbol implementation. Second consumer for lib/guest/reflective/hygiene.sx extraction once that kit's API surface stabilises.
  • Tests: hygienic identifier capture, ellipsis patterns, recursive macros.

Phase 7 — Reflection: eval, interaction-environment, etc.

  • eval EXPR ENV — applicative form of the evaluator. Second consumer for lib/guest/reflective/evaluator.sx extraction.
  • interaction-environment, null-environment, scheme-report-environment.
  • environment? predicate.

Phase 8 — define-library + module hygiene

  • define-library, import, export.
  • cond-expand for feature-flag conditionals.
  • Tests: cross-library imports, identifier renaming.

Phase 9 — Records

  • define-record-type with constructor/predicate/accessors/mutators.
  • Tests: typical record idioms.

Phase 10 — Quasiquote runtime

  • Backquote walker with depth tracking. Second consumer for lib/guest/reflective/quoting.sx extraction.
  • Tests including nested quasiquote.

Phase 11 — Conformance + scoreboard

  • Curated R7RS test slice (Chibi, Larceny, or hand-picked).
  • lib/scheme/conformance.sh + scoreboard.
  • Drive conformance toward 100% on chosen slice.

Reflective kit consumption — explicit mapping

Kit When it lands How Scheme uses it
lib/guest/reflective/env.sx Phase 2 Direct — canonical wire shape, no cfg needed. Third consumer.
lib/guest/reflective/evaluator.sx Phase 7 (will trigger the extraction) Scheme's eval/interaction-environment/null-environment mirror the proposed refl-eval/refl-make-environment/refl-current-env triple. Second consumer → extraction unblocked.
lib/guest/reflective/hygiene.sx Phase 6 Scheme's hygienic syntax-rules is the canonical implementation of scope sets / lifted symbols. Second consumer for the deferred Shutt-style hygiene work — Scheme's hygiene goes BEYOND Kernel's by-default-static-env-extension into proper scope-set lifting. Drives the deferred research-grade kit.
lib/guest/reflective/quoting.sx Phase 10 Scheme's backquote walker is structurally identical to Kernel's knl-quasi-walk, with depth tracking added. Second consumer → extraction unblocked.
lib/guest/reflective/combiner.sx NEVER (no fexprs) Not applicable. Stays Kernel-only until a fexpr-having consumer arrives.
lib/guest/reflective/short-circuit.sx Possibly Phase 3 Scheme's and/or are syntactic, not operative; could be second consumer but adapter would need to bridge "macro that short-circuits" vs "operative that short-circuits". Marginal.

Ground rules

  • Scope: only lib/scheme/** and plans/scheme-on-sx.md and lib/guest/reflective/** (for extraction work). Don't edit spec/, hosts/, shared/, or other lib/<lang>/ directories.
  • Consume: lib/guest/lex.sx (character predicates), lib/guest/reflective/env.sx (scope chain), eventually evaluator.sx/hygiene.sx/quoting.sx once extracted with Scheme as second consumer.
  • Commits: one feature per commit. Short factual messages.
  • Tests: every phase ends with a test file. Conformance scoreboard at the end.
  • Branch: loops/scheme. Worktree pattern (already set up at /root/rose-ash-loops/scheme).
  • Substrate gaps: filed to sx-improvements.md, not fixed in this loop.

References

  • R7RS-small: https://small.r7rs.org/attachment/r7rs.pdf
  • Chibi Scheme — a small, readable R7RS implementation.
  • Dybvig, "Three Implementation Models for Scheme" — for the hygiene story.
  • Existing kernel-on-sx code in lib/kernel/ — much of the parser, evaluator structure, and env handling carries over near-verbatim because Kernel and Scheme share lexical scope.

Progress log

  • 2026-05-14 — Phases 1, 2, 3, 3.5, 4, 5abc, 6ab, 7, 8, 9, 10, 11 landed in one loop session. 296 Scheme tests across 9 suites; ~1830 LoC of substrate. Test runner + scoreboard at lib/scheme/test.sh and lib/scheme/scoreboard.md. Three reflective kits unlocked: env.sx extracted directly as third consumer, evaluator.sx and quoting.sx second-consumer-ready for the kit-extraction commits (kit code is documented in plans/kernel-on-sx.md; Scheme consumer code is in place).

Phase-by-phase outcomes

  • Phase 1 (Parser, 62 tests): R7RS lexical syntax with reader macros, three comment flavours (;, #;, #| |#).
  • Phase 2 (Eval + env third-consumer, 23 tests): scheme-make-env etc. are thin aliases for refl-env-* from lib/guest/reflective/env.sx. No adapter cfg needed — Scheme uses the canonical wire shape directly.
  • Phase 3 (if/define/set!/begin/lambda + closures, 24 tests): factorial 10 → 3628800, counter via closed-over set!, curried lambda.
  • Phase 3.5 (let/let*/cond/when/unless/and/or, 21 tests).
  • Phase 4 (standard env + set! bugfix, 82 tests): variadic arithmetic, type predicates, list/string/char/vector ops, higher-order combinators. Found and fixed an SX cond multi-expression branch bug affecting set!. Bugfix unblocked 4 silently-failing tests in Phase 3.
  • Phase 5a (call/cc, 8 tests): single-shot escape continuations.
  • Phase 5b (raise/guard/with-exception-handler/error, 12 tests): catch-once-then-rehandle-outside pattern avoids handler-self-raise loops.
  • Phase 5c (dynamic-wind, 5 tests): basic before-thunk-after with raise propagation. call/cc-escape tracking deferred.
  • Phase 6a (define-syntax + syntax-rules, 12 tests): pattern matching with literals + pattern variables + list structure; template substitution.
  • Phase 6b (syntax-rules ellipsis, 8 tests): tail-rest single-variable form. (my-and 1 2 3) etc. work.
  • Phase 7 (eval / interaction-environment, 13 tests): second consumer for evaluator.sx. interaction-environment closes over the env being built, so user-side defines via (eval ... ie) persist across calls.
  • Phase 8 (define-library + import, 7 tests): minimal module system. Private definitions stay in library env; only exports are visible after import.
  • Phase 9 (define-record-type, 9 tests): tagged-dict records with optional mutators.
  • Phase 10 (quasiquote runtime, 10 tests): second consumer for quoting.sx. Identical algorithm to Kernel's knl-quasi-walk — universal across reflective Lisps.
  • Phase 11 (test.sh + scoreboard): single-process aggregating runner, scoreboard markdown.

Deferred phases

  • Phase 6c — full hygiene. Dybvig-style scope-sets / lifted-symbol algorithm. Would be the second consumer for the deferred lib/guest/reflective/hygiene.sx. Current macros work for common patterns but don't prevent introduced-binding capture. Research-grade work; warrants its own loop iteration.
  • Nested quasiquote depth tracking.
  • R7RS module rich features (cond-expand, include, import sets like only/except/prefix/rename).
  • Dotted-pair (a b . rest) parser syntax + lambda rest-args.
  • Full call/cc + dynamic-wind interaction: dynamic-extent re-entry/re-exit tracking.

Chisel ledger update

This Scheme port satisfies the two-consumer rule for three reflective kits documented in the kernel-on-sx loop:

Kit Status
env.sx Extracted — Scheme is the third consumer (after Kernel + Tcl/Smalltalk), uses the canonical shape directly with no cfg
evaluator.sx Second consumer ready — Scheme eval/interaction-environment/null-environment/scheme-report-environment mirror the proposed refl-eval/refl-current-env/refl-make-environment triple
quoting.sx Second consumer ready — Scheme scm-quasi-walk is structurally identical to Kernel's knl-quasi-walk; the only difference is the unquote keyword names (cfg parameterisation)
hygiene.sx Still awaiting (needs Phase 6c)
combiner.sx N/A — Scheme has no fexprs
short-circuit.sx N/A — Scheme and/or are syntactic, not operative

The kit-extraction commits themselves are follow-on work; this Scheme port is the consumer-side foundation.