Commit Graph

6 Commits

Author SHA1 Message Date
e3e5d3e888 scheme: Phase 5a — call/cc + 8 tests
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 38s
scheme-standard-env binds:
- call/cc                            — primary
- call-with-current-continuation     — alias

Implementation wraps SX's host call/cc, presenting the captured
continuation k as a Scheme procedure that accepts a single value
(or a list of values for multi-arg invocation). Single-shot
escape semantics: when k is invoked, control jumps out of the
surrounding call/cc form. Multi-shot re-entry isn't safely
testable without delimited-continuation infrastructure (the
captured continuation re-enters indefinitely if invoked after
the call/cc returns) — deferred to a follow-up commit if needed.

Tests cover:
- No-escape return value
- Escape past arithmetic frames
- Detect/early-exit idiom over for-each
- Procedure? on the captured k

220 total Scheme tests now (62 + 23 + 49 + 78 + 8).
2026-05-14 06:27:03 +00:00
cf933f0ece scheme: Phase 4 standard env + set! bugfix + 78 tests
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 25s
lib/scheme/runtime.sx — full R7RS-base surface:

- Arithmetic: variadic +/-/*//, abs, min, max, modulo, quotient,
  remainder. Predicates zero?/positive?/negative?.
- Comparison: chained =/</>/<=/>=.
- Type predicates: number?/boolean?/symbol?/string?/char?/vector?/
  null?/pair?/procedure?/not.
- List: cons/car/cdr/list/length/reverse/append.
- Higher-order: map/filter/fold-left/fold-right/for-each/apply.
  These re-enter scheme-apply to invoke user-supplied procs.
- String: string-length/string=?/string-append/substring.
- Char: char=?.
- Vector: vector/vector-length/vector-ref/vector->list/list->vector/
  make-vector.
- Equality: eqv?/equal?/eq? (all = under the hood for now).

Built via small adapters: scm-unary, scm-binary, scm-fold (variadic
left-fold with identity + one-arity special), scm-chain (n-ary
chained comparison).

**Bugfix in eval.sx set! handler.** The :else branch had two
expressions `(dict-set! ...) val` — SX cond branches don't run
multiple expressions, they return nil silently (or evaluate only
the first, depending on shape). Wrapped in (begin ...) to force
sequential execution. This fix also unblocks 4 set!-dependent
tests in lib/scheme/tests/syntax.sx that were silently raising
during load (and thus not counted) — syntax test count jumps
from 45 → 49.

Classic programs verified:
- factorial 10 → 3628800
- fib 10 → 55
- recursive list reverse → working
- sum of squares via fold-left + map → 55

212 total Scheme tests: parse 62 + eval 23 + syntax 49 + runtime 78.
All green.

The env-as-value section in runtime tests demonstrates
scheme-standard-env IS a refl-env? — kit primitives operate on it
directly, confirming the third-consumer adoption with zero adapter.
2026-05-13 20:29:37 +00:00
0fccd1b353 scheme: Phase 3.5 — let/let*/cond/when/unless/and/or + 21 tests
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 27s
Adds the rest of the standard syntactic operators, all built on the
existing eval/closure infrastructure from Phase 3:

- let — parallel bindings in fresh child env; values evaluated in
  outer env (RHS sees pre-let bindings only). Multi-body via
  scheme-eval-body.
- let* — sequential bindings, each in a nested child env; later
  bindings see earlier ones.
- cond — clauses walked in order; first truthy test wins. `else`
  symbol is the catch-all. Test-only clauses (no body) return the
  test value. Scheme truthiness: only #f is false.
- when / unless — single-test conditional execution, multi-body
  body via scheme-eval-body.
- and / or — short-circuit boolean. Empty `(and)` = true,
  `(or)` = false. Both return the actual value at the point
  of short-circuit (not coerced to bool), matching R7RS.

130 total Scheme tests (62 parse + 23 eval + 45 syntax). The
Scheme port is now self-hosting enough to write any non-stdlib
program — factorial, list operations via primitives, closures
with mutable state, all working.

