cl: tagbody + go — 11 new tests (151 eval, 323 total green)
Sentinel-based tagbody: cl-build-tag-map indexes tags by str-normalised key (handles integer tags); cl-eval-tagbody loops with go-jump restart; go-tag propagates through cl-eval-body alongside block-return.
This commit is contained in:
@@ -40,6 +40,9 @@
|
||||
(define cl-block-return?
|
||||
(fn (v) (and (dict? v) (= (get v "cl-type") "block-return"))))
|
||||
|
||||
(define cl-go-tag?
|
||||
(fn (v) (and (dict? v) (= (get v "cl-type") "go-tag"))))
|
||||
|
||||
(define cl-eval-body
|
||||
(fn (forms env)
|
||||
(cond
|
||||
@@ -47,7 +50,7 @@
|
||||
((= (len forms) 1) (cl-eval (nth forms 0) env))
|
||||
(:else
|
||||
(let ((result (cl-eval (nth forms 0) env)))
|
||||
(if (cl-block-return? result)
|
||||
(if (or (cl-block-return? result) (cl-go-tag? result))
|
||||
result
|
||||
(cl-eval-body (rest forms) env)))))))
|
||||
|
||||
@@ -270,6 +273,42 @@
|
||||
{:cl-type "function" :builtin-fn (get cl-builtins name)}))
|
||||
(keys cl-builtins))
|
||||
|
||||
;; ── TAGBODY / GO ─────────────────────────────────────────────────
|
||||
|
||||
(define cl-tagbody-tag?
|
||||
(fn (form) (or (string? form) (number? form))))
|
||||
|
||||
(define cl-build-tag-map
|
||||
(fn (forms i acc)
|
||||
(if (>= i (len forms))
|
||||
acc
|
||||
(if (cl-tagbody-tag? (nth forms i))
|
||||
(cl-build-tag-map forms (+ i 1)
|
||||
(assoc acc (str (nth forms i)) i))
|
||||
(cl-build-tag-map forms (+ i 1) acc)))))
|
||||
|
||||
(define cl-eval-tagbody
|
||||
(fn (args env)
|
||||
(let ((tag-map (cl-build-tag-map args 0 {})))
|
||||
(define run
|
||||
(fn (i)
|
||||
(if (>= i (len args))
|
||||
nil
|
||||
(let ((form (nth args i)))
|
||||
(if (cl-tagbody-tag? form)
|
||||
(run (+ i 1))
|
||||
(let ((result (cl-eval form env)))
|
||||
(cond
|
||||
((cl-go-tag? result)
|
||||
(let ((target (get result "tag")))
|
||||
(let ((tkey (str target)))
|
||||
(if (has-key? tag-map tkey)
|
||||
(run (get tag-map tkey))
|
||||
{:cl-type "error" :message (str "No tag: " target)}))))
|
||||
((cl-block-return? result) result)
|
||||
(:else (run (+ i 1))))))))))
|
||||
(run 0))))
|
||||
|
||||
;; ── BLOCK / RETURN-FROM ───────────────────────────────────────────
|
||||
|
||||
(define cl-eval-block
|
||||
@@ -563,6 +602,9 @@
|
||||
((= head "LOCALLY") (cl-eval-body args env))
|
||||
((= head "EVAL-WHEN") (cl-eval-eval-when args env))
|
||||
((= head "DEFUN") (cl-eval-defun args env))
|
||||
((= head "TAGBODY") (cl-eval-tagbody args env))
|
||||
((= head "GO")
|
||||
{:cl-type "go-tag" :tag (nth args 0)})
|
||||
((= head "BLOCK") (cl-eval-block args env))
|
||||
((= head "RETURN-FROM") (cl-eval-return-from args env))
|
||||
((= head "RETURN")
|
||||
|
||||
Reference in New Issue
Block a user