core: Stage 2 tier 6c — dispatch-table ops + misc compile (macros/plain invokes)

prefer-method/remove-method/remove-all-methods/get-method/methods become
overlay macros over ctx-capturing *-setup fns (a multimethod's method table
lives on its VAR, so the name passes quoted — the defmulti/defmethod shape).
instance? likewise (class names don't evaluate to values); satisfies? is a
plain ctx-capturing fn (evaluated args). locking and defonce become overlay
macros — locking now also evaluates the monitor expr (the old arm skipped it
and any body form past the first); defonce keeps the existing-root check.
read-string and macroexpand-1 are ctx-capturing fns.

Removed all eleven from the evaluator special arms + special-symbol?,
host_iface special-names, and compiler uncompilable-heads. evaluator-test's
locking/instance? cases use init now (overlay macros need the full env).

Surfaced pre-existing (filed): multimethod dispatch records prefer-method
preferences on the var but never consults them in ambiguous isa dispatch.

Gate: conformance 296x3 (+11 tier-6c cases), fallback-zero 73/3, fixpoint,
self-host, sci, staged, suite 4049>=4034, all specs+unit.
This commit is contained in:
Yogthos 2026-06-10 09:51:42 -04:00
parent b49cb5c934
commit 719efc56ce
7 changed files with 193 additions and 133 deletions

View file

@ -156,6 +156,21 @@
["resolve + call" "3" "((var-get (resolve (quote inc))) 2)"]
["resolve absent" "nil" "(resolve (quote no-such-sym-xyz))"]
### ---- dispatch-table ops + misc as macros/fns (Stage 2 tier 6c) ----
["get-method + call" "1" "(do (defmulti t6f :k) (defmethod t6f :a [x] 1) ((get-method t6f :a) {:k :a}))"]
["remove-method" "nil" "(do (defmulti t6g :k) (defmethod t6g :b [x] 2) (remove-method t6g :b) (get (methods t6g) :b))"]
["remove-all-methods" "nil" "(do (defmulti t6h :k) (defmethod t6h :c [x] 3) (remove-all-methods t6h) (get (methods t6h) :c))"]
# NOTE: dispatch does not yet CONSULT prefers in ambiguous isa dispatch
# (jolt-bug filed) — this asserts prefer-method records the preference.
["prefer-method records" ":shape" "(do (defmulti t6p identity) (prefer-method t6p :rect :shape) (get (get (var t6p) :jolt/prefers) :rect))"]
["instance? deftype" "true" "(do (deftype T6i [a]) (instance? T6i (->T6i 1)))"]
["instance? String" "true" "(instance? String \"s\")"]
["locking evals body" "3" "(locking :anything (+ 1 2))"]
["locking evals monitor" "[3 1]" "(let [a (atom 0)] [(locking (swap! a inc) 3) @a])"]
["defonce keeps first" "5" "(do (defonce d6o 5) (defonce d6o 9) d6o)"]
["read-string + eval" "3" "(eval (read-string \"(+ 1 2)\"))"]
["macroexpand-1 when" "2" "(count (rest (macroexpand-1 (quote (when true 1)))))"]
### ---- HIGH: aliased namespace calls ----
["require :as alias" "\"1,2,3\"" "(do (require (quote [clojure.string :as s])) (s/join \",\" [1 2 3]))"]
["ns form + alias" "\"HI\"" "(do (ns my.a (:require [clojure.string :as s])) (s/upper-case \"hi\"))"]

View file

@ -64,7 +64,13 @@
"(the-ns (quote clojure.core))" "(ns-interns (quote clojure.core))"
"(ns-aliases (quote user))" "(ns-imports (quote user))"
"(ns-resolve (quote clojure.core) (quote map))" "(resolve (quote map))"
"(refer (quote clojure.string))"])
"(refer (quote clojure.string))"
# Stage 2 tier 6c: dispatch-table ops + misc compile as macros/plain invokes
"(prefer-method mf :a :b)" "(remove-method mf :a)" "(remove-all-methods mf)"
"(get-method mf :a)" "(methods mf)"
"(satisfies? P 5)" "(instance? String \"x\")" "(locking :x 1)"
"(defonce fz-once 1)" "(read-string \"[1 2]\")"
"(macroexpand-1 (quote (when true 1)))"])
# --- Intentional fallback (sanity sample): these SHOULD punt to the interpreter.
# The remaining frozen/uncompiled set keeps the harness honest in the punt

View file

@ -100,14 +100,17 @@
(print " passed")
(print "13: locking...")
# locking is a no-op in single-threaded Janet — just executes body
(assert (= 42 (eval-str "(locking :lock 42)")) "locking returns body result")
# locking/instance? are overlay macros now (Stage 2 tier 6c) — they need the
# full env (init loads the overlay), not a bare make-ctx.
(let [ctx (init)]
(assert (= 42 (eval-string ctx "(locking :lock 42)")) "locking returns body result"))
(print " passed")
(print "14: instance?...")
# instance? checks type
(assert (= true (eval-str "(instance? Number 42)")) "instance? Number matches number")
(assert (= false (eval-str "(instance? Number \"hello\")")) "instance? Number doesn't match string")
(let [ctx (init)]
(assert (= true (eval-string ctx "(instance? Number 42)")) "instance? Number matches number")
(assert (= false (eval-string ctx "(instance? Number \"hello\")")) "instance? Number doesn't match string"))
(print " passed")
(print "15: defmulti/defmethod...")