Chez Phase 1 (increment 3h): host-interop method-call emit

(.method target arg*) now analyzes to a :host-call IR node instead of
punting at analyze. The Chez back end lowers it to a jolt-host-call
dispatch for the methods the RT shims (.write -> port display,
.isDirectory -> file-directory?, .listFiles -> directory-list); any
other method stays out of subset (clean emit-time reject, so it can't
read as a compiled-but-broken corpus divergence). The Janet back end
punts ALL :host-call to the interpreter, same shape as letfn: compiles
on Chez, interprets on Janet, zero change to the main language.

Closes the io tier's print-method defmethods and file-seq: prelude emit
reach 348 -> 354/355 (50-io 20/20). The one remaining gap is the regex
literal in parse-uuid (needs a regex engine on Chez; deferred).

emit-test 122/122; Chez subset 672/672, 0 divergences; full gate green.
This commit is contained in:
Yogthos 2026-06-17 18:58:44 -04:00
parent 0f7d2753a8
commit b1cdfd1c9b
9 changed files with 96 additions and 13 deletions

View file

@ -283,6 +283,10 @@
(defn- stdlib-var? [n]
(and (= :var (get n :op)) (string/has-prefix? "clojure." (or (get n :ns) ""))))
# Host interop methods with a Chez RT shim (rt.ss jolt-host-call). A `.method`
# call on any other method is out of subset until shimmed — keep this in sync.
(def- supported-host-methods {"write" true "isDirectory" true "listFiles" true})
# jolt's comparison ops are vacuously true at arity 1 and DON'T inspect the arg
# (so (< :kw) is true), but Scheme's < demands a number even there — special-case.
(def- cmp1-ops {"<" true ">" true "<=" true ">=" true})
@ -365,6 +369,18 @@
:throw (string "(jolt-throw " (emit (get node :expr)) ")")
:try (emit-try node)
:quote (emit-quoted (get node :form))
# host interop (jolt-0kf5): (.method target arg*) -> (jolt-host-call "method"
# target arg*). Only the methods the RT dispatcher (rt.ss) actually shims are
# IN the subset; any other method is out of subset (a clean emit-time reject,
# like an unimplemented stdlib fn), so it doesn't masquerade as a compiled-but-
# broken divergence. The Janet back end punts ALL :host-call to the interpreter.
:host-call (let [m (get node :method)]
(unless (get supported-host-methods m)
(errorf "emit: unsupported host method `.%s` (no Chez shim yet)" m))
(let [target (emit (get node :target))
args (map emit (vv (get node :args)))]
(string "(jolt-host-call " (string/format "%j" m) " "
target (if (empty? args) "" (string " " (string/join args " "))) ")")))
:fn (emit-fn node)
# (def name) with no init (declare): reserve the var cell (declare-var!
# doesn't clobber an existing root) so a forward reference resolves.