jolt/jolt-core/clojure/core/00-kernel.clj
Yogthos cf0b544baf Host interop fixes: ==/time/subvec/defonce + corpus cleanup
- == 1-arg returns true for any value (Clojure short-circuits before the number
  check), not 'requires numbers'.
- current-time-ms wired to now-millis so the time macro works.
- subvec truncates float/ratio indices via long (Scheme quotient rejects flonums).
- defonce checks bound? not var-get — in a top-level do the name is already an
  unbound interned cell, which var-get throws on.
- drop the line-seq corpus row (used janet/spit, N/A); allowlist char-array
  (needs Class/forName "[C").

Corpus 2678->2683, floor raised. Re-minted. Full gate green; CI green.

jolt-cf1q.7
2026-06-21 15:36:41 -04:00

45 lines
2 KiB
Clojure

;; clojure.core — kernel tier (stage just above the host primitives).
;;
;; These are the structural fns the self-hosted compiler itself uses
;; (jolt.analyzer): second/peek/subvec/mapv/update. Because the compiler must be
;; able to compile the *rest* of clojure.core, anything it calls has to exist
;; before it is built. So this tier is loaded FIRST and, in compile mode, is
;; bootstrap-compiled directly into clojure.core (not routed through the
;; self-hosted pipeline, which would need these to already exist — the
;; circularity that previously forced `second` to stay a host primitive). With this tier
;; in place the analyzer is built against the Clojure definitions.
;;
;; Constraint: depend only on core-renames primitives (first/next/nth/count/conj/
;; vec/map/apply/assoc/get/…, all hardwired to host primitives) and on each other.
(defn second [coll] (first (next coll)))
(defn peek [coll]
(cond
(nil? coll) nil
;; vectors (incl. jolt's eager seq results): last element; lists/seqs: first.
(vector? coll) (if (zero? (count coll)) nil (nth coll (dec (count coll))))
(seq? coll) (first coll)
:else (throw (str "peek not supported on: " coll))))
(defn subvec
([v start] (subvec v start (count v)))
([v start end]
(when (not (vector? v)) (throw (str "subvec requires a vector")))
;; Clojure coerces indices with (int ...): NaN -> 0, floats/ratios truncate
;; toward zero; non-numbers throw. Only then range-check.
(let [coerce (fn [x]
(cond
(not (number? x)) (throw (str "subvec index must be a number"))
(not= x x) 0
:else (long x)))
s (coerce start)
e (coerce end)]
(when (or (< s 0) (< e s) (< (count v) e))
(throw (str "subvec index out of range: " s " " e)))
(loop [i s acc []]
(if (< i e) (recur (inc i) (conj acc (nth v i))) acc)))))
(defn mapv [f & colls] (vec (apply map f colls)))
(defn update [m k f & args] (assoc m k (apply f (get m k) args)))