scheme: Phase 10 — quasiquote runtime + 10 tests [shapes-reflective]
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 26s

eval.sx adds quasiquote / unquote / unquote-splicing as syntactic
operators with the canonical R7RS walker:

- (quasiquote X) — top-level entry to scm-quasi-walk
- (unquote X) — at depth-0, evaluates X in env
- (unquote-splicing X) — inside a list, splices X's list value
- Reader-macro sugar: `X / ,X / ,@X work via Phase 1 parser

Algorithm identical to lib/kernel/runtime.sx's knl-quasi-walk:
- Walk template recursively
- Non-list: pass through
- ($unquote/unquote X) head form: eval X
- Inside a list, ($unquote-splicing/unquote-splicing X) head:
  eval X, splice list into surrounding context
- Otherwise: recurse on each element

No depth-tracking yet — nested quasiquotes are not properly
handled (matches Kernel's deferred state).

10 tests: plain atom/list, unquote substitution, splicing at
start/middle/end, nested list with unquote, unquote evaluates
expression, error on non-list splice, error on bare unquote.

**Second consumer for lib/guest/reflective/quoting.sx unlocked.**
Both Kernel and Scheme have structurally identical walkers; the
extraction would parameterise just the unquote/splicing keyword
names (Kernel uses $unquote / $unquote-splicing; Scheme uses
unquote / unquote-splicing — pure cfg, no algorithmic change).

280 total Scheme tests (62+23+49+78+25+20+13+10).

Three reflective-kit extractions unlocked in this Scheme port:
- env.sx        — Phase 2 (consumed directly, third overall consumer)
- evaluator.sx  — Phase 7 (second consumer via eval/interaction-env)
- quoting.sx    — Phase 10 (second consumer via scm-quasi-walk)

The kit extractions themselves remain follow-on commits when
desired. hygiene.sx still awaits a real second consumer
(Scheme phase 6c with scope-set algorithm).
This commit is contained in:
2026-05-14 06:47:51 +00:00
parent 342e1a2ccf
commit e200935698
2 changed files with 100 additions and 0 deletions

View File

@@ -97,4 +97,34 @@
"(define sandbox (null-environment 7))\n (guard (e (else 'unbound))\n (eval '(+ 1 1) sandbox))")
"unbound")
;; ── quasiquote / unquote / unquote-splicing ─────────────────────
(scm-ref-test "qq: plain atom"
(scm-ref "`hello") "hello")
(scm-ref-test "qq: plain list"
(scm-ref "`(a b c)") (list "a" "b" "c"))
(scm-ref-test "qq: unquote substitutes value"
(scm-ref-all "(define x 42) `(a ,x b)")
(list "a" 42 "b"))
(scm-ref-test "qq: unquote-splicing splices list"
(scm-ref-all "(define xs '(1 2 3)) `(a ,@xs b)")
(list "a" 1 2 3 "b"))
(scm-ref-test "qq: splice at start"
(scm-ref-all "(define xs '(1 2)) `(,@xs c)")
(list 1 2 "c"))
(scm-ref-test "qq: splice at end"
(scm-ref-all "(define xs '(9 8)) `(a b ,@xs)")
(list "a" "b" 9 8))
(scm-ref-test "qq: nested list with unquote"
(scm-ref-all "(define x 5) `(a (b ,x) c)")
(list "a" (list "b" 5) "c"))
(scm-ref-test "qq: unquote evaluates expression"
(scm-ref "`(a ,(+ 1 2) b)")
(list "a" 3 "b"))
(scm-ref-test "qq: error on splicing non-list"
(scm-ref-all
"(define x 42) (guard (e (else 'raised)) `(a ,@x b))")
"raised")
(scm-ref-test "qq: bare unquote at top level errors"
(scm-ref "(guard (e (else 'raised)) (unquote 5))") "raised")
(define scm-ref-tests-run! (fn () {:total (+ scm-ref-pass scm-ref-fail) :passed scm-ref-pass :failed scm-ref-fail :fails scm-ref-fails}))