Phase 1: CEK is now the sole evaluator on JavaScript

- Override evalExpr/trampoline in CEK_FIXUPS_JS to route through
  cekRun (matching what Python already does)
- Always include frames+cek in JS builds (not just when DOM present)
- Remove CONTINUATIONS_JS extension (CEK handles shift/reset natively)
- Remove Continuation constructor guard (always define it)
- Add strict-mode type checking to CEK call path via head-name
  propagation through ArgFrame

Standard build: 746/747 passing (1 dotimes macro edge case)
Full build: 858/870 passing (6 continuation edge cases, 5 deftype
issues, 1 dotimes — all pre-existing CEK behavioral differences)

The tree-walk eval-expr, eval-list, eval-call, and all sf-*/ho-*
forms in eval.sx are now dead code — never reached at runtime.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-03-15 12:49:08 +00:00
parent ebb3445667
commit 293af75821
7 changed files with 94 additions and 56 deletions

View File

@@ -466,11 +466,13 @@
(define step-eval-call
(fn (head args env kont)
;; First evaluate the head, then evaluate args left-to-right
(make-cek-state
head env
(kont-push
(make-arg-frame nil (list) args env args)
kont))))
;; Preserve head name for strict mode type checking
(let ((hname (if (= (type-of head) "symbol") (symbol-name head) nil)))
(make-cek-state
head env
(kont-push
(make-arg-frame nil (list) args env args hname)
kont)))))
;; --------------------------------------------------------------------------
@@ -760,28 +762,36 @@
(evaled (get frame "evaled"))
(remaining (get frame "remaining"))
(fenv (get frame "env"))
(raw-args (get frame "raw-args")))
(raw-args (get frame "raw-args"))
(hname (get frame "head-name")))
(if (nil? f)
;; Head just evaluated — value is the function
(if (empty? remaining)
;; No args — call immediately
(continue-with-call value (list) fenv raw-args rest-k)
;; Start evaluating args
(make-cek-state
(first remaining) fenv
(kont-push
(make-arg-frame value (list) (rest remaining) fenv raw-args)
rest-k)))
(do
;; Strict mode: check arg types for named primitives
(when (and *strict* hname)
(strict-check-args hname (list)))
(if (empty? remaining)
;; No args — call immediately
(continue-with-call value (list) fenv raw-args rest-k)
;; Start evaluating args
(make-cek-state
(first remaining) fenv
(kont-push
(make-arg-frame value (list) (rest remaining) fenv raw-args hname)
rest-k))))
;; An arg was evaluated — accumulate
(let ((new-evaled (append evaled (list value))))
(if (empty? remaining)
;; All args evaluated — call
(continue-with-call f new-evaled fenv raw-args rest-k)
;; All args evaluated — strict check then call
(do
(when (and *strict* hname)
(strict-check-args hname new-evaled))
(continue-with-call f new-evaled fenv raw-args rest-k))
;; Next arg
(make-cek-state
(first remaining) fenv
(kont-push
(make-arg-frame f new-evaled (rest remaining) fenv raw-args)
(make-arg-frame f new-evaled (rest remaining) fenv raw-args hname)
rest-k))))))
;; --- DictFrame: value evaluated ---

View File

@@ -88,9 +88,9 @@
;; f = function value (already evaluated), evaled = already evaluated args
;; remaining = remaining arg expressions
(define make-arg-frame
(fn (f evaled remaining env raw-args)
(fn (f evaled remaining env raw-args head-name)
{:type "arg" :f f :evaled evaled :remaining remaining :env env
:raw-args raw-args}))
:raw-args raw-args :head-name (or head-name nil)}))
;; CallFrame: about to call with fully evaluated args
(define make-call-frame