Next phase: standard env (runtime.sx) with variadic +/-, list
ops as Scheme-visible applicatives.
2026-05-13 20:04:44 +00:00
23a53a2ccb scheme: Phase 3 — if/define/set!/begin/lambda/closures + 24 tests
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 28s
eval.sx grows: five new syntactic operators wired via the table-
driven dispatch from Phase 2. lambda creates closures
{:scm-tag :closure :params :rest :body :env} that capture the
static env; scheme-apply-closure binds formals + rest-arg, evaluates
multi-expression body in (extend static-env), returns last value.

Supports lambda formals shapes:
  ()            → no args
  (a b c)       → fixed arity
  args          → bare symbol; binds all call-args as a list

Dotted-pair tail (a b . rest) deferred until parser supports it.

define has both flavours:
  (define name expr)                 — direct binding
  (define (name . formals) body...)  — lambda sugar

set! walks the env chain via refl-env-find-frame, mutates at the
binding's source frame (no shadowing). Raises on unbound name.

24 new tests in lib/scheme/tests/syntax.sx, including:
- Factorial 5 → 120 and 10 → 3628800 (recursion + closures)
- make-counter via closed-over set! state
- Curried (((curry+ 1) 2) 3) → 6
- (lambda args args) rest-arg binding
- Multi-body lambdas with internal define

109 total Scheme tests (62 parse + 23 eval + 24 syntax).
2026-05-13 20:02:46 +00:00
e222e8b0aa scheme: Phase 2 evaluator — env.sx third consumer + 23 tests [consumes-env]
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 25s
lib/scheme/eval.sx — R7RS evaluator skeleton:
- Self-evaluating: numbers, booleans, characters, vectors, strings
- Symbol lookup: refl-env-lookup
- Lists: syntactic-operator table dispatch, else applicative call
- Table-driven syntactic ops (Phase 2 wires `quote` only; full set
  in Phase 3)
- Apply: callable host fn or scheme closure (closure stub for Phase 3)

scheme-make-env / scheme-env-bind! / etc. are THIN ALIASES for the
refl-env-* primitives from lib/guest/reflective/env.sx. No adapter
cfg needed — Scheme's lexical-scope semantics ARE the canonical
wire shape. This is the THIRD CONSUMER for env.sx after Kernel and
Tcl + Smalltalk's variant adapters; the first to use it without
any bridging code. Validates the kit handles canonical-shape
adoption with zero ceremony.

23 tests in lib/scheme/tests/eval.sx cover literals, symbol
lookup with parent-chain shadowing, quote (special form + sugar),
primitive application with nested calls, and an env-as-value
section explicitly demonstrating the kit primitives work on
Scheme envs.

85 total Scheme tests (62 parse + 23 eval).

chisel: consumes-env (third consumer for lib/guest/reflective/env.sx).
2026-05-13 20:00:36 +00:00
c919d9a0d7 scheme: Phase 1 parser — R7RS lexical reader + 62 tests [consumes-lex]
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 21s
lib/scheme/parser.sx — reader for R7RS-small lexical syntax:
- numbers (int/float/exp)
- booleans #t / #f / #true / #false
- strings with standard escapes
- symbols (permissive — any non-delimiter)
- characters #\c, #\space, #\newline, #\tab, etc.
- vectors #(...)
- proper lists (dotted-pair deferred to Phase 3 with lambda rest-args)
- reader macros: 'X `X ,X ,@X → (quote X) (quasiquote X) etc.
  (Scheme conventions — lowercase, no $ prefix)
- line comments ;
- nestable block comments #| ... |#
- datum comments #;<datum>

AST shape mirrors Kernel: numbers/booleans/lists pass through;
strings wrapped as {:scm-string ...} to distinguish from symbols
(bare SX strings); chars as {:scm-char ...}; vectors as
{:scm-vector (list ...)}.

62 tests in lib/scheme/tests/parse.sx cover atom kinds, escape
sequences, quote/quasiquote/unquote/unquote-splicing, all three
comment flavours, and classic Scheme idioms (lambda, define, let,
if-cond).

Note: SX cond branches evaluate only the LAST expression, so
multi-mutation branches need explicit (do ...) or (begin ...)
wrappers — caught during block-comment debugging.

chisel: consumes-lex (lex-digit?, lex-whitespace? from
lib/guest/lex.sx); pratt not consumed (no operator precedence
in Scheme).
2026-05-13 19:58:30 +00:00