jolt/src/jolt/core.janet
Yogthos f7747ed1b4 Phase 12: Protocol System — full implementation with all tests passing
Root cause: fn* multi-arity detection checks (array? (in form 1))
— defprotocol used @[...] for args, triggering multi-arity path
that treated the body form as a second arity pair.

Fixes applied:
- defprotocol: change fn* args from @[...] to [...] (tuple)
  so single-arity fn* path is used with [this & rest-args]
- defprotocol: remove quote wrappers from protocol-dispatch call
  (protocol-name and method-name passed directly as symbols)
- extend-type/extend-protocol: remove quote wrappers from
  register-method call (symbols passed directly, not via quote)
- protocol-dispatch: use (in form ...) directly for proto/method
  symbols (no eval-form needed after quote removal)
- satisfy?: extract name string from protocol value's :name field
  (which is a symbol struct, not a plain string)
- make-reified: remove spurious (apply fn []) call
- core-reify: fix (keyword struct) → extract :name string first
- core-extend-protocol: handle single method spec vs multi

5 test sections (35-39) covering:
  defprotocol, extend-type, extend-protocol,
  satisfies?, reify — all pass

315 ok, 2 fail (pre-existing, unchanged)
2026-06-03 00:33:41 -04:00

1373 lines
44 KiB
Text

# Jolt Core Library
# Clojure-compatible core functions for the Jolt interpreter.
(use ./types)
(use ./phm)
# ============================================================
# Predicates
# ============================================================
(defn core-nil? [x] (nil? x))
(defn core-not [x] (if x false true))
(defn core-some? [x] (not (nil? x)))
(defn core-string? [x] (string? x))
(defn core-number? [x] (number? x))
(defn core-fn? [x] (or (function? x) (cfunction? x)))
(defn core-keyword? [x] (keyword? x))
(defn core-symbol? [x] (and (struct? x) (= :symbol (x :jolt/type))))
(defn core-vector? [x] (tuple? x))
(defn core-map? [x] (or (phm? x) (struct? x) (if (and (table? x) (get x :jolt/deftype)) true false)))
(defn core-seq? [x] (or (array? x) (tuple? x)))
(defn core-coll? [x] (or (array? x) (tuple? x) (struct? x)))
(defn core-true? [x] (= true x))
(defn core-false? [x] (= false x))
(defn core-identical? [a b] (= a b))
(defn core-zero? [x] (and (number? x) (= x 0)))
(defn core-pos? [x] (and (number? x) (> x 0)))
(defn core-neg? [x] (and (number? x) (< x 0)))
(defn core-even? [n] (= 0 (% n 2)))
(defn core-odd? [n] (not= 0 (% n 2)))
(defn core-empty? [coll]
(if (nil? coll) true
(if (set? coll) (= 0 (coll :cnt))
(if (phm? coll) (= 0 (coll :cnt))
(if (struct? coll) (= 0 (length (keys coll)))
(= 0 (length coll)))))))
(defn core-every? [pred coll]
(var result true)
(each x coll (if (not (pred x)) (do (set result false) (break))))
result)
# ============================================================
# Math — Clojure semantics (variadic, / with one arg = reciprocal)
# ============================================================
(def core-+ (fn [& args] (if (= 0 (length args)) 0 (+ ;args))))
(def core-sub
(fn [& args]
(if (= 0 (length args))
(error "Wrong number of args (0) passed to: -")
(apply - args))))
(def core-* (fn [& args] (if (= 0 (length args)) 1 (* ;args))))
(def core-/
(fn [& args]
(case (length args)
0 (error "Wrong number of args (0) passed to: /")
1 (/ 1 (args 0))
(apply / args))))
(def core-inc inc)
(def core-dec dec)
(def core-mod %)
(def core-rem %)
(def core-quot (fn [n d] (math/floor (/ n d))))
(defn core-max [& args] (apply max args))
(defn core-min [& args] (apply min args))
# ============================================================
# Comparison
# ============================================================
(defn core-= [& args]
(if (< (length args) 2) true
(do
(var ok true)
(var i 0)
(while (and ok (< i (dec (length args))))
(let [a (args i) b (args (+ i 1))]
(set ok
(if (phm? a)
(deep= (phm-to-struct a) (if (phm? b) (phm-to-struct b) b))
(if (phm? b) (deep= a (phm-to-struct b))
(if (set? a)
(deep= (phs-to-struct a) (if (set? b) (phs-to-struct b) b))
(if (set? b) (deep= a (phs-to-struct b)) (deep= a b)))))))
(++ i))
ok)))
(defn core-not= [& args] (not (apply core-= args)))
(defn core-< [a b] (< a b))
(defn core-> [a b] (> a b))
(defn core-<= [a b] (<= a b))
(defn core->= [a b] (>= a b))
# ============================================================
# Collections
# ============================================================
(defn core-conj [coll & xs]
(if (tuple? coll)
(tuple/slice (tuple ;(array/concat (array/slice coll) xs)))
(if (array? coll)
(do
(var result coll)
(var i 0)
(while (< i (length xs))
(set result (array/insert result 0 (xs i)))
(++ i))
result)
(if (set? coll)
(apply phs-conj coll xs)
(if (phm? coll)
(do
(var result coll)
(var i 0)
(while (< i (length xs))
(let [pair (xs i)]
(set result (phm-assoc result (pair 0) (pair 1))))
(++ i))
result)
(do
(var result coll)
(var i 0)
(while (< i (length xs))
(let [pair (xs i)]
(set result (merge result {(pair 0) (pair 1)})))
(++ i))
result))))))
(defn core-assoc [m & kvs]
(if (phm? m)
(do (var result m) (var i 0) (while (< i (length kvs)) (set result (phm-assoc result (kvs i) (kvs (+ i 1)))) (+= i 2)) result)
(do (var result @{}) (when m (each k (if (struct? m) (keys m) (keys (table ;(pairs m)))) (put result k (get m k))))
(var i 0) (while (< i (length kvs)) (let [k (kvs i) v (kvs (+ i 1))] (put result k v) (+= i 2)))
(if (struct? m) (table/to-struct result) result))))
(defn core-dissoc [m & ks]
(if (phm? m)
(do (var result m) (each k ks (set result (phm-dissoc result k))) result)
(do (var result @{}) (each k (keys m) (var in-ks false) (each k2 ks (if (deep= k k2) (do (set in-ks true) (break)))) (if (not in-ks) (put result k (m k))))
(if (struct? m) (table/to-struct result) result))))
(defn core-get [m k &opt default]
(default default nil)
(if (nil? m) default
(if (set? m) (phs-get m k default)
(if (phm? m) (phm-get m k default)
(if (or (struct? m) (table? m))
(let [v (m k)]
(if (nil? v) default v))
(if (and (or (tuple? m) (array? m)) (number? k) (>= k 0) (< k (length m)))
(in m k)
default))))))
(defn core-get-in [m ks &opt default]
(default default nil)
(var current m)
(var i 0)
(while (< i (length ks))
(if (nil? current) (break))
(set current (core-get current (ks i)))
(++ i))
(if (nil? current) default current))
(defn core-contains? [coll key]
(if (set? coll) (phs-contains? coll key)
(if (phm? coll) (let [b (get (coll :buckets) (phm-hash-key key))] (if b (phm-bucket-contains? b key) false))
(if (struct? coll) (not (nil? (coll key)))
(if (table? coll) (not (nil? (coll key)))
(if (or (tuple? coll) (array? coll))
(and (number? key) (>= key 0) (< key (length coll)))
false))))))
(defn core-count [coll]
(if (lazy-seq? coll) (ls-count coll)
(if (set? coll) (coll :cnt)
(if (phm? coll) (coll :cnt)
(if (and (table? coll) (get coll :jolt/deftype)) (- (length (keys coll)) 1)
(length coll))))))
(defn core-first [coll]
(if (lazy-seq? coll) (ls-first coll)
(if (or (nil? coll) (= 0 (length coll))) nil
(in coll 0))))
(defn core-rest [coll]
(if (lazy-seq? coll) (ls-rest coll)
(if (or (nil? coll) (= 0 (length coll)))
@[]
(if (tuple? coll)
(tuple/slice coll 1)
(array/slice coll 1)))))
(defn core-next [coll]
(let [r (core-rest coll)]
(if (= 0 (length r)) nil r)))
(defn core-cons [x coll]
(if (nil? coll)
@[x]
(if (tuple? coll)
(tuple/slice (tuple ;(array/insert (array/slice coll) 0 x)))
(array/insert coll 0 x))))
(defn core-seq [coll]
(if (or (nil? coll) (and (or (tuple? coll) (array? coll)) (= 0 (length coll))))
nil
(if (lazy-seq? coll) (ls-seq coll)
(if (set? coll) (phs-seq coll)
(if (phm? coll) (tuple ;(phm-entries coll))
(if (tuple? coll) (tuple/slice coll)
(if (string? coll) (map |(string/from-bytes $) (string/bytes coll))
(if (struct? coll) (tuple ;(keys coll))
coll))))))))
(defn core-vec [coll]
(if (tuple? coll) coll
(if (array? coll) (tuple ;coll)
(if (struct? coll) (tuple ;(map |(in (kvs coll) (+ (* $ 2) 1)) (range (/ (length (kvs coll)) 2))))
(tuple)))))
(defn core-into [to from]
(if (tuple? to)
(tuple/slice (tuple ;(array/concat (array/slice to) (if (tuple? from) from (array/slice from)))))
(if (array? to)
(array/concat to from)
(if (struct? to)
(do
(var result to)
(each [k v] (pairs from)
(set result (merge result {k v})))
result)
to))))
(defn core-merge [& maps]
(if (phm? (first maps))
(do (var result (first maps)) (var mi 1) (while (< mi (length maps)) (let [m (maps mi)] (each k (if (phm? m) (keys (phm-to-struct m)) (keys m)) (set result (phm-assoc result k (if (phm? m) (phm-get m k) (m k))))) (++ mi))) result)
(do (var result (struct)) (each m maps (set result (merge result m))) result)))
(defn core-merge-with [f & maps]
(if (phm? (first maps))
(do (var result (first maps)) (var mi 1) (while (< mi (length maps)) (let [m (maps mi)]
(each k (if (phm? m) (keys (phm-to-struct m)) (keys m)) (let [existing (phm-get result k)
val (if (phm? m) (phm-get m k) (m k))]
(set result (phm-assoc result k (if (nil? existing) val (f existing val)))))) (++ mi))) result)
(do (var result @{}) (each m maps (each k (if (phm? m) (keys (phm-to-struct m)) (keys m)) (let [existing (result k)] (put result k (if (nil? existing) (m k) (f existing (m k))))))) (table/to-struct result))))
(defn core-keys [m]
(if (phm? m) (tuple ;(keys (phm-to-struct m))) (tuple ;(keys m))))
(defn core-vals [m]
(if (phm? m) (do (def s (phm-to-struct m)) (tuple ;(map |(s $) (keys s)))) (tuple ;(map |(m $) (keys m)))))
(defn core-select-keys [m ks]
(var result @{})
(each k ks
(let [v (core-get m k)]
(if (not (nil? v)) (put result k v))))
(if (struct? m) (table/to-struct result) result))
(defn core-zipmap [ks vs]
(var result @{})
(var i 0)
(while (and (< i (length ks)) (< i (length vs)))
(put result (ks i) (vs i))
(++ i))
(table/to-struct result))
# ============================================================
# Sequence operations
# ============================================================
(defn core-map [f & colls]
(let [first-coll (colls 0)
result (if (= 1 (length colls))
(array ;(map f first-coll))
(do
(var res @[])
(var idxs @{})
(each _ first-coll (array/push idxs 0))
(var done false)
(while (not done)
(var args @[])
(var i 0)
(while (< i (length colls))
(let [c (colls i) j (idxs i)]
(if (>= j (length c))
(do (set done true) (break))
(array/push args (c j))))
(++ i))
(if (not done) (array/push res (apply f args)))
(var k 0)
(while (< k (length colls))
(set (idxs k) (+ (idxs k) 1))
(++ k)))
res))]
(if (tuple? first-coll) (tuple/slice (tuple ;result)) result)))
(defn core-filter [pred coll]
(var result @[])
(each x coll
(if (pred x) (array/push result x)))
(if (tuple? coll) (tuple/slice (tuple ;result)) result))
(defn core-remove [pred coll]
(core-filter (fn [x] (not (pred x))) coll))
(def core-reduce
(fn [& args]
(case (length args)
2 (let [f (args 0) coll (args 1)]
(if (= 0 (length coll))
(f)
(do
(var acc (coll 0))
(var i 1)
(while (< i (length coll))
(set acc (f acc (coll i)))
(++ i))
acc)))
3 (let [f (args 0) val (args 1) coll (args 2)]
(var acc val)
(each x coll (set acc (f acc x)))
acc)
(error "Wrong number of args passed to: reduce"))))
(defn core-take [n coll]
(var result @[])
(var i 0)
(while (and (< i n) (< i (length coll)))
(array/push result (coll i))
(++ i))
(if (tuple? coll) (tuple/slice (tuple ;result)) result))
(defn core-drop [n coll]
(if (tuple? coll)
(tuple/slice coll (min n (length coll)))
(array/slice coll (min n (length coll)))))
(defn core-take-while [pred coll]
(var result @[])
(each x coll
(if (pred x) (array/push result x) (break)))
(if (tuple? coll) (tuple/slice (tuple ;result)) result))
(defn core-drop-while [pred coll]
(var start 0)
(while (and (< start (length coll)) (pred (coll start)))
(++ start))
(if (tuple? coll)
(tuple/slice coll start)
(array/slice coll start)))
(defn core-concat [& colls]
(var result @[])
(each c colls
(each x c (array/push result x)))
result)
(defn core-reverse [coll]
(var result @[])
(var i (dec (length coll)))
(while (>= i 0)
(array/push result (coll i))
(-- i))
(if (tuple? coll) (tuple/slice (tuple ;result)) result))
(defn core-nth
"Return the nth element of a sequential collection."
[coll idx &opt default]
(if (and (>= idx 0) (< idx (length coll)))
(in coll idx)
(if (nil? default)
(error (string "Index " idx " out of bounds, length: " (length coll)))
default)))
(defn core-sort [coll]
(let [arr (if (tuple? coll) (array/slice coll) coll)
sorted (sort arr)]
(if (tuple? coll) (tuple/slice (tuple ;sorted)) sorted)))
(defn core-sort-by [keyfn coll]
(let [arr (if (tuple? coll) (array/slice coll) coll)
sorted (sort-by keyfn arr)]
(if (tuple? coll) (tuple/slice (tuple ;sorted)) sorted)))
(defn core-distinct [coll]
(var seen @{})
(var result @[])
(each x coll
(if (nil? (seen x))
(do
(put seen x true)
(array/push result x))))
(if (tuple? coll) (tuple/slice (tuple ;result)) result))
(defn core-group-by [f coll]
(var result @{})
(each x coll
(let [k (f x)]
(put result k (array/push (core-get result k @[]) x))))
result)
(defn core-frequencies [coll]
(core-group-by identity coll))
(defn core-partition [n coll]
(var result @[])
(var i 0)
(while (< i (length coll))
(var part @[])
(var j 0)
(while (and (< j n) (< (+ i j) (length coll)))
(array/push part (coll (+ i j)))
(++ j))
(if (= (length part) n) (array/push result (tuple/slice (tuple ;part))))
(+= i n))
result)
(defn core-partition-by [f coll]
(var result @[])
(var part @[])
(var last-k nil)
(each x coll
(let [k (f x)]
(if (and last-k (deep= k last-k))
(array/push part x)
(do
(if (> (length part) 0) (array/push result (tuple/slice (tuple ;part))))
(set part @[x])
(set last-k k)))))
(if (> (length part) 0) (array/push result (tuple/slice (tuple ;part))))
result)
# ============================================================
# Sequence generators
# ============================================================
(def core-range
(fn [& args]
(let [start (if (> (length args) 1) (args 0) 0)
end (if (> (length args) 1) (args 1) (args 0))
step (if (> (length args) 2) (args 2) 1)]
(var result @[])
(var i start)
(while (if (pos? step) (< i end) (> i end))
(array/push result i)
(+= i step))
(tuple/slice (tuple ;result)))))
(def core-repeat (fn [n x]
(var result @[])
(var i 0)
(while (< i n)
(array/push result x)
(++ i))
result))
(defn core-iterate [f x]
"Macro: (iterate f x) → lazy infinite sequence x, (f x), (f (f x)), ..."
(def sym-x (gensym "x"))
(def sym-f (gensym "f"))
@[{:jolt/type :symbol :ns nil :name "lazy-seq"}
@[{:jolt/type :symbol :ns nil :name "let*"}
@[sym-x x sym-f f]
@[{:jolt/type :symbol :ns nil :name "cons"}
sym-x
@[{:jolt/type :symbol :ns nil :name "iterate"}
sym-f
@[{:jolt/type :symbol :ns nil :name sym-f} sym-x]]]]])
(defn core-repeatedly [n f]
(var result @[])
(var i 0)
(while (< i n)
(array/push result (f))
(++ i))
result)
# ============================================================
# Higher-order functions
# ============================================================
(def core-identity (fn [x] x))
(def core-constantly (fn [x] (fn [& _] x)))
(defn core-complement [f]
(fn [& args] (not (apply f args))))
(defn core-qualified-symbol? [x]
"Returns true if x is a symbol with a namespace."
(and (struct? x) (= :symbol (x :jolt/type)) (not (nil? (x :ns)))))
(defn core-meta [x]
"Returns the metadata of x, or nil."
(if (var? x) (var-meta x)
(if (struct? x) (get x :meta) nil)))
(def core-comp
(fn [& fs]
(case (length fs)
0 identity
1 (fs 0)
2 (let [f (fs 0) g (fs 1)] (fn [& args] (f (apply g args))))
(let [f (last fs)
gs (array/slice fs 0 (dec (length fs)))]
(fn [& args]
(var result (apply (last gs) args))
(var i (- (length gs) 2))
(while (>= i 0)
(set result ((gs i) result))
(-- i))
(f result))))))
(defn core-partial [f & args]
(fn [& more] (apply f (array/concat (array/slice args) more))))
(defn core-juxt [& fs]
(fn [& args]
(tuple ;(map |(apply $ args) fs))))
(defn core-memoize [f]
(var cache @{})
(fn [& args]
(let [key (tuple ;args)]
(if-let [v (get cache key)]
v
(let [result (apply f args)]
(put cache key result)
result)))))
# ============================================================
# Collection constructors
# ============================================================
(defn core-vector [& xs] (tuple ;xs))
(defn core-hash-map [& kvs] (make-phm kvs))
(defn core-array-map [& kvs]
(var result @{})
(var i 0)
(while (< i (length kvs))
(put result (kvs i) (kvs (+ i 1)))
(+= i 2))
(table/to-struct result))
(defn core-hash-set [& xs]
(apply make-phs xs))
(defn core-set? [x] (set? x))
(defn core-disj [s & ks]
(if (set? s) (apply phs-disj s ks) (error "disj expects a set")))
(defn core-lazy-seq [& body]
@[{:jolt/type :symbol :ns nil :name "make-lazy-seq"}
@[{:jolt/type :symbol :ns nil :name "fn*"} [] ;body]])
(defn core-set [coll]
(apply core-hash-set (if (tuple? coll) (array/slice coll) coll)))
(defn core-list [& xs]
(array ;xs))
# ============================================================
# String functions
# ============================================================
(defn core-str [& xs]
(if (= 0 (length xs)) ""
(do
(var result @[])
(each x xs
(if (nil? x) nil # skip nil
(array/push result (if (string? x) x (string x)))))
(string/join result ""))))
(defn core-name
"Returns the name string of a keyword, symbol, or string."
[x]
(if (keyword? x) (string x)
(if (and (struct? x) (= :symbol (x :jolt/type))) (x :name)
(if (string? x) x
""))))
(defn core-namespace
"Returns the namespace of a keyword, symbol, or nil if none."
[x]
(if (keyword? x) (string x)
(if (and (struct? x) (= :symbol (x :jolt/type)))
(if (x :ns) (if (struct? (x :ns)) ((x :ns) :name) (string (x :ns))) nil)
nil)))
(def core-subs
(fn [& args]
(case (length args)
2 (string/slice (args 0) (args 1))
3 (string/slice (args 0) (args 1) (args 2))
(error "Wrong number of args passed to: subs"))))
# ============================================================
# I/O — minimal wrappers
# ============================================================
(def core-print print)
(def core-println (fn [& xs] (apply print xs) (print "\n") nil))
(defn core-pr [& xs]
(var i 0)
(while (< i (length xs))
(if (> i 0) (prin " "))
(prin (xs i))
(++ i))
nil)
(defn core-prn [& xs]
(apply core-pr xs)
(print "\n")
nil)
# ============================================================
# Array primitives (needed for persistent data structures)
# ============================================================
(def core-alength (fn [arr] (length arr)))
(def core-aget (fn [arr idx] (in arr idx)))
(def core-aset (fn [arr idx val] (put arr idx val) val))
(def core-aclone (fn [arr] (array/slice arr 0)))
(def core-object-array (fn [size] (array/new-filled size nil)))
(def core-int-array (fn [size] (array/new-filled size 0)))
(def core-to-array (fn [coll]
(def arr @[])
(each x coll (array/push arr x))
arr))
# ============================================================
# Bit operations (needed for persistent data structures)
# ============================================================
(def core-bit-and (fn [a b] (band a b)))
(def core-bit-or (fn [a b] (bor a b)))
(def core-bit-xor (fn [a b] (bxor a b)))
(def core-bit-not (fn [a] (bnot a)))
(def core-bit-shift-left (fn [x n] (blshift x n)))
(def core-bit-shift-right (fn [x n] (brshift x n)))
(def core-unsigned-bit-shift-right (fn [x n] (brushift x n)))
# ============================================================
# Integer coercion
# ============================================================
(def core-int (fn [x] (math/trunc x)))
(def core-unchecked-inc (fn [x] (+ x 1)))
(def core-unchecked-dec (fn [x] (- x 1)))
(def core-unchecked-add (fn [& xs] (+ ;xs)))
(def core-unchecked-subtract (fn [& xs] (- ;xs)))
# ============================================================
# Hash
# ============================================================
(def core-hash (fn [x] (hash x)))
# ============================================================
# Atom
# ============================================================
(defn core-atom [val]
@{:jolt/type :jolt/atom :value val :watches @{}})
(defn core-atom? [x]
(and (table? x) (= :jolt/atom (x :jolt/type))))
(defn core-deref [ref]
(cond
# Jolt atom
(and (table? ref) (= :jolt/atom (ref :jolt/type)))
(ref :value)
# Jolt var (from types.janet)
(and (table? ref) (= :jolt/var (ref :jolt/type)))
(ref :root)
# default: return as-is
ref))
(defn core-reset! [atm val]
(put atm :value val)
val)
(defn core-swap! [atm f & args]
(let [new-val (apply f (atm :value) args)]
(put atm :value new-val)
new-val))
# ============================================================
# Threading macros (as regular functions? No, as macros in Clojure)
# These need to be defined as macros in the Jolt namespace system.
# For now, skip — they need proper macro definition via the evaluator.
# ============================================================
# ============================================================
# Initialization — intern everything into a context's namespace
# ============================================================
(def gensym_counter @{:val 0})
(defn gensym
"Returns a new symbol with a unique name."
[&opt prefix-string]
(default prefix-string "G__")
(def n (get gensym_counter :val))
(put gensym_counter :val (+ n 1))
{:jolt/type :symbol :ns nil :name (string prefix-string n)})
(defn core-when
"Macro: (when test & body) -> (if test (do body...))"
[test & body]
(def arr (array ;body))
(array/insert arr 0 {:jolt/type :symbol :ns nil :name "do"})
@[{:jolt/type :symbol :ns nil :name "if"}
test
arr])
(defn core-when-not
"Macro: (when-not test & body) -> (when (not test) & body)"
[test & body]
(def not-form @[{:jolt/type :symbol :ns nil :name "not"} test])
@[{:jolt/type :symbol :ns nil :name "if"} not-form
@[{:jolt/type :symbol :ns nil :name "do"} ;body]])
(defn core-and
"Macro: (and) -> true, (and x) -> x, (and x y ...) -> (if x (and y ...) x)"
[& exprs]
(if (= 0 (length exprs)) true
(if (= 1 (length exprs)) (first exprs)
@[{:jolt/type :symbol :ns nil :name "let*"}
@[{:jolt/type :symbol :ns nil :name "and__x"} (first exprs)]
@[{:jolt/type :symbol :ns nil :name "if"}
{:jolt/type :symbol :ns nil :name "and__x"}
@[{:jolt/type :symbol :ns nil :name "and"} ;(tuple/slice exprs 1)]
{:jolt/type :symbol :ns nil :name "and__x"}]])))
(defn core-or
"Macro: (or) -> nil, (or x) -> x, (or x y ...) -> (let [or__x x] (if or__x or__x (or y ...)))"
[& exprs]
(if (= 0 (length exprs)) nil
(if (= 1 (length exprs)) (first exprs)
@[{:jolt/type :symbol :ns nil :name "let*"}
@[{:jolt/type :symbol :ns nil :name "or__x"} (first exprs)]
@[{:jolt/type :symbol :ns nil :name "if"}
{:jolt/type :symbol :ns nil :name "or__x"}
{:jolt/type :symbol :ns nil :name "or__x"}
@[{:jolt/type :symbol :ns nil :name "or"} ;(tuple/slice exprs 1)]]])))
(defn core-if-let
"Macro: (if-let [binding val-expr] then else?)"
[bindings then-form & else-forms]
(def form-sym (in bindings 0))
(def val-form (in bindings 1))
@[{:jolt/type :symbol :ns nil :name "let*"}
@[form-sym val-form]
@[{:jolt/type :symbol :ns nil :name "if"}
form-sym
then-form
;else-forms]])
(defn core-when-let
"Macro: (when-let [binding val-expr] & body)"
[bindings & body]
(def form-sym (in bindings 0))
(def val-form (in bindings 1))
@[{:jolt/type :symbol :ns nil :name "let*"}
@[form-sym val-form]
@[{:jolt/type :symbol :ns nil :name "when"}
form-sym
;body]])
(defn core-if-some
"Macro: (if-some [binding val-expr] then else?)"
[bindings then-form & else-forms]
(def form-sym (in bindings 0))
(def val-form (in bindings 1))
@[{:jolt/type :symbol :ns nil :name "let*"}
@[form-sym val-form]
@[{:jolt/type :symbol :ns nil :name "if"}
@[{:jolt/type :symbol :ns nil :name "some?"} form-sym]
then-form
;else-forms]])
(defn core-when-some
"Macro: (when-some [binding val-expr] & body)"
[bindings & body]
(def form-sym (in bindings 0))
(def val-form (in bindings 1))
@[{:jolt/type :symbol :ns nil :name "let*"}
@[form-sym val-form]
@[{:jolt/type :symbol :ns nil :name "when"}
@[{:jolt/type :symbol :ns nil :name "some?"} form-sym]
;body]])
(defn core-doto
"Macro: (doto obj (method args)...) → let obj, call methods, return obj"
[obj & forms]
(def sym (gensym "doto"))
(def result @[{:jolt/type :symbol :ns nil :name "let*"}
@[sym obj]])
(each f forms
(if (array? f)
(array/push result @[{:jolt/type :symbol :ns nil :name "."} sym (first f) ;(tuple/slice f 1)])
(array/push result @[{:jolt/type :symbol :ns nil :name "."} sym f])))
(array/push result sym)
result)
(defn core-push-thread-bindings [b] (push-thread-bindings b))
(defn core-pop-thread-bindings [] (pop-thread-bindings))
(defn core-var-get [v] (var-get v))
(defn core-var-set [v val] (var-set v val))
(defn core-var? [x] (var? x))
(defn core-alter-var-root [v f & args] (apply alter-var-root v f args))
(defn core-alter-meta! [v f & args] (apply alter-meta! v f args))
(defn core-reset-meta! [v meta] (reset-meta! v meta))
(defn core-intern [ns-name sym-name val] val)
(defn core-binding
"Macro: (binding [var val ...] body...)
Uses array-map (plain struct) to store binding frame
to avoid PHM get() incompatibility with var-get."
[bindings & body]
(def frame-pairs @[])
(var i 0)
(let [n (length bindings)]
(while (< i n)
(array/push frame-pairs
@[{:jolt/type :symbol :ns nil :name "var"} (in bindings i)])
(array/push frame-pairs (in bindings (+ i 1)))
(+= i 2)))
(def hm-form (array/insert frame-pairs 0
{:jolt/type :symbol :ns nil :name "array-map"}))
@[{:jolt/type :symbol :ns nil :name "let*"}
[{:jolt/type :symbol :ns nil :name "frame"} hm-form]
@[{:jolt/type :symbol :ns nil :name "push-thread-bindings"}
{:jolt/type :symbol :ns nil :name "frame"}]
@[{:jolt/type :symbol :ns nil :name "try"}
@[{:jolt/type :symbol :ns nil :name "do"} ;body]
@[{:jolt/type :symbol :ns nil :name "finally"}
@[{:jolt/type :symbol :ns nil :name "pop-thread-bindings"}]]]])
(defn core-defn
"Macro: (defn name [args] body) or (defn name ([args] body)...)
-> (def name (fn* ...) )"
[fn-name & rest]
# Multi-arity if rest starts with list of [args] pairs
(if (and (> (length rest) 0) (array? (first rest)) (indexed? (first (first rest))))
(let [pairs rest]
(def fn-form @[])
(array/push fn-form {:jolt/type :symbol :ns nil :name "fn*"})
(each pair pairs (array/push fn-form pair))
@[{:jolt/type :symbol :ns nil :name "def"} fn-name fn-form])
# Single-arity: (defn name [args] body...)
(let [args-form (first rest)
body (tuple/slice rest 1)]
(def fn-form @[])
(array/push fn-form {:jolt/type :symbol :ns nil :name "fn*"})
(array/push fn-form args-form)
(each b body (array/push fn-form b))
@[{:jolt/type :symbol :ns nil :name "def"} fn-name fn-form])))
# defn- — same as defn (private not enforced in Jolt)
(defn core-defn- [fn-name & rest]
# Multi-arity if rest starts with list of [args] pairs
(if (and (> (length rest) 0) (array? (first rest)) (indexed? (first (first rest))))
(let [pairs rest]
(def fn-form @[])
(array/push fn-form {:jolt/type :symbol :ns nil :name "fn*"})
(each pair pairs (array/push fn-form pair))
@[{:jolt/type :symbol :ns nil :name "def"} fn-name fn-form])
# Single-arity: (defn- name [args] body...)
(let [args-form (first rest)
body (tuple/slice rest 1)]
(def fn-form @[])
(array/push fn-form {:jolt/type :symbol :ns nil :name "fn*"})
(array/push fn-form args-form)
(each b body (array/push fn-form b))
@[{:jolt/type :symbol :ns nil :name "def"} fn-name fn-form])))
# Hierarchy stubs for sci bootstrap
(def core-make-hierarchy make-hierarchy)
(defn core-derive
[& args]
(case (length args)
2 (let [[tag parent] args] (derive* (make-hierarchy) tag parent))
3 (let [[h tag parent] args] (derive* h tag parent))))
(defn core-isa?
[& args]
(case (length args)
1 false
2 false
3 (let [[h child parent] args] (isa? h child parent))))
(defn core-ancestors
[& args]
(case (length args)
1 @[]
2 (let [[h tag] args] (ancestors h tag))))
(defn core-descendants
[& args]
(case (length args)
1 @[]
2 (let [[h tag] args] (descendants h tag))))
(def core-underive underive)
(def core-remove-method (fn [mm-var dispatch-val]
(let [methods (get mm-var :jolt/methods)]
(put methods dispatch-val nil) mm-var)))
(def core-remove-all-methods (fn [mm-var]
(put mm-var :jolt/methods @{}) mm-var))
(defn core-prefer-method [mm-var dispatch-val-a dispatch-val-b]
(let [prefs (or (get mm-var :jolt/prefers)
(do (put mm-var :jolt/prefers @{}) (mm-var :jolt/prefers)))]
(put prefs dispatch-val-a dispatch-val-b) mm-var))
# Java interop stubs
(def core-Object (fn [] (struct ;[:jolt/type :jolt/java-object])))
# Volatile stubs (minimal — use table as volatile box)
(defn core-volatile! [v] @{:val v})
(defn core-vswap! [vol f & args]
(def new-val (apply f (vol :val) args))
(put vol :val new-val)
new-val)
(defn core-vreset! [vol val] (put vol :val val) val)
# Proxy stub — returns nil form (macro, args not evaluated)
(defn core-proxy [& args] nil)
# Thread stubs
(def core-Thread (fn [& args] (struct ;[:jolt/type :jolt/thread])))
(def core-ThreadLocal (fn [& args] (struct ;[:jolt/type :jolt/thread-local])))
(def core-IllegalStateException (fn [& args] (struct ;[:jolt/type :jolt/exception])))
# definterface stub — JVM-only, emits def form
(defn core-definterface [name-sym & body]
@[{:jolt/type :symbol :ns nil :name "def"}
name-sym
@{}])
# comment macro — ignores body, returns nil
(defn core-comment [& body]
nil)
# defrecord — creates a proper type via deftype + factory functions
(defn core-defrecord [name-sym fields-vec & body]
(def type-name (name-sym :name))
(def type-name-dot (string type-name "."))
(def arrow-name (string "->" type-name))
(def map-name (string "map->" type-name))
# (deftype TypeName [fields...])
(def dt-form @[{:jolt/type :symbol :ns nil :name "deftype"} name-sym fields-vec])
# Arrow factory: (def ->TypeName (fn [field1 field2 ...] (TypeName. field1 field2 ...)))
(def arrow-call @[{:jolt/type :symbol :ns nil :name type-name-dot}])
(each f fields-vec (array/push arrow-call f))
(def arrow-sym {:jolt/type :symbol :ns nil :name arrow-name})
(def arrow-body @[{:jolt/type :symbol :ns nil :name "fn"} fields-vec arrow-call])
# map-> factory: (def map->TypeName (fn [m] (->TypeName (get m :field1) (get m :field2) ...)))
(def map-call @[{:jolt/type :symbol :ns nil :name arrow-name}])
(each f fields-vec
(array/push map-call @[{:jolt/type :symbol :ns nil :name "core-get"} {:jolt/type :symbol :ns nil :name (string "m")} (keyword (f :name))]))
(def map-sym {:jolt/type :symbol :ns nil :name map-name})
(def map-body @[{:jolt/type :symbol :ns nil :name "fn"} @[{:jolt/type :symbol :ns nil :name (string "m")}] map-call])
@[{:jolt/type :symbol :ns nil :name "do"}
dt-form
@[{:jolt/type :symbol :ns nil :name "def"} arrow-sym arrow-body]
@[{:jolt/type :symbol :ns nil :name "def"} map-sym map-body]])
# resolve stub — returns nil (symbols not found in Jolt's clojure.core)
(defn core-resolve [sym] nil)
# update — works on both structs and tables
(defn core-update [m k f & args]
(let [current (get m k)
new-val (apply f current args)]
(put m k new-val)))
# copy-var stubs for sci.impl.copy-vars (used by sci.impl.namespaces)
(defn core-copy-core-var [sym] nil)
(defn core-copy-var [sym & args] nil)
(defn core-macrofy [sym fn] fn)
(defn core-new-var [sym & args] nil)
(defn core-avoid-method-too-large [& args] @{})
# declare macro — accepts symbols, does nothing (forward declaration)
(defn core-declare [& syms]
@[{:jolt/type :symbol :ns nil :name "do"}])
(defn core-fn
"Macro: (fn [args] body) → (fn* [args] body)"
[& args]
(def result @[])
(array/push result {:jolt/type :symbol :ns nil :name "fn*"})
(each a args (array/push result a))
result)
(defn core-let
"Macro: (let [bindings] body) → (let* [bindings] body)"
[bindings & body]
(def result @[])
(array/push result {:jolt/type :symbol :ns nil :name "let*"})
(array/push result bindings)
(each b body (array/push result b))
result)
(defn core-loop
"Macro: (loop [bindings] body) → (loop* [bindings] body)"
[bindings & body]
(def result @[])
(array/push result {:jolt/type :symbol :ns nil :name "loop*"})
(array/push result bindings)
(each b body (array/push result b))
result)
# Protocol implementation — methods dispatch via type registry
(defn core-defprotocol [protocol-name & sigs]
(def result @[])
(array/push result {:jolt/type :symbol :ns nil :name "do"})
(def methods @{})
(each sig sigs
(def method-name (first sig))
(def arglists (tuple/slice sig 1))
(put methods (keyword (if (struct? method-name) (method-name :name) method-name)) {:name method-name :arglists arglists}))
(def proto-def @[])
(array/push proto-def {:jolt/type :symbol :ns nil :name "def"})
(array/push proto-def protocol-name)
(array/push proto-def @{:jolt/type :jolt/protocol
:name {:jolt/type :symbol :ns nil :name (protocol-name :name)}
:methods methods})
(array/push result proto-def)
(each sig sigs
(def method-name (first sig))
(def method-def @[])
(array/push method-def {:jolt/type :symbol :ns nil :name "def"})
(array/push method-def method-name)
(def fn-form @[])
(array/push fn-form {:jolt/type :symbol :ns nil :name "fn*"})
(array/push fn-form [{:jolt/type :symbol :ns nil :name "this"} {:jolt/type :symbol :ns nil :name "&"} {:jolt/type :symbol :ns nil :name "rest-args"}])
(array/push fn-form @[
{:jolt/type :symbol :ns nil :name "protocol-dispatch"}
protocol-name
method-name
{:jolt/type :symbol :ns nil :name "this"}
{:jolt/type :symbol :ns nil :name "rest-args"}])
(array/push method-def fn-form)
(array/push result method-def))
result)
(defn core-extend-type [type-sym proto-sym & impls]
(def result @[{:jolt/type :symbol :ns nil :name "do"}])
(each method-spec impls
(def method-name (method-spec 0))
(def arg-vec (method-spec 1))
(def body (tuple/slice method-spec 2))
(def fn-form @[{:jolt/type :symbol :ns nil :name "fn*"} arg-vec ;body])
(array/push result @[
{:jolt/type :symbol :ns nil :name "register-method"}
type-sym
proto-sym
method-name
fn-form]))
result)
(defn core-extend-protocol [proto-sym & type-impls]
(def result @[{:jolt/type :symbol :ns nil :name "do"}])
(var i 0)
(while (< i (length type-impls))
(let [type-sym (type-impls i)
methods (type-impls (+ i 1))]
# methods is a single method spec array or an array of method specs
# If the first element is a symbol (method name), treat as single spec
(if (and (struct? (methods 0)) (= :symbol ((methods 0) :jolt/type)))
(let [method-spec methods]
(def method-name (method-spec 0))
(def arg-vec (method-spec 1))
(def body (tuple/slice method-spec 2))
(def fn-form @[{:jolt/type :symbol :ns nil :name "fn*"} arg-vec ;body])
(array/push result @[
{:jolt/type :symbol :ns nil :name "register-method"}
type-sym
proto-sym
method-name
fn-form]))
(each method-spec methods
(def method-name (method-spec 0))
(def arg-vec (method-spec 1))
(def body (tuple/slice method-spec 2))
(def fn-form @[{:jolt/type :symbol :ns nil :name "fn*"} arg-vec ;body])
(array/push result @[
{:jolt/type :symbol :ns nil :name "register-method"}
type-sym
proto-sym
method-name
fn-form]))))
(+= i 2))
result)
(def core-extend (fn [& args] nil))
(defn core-reify [proto-sym & impls]
(def result @[{:jolt/type :symbol :ns nil :name "do"}])
(def methods @{})
(var i 0)
(while (< i (length impls))
(let [method-spec (impls i)]
(def method-name (method-spec 0))
(def arg-vec (method-spec 1))
(def body (tuple/slice method-spec 2))
(put methods (keyword (if (struct? method-name) (method-name :name) method-name)) @{:fn* true :args arg-vec :body body})
(+= i 2)))
(array/push result @[
{:jolt/type :symbol :ns nil :name "make-reified"}
proto-sym
methods])
result)
(def core-satisfies? (fn [proto-sym obj] false))
(def core-extends? (fn [& args] false))
(def core-implements? (fn [& args] false))
(def core-type->str (fn [& args] ""))
(def- core-bindings
"Map of symbol name → function for all core functions."
@{"nil?" core-nil?
"some?" core-some?
"string?" core-string?
"number?" core-number?
"fn?" core-fn?
"keyword?" core-keyword?
"symbol?" core-symbol?
"vector?" core-vector?
"map?" core-map?
"seq?" core-seq?
"coll?" core-coll?
"true?" core-true?
"false?" core-false?
"identical?" core-identical?
"zero?" core-zero?
"pos?" core-pos?
"neg?" core-neg?
"even?" core-even?
"odd?" core-odd?
"empty?" core-empty?
"every?" core-every?
"+" core-+
"-" core-sub
"*" core-*
"/" core-/
"inc" core-inc
"dec" core-dec
"mod" core-mod
"rem" core-rem
"quot" core-quot
"max" core-max
"min" core-min
"=" core-=
"not=" core-not=
"<" core-<
">" core->
"<=" core-<=
">=" core->=
"conj" core-conj
"assoc" core-assoc
"dissoc" core-dissoc
"get" core-get
"get-in" core-get-in
"contains?" core-contains?
"count" core-count
"first" core-first
"rest" core-rest
"next" core-next
"cons" core-cons
"seq" core-seq
"vec" core-vec
"into" core-into
"merge" core-merge
"merge-with" core-merge-with
"keys" core-keys
"vals" core-vals
"select-keys" core-select-keys
"zipmap" core-zipmap
"map" core-map
"filter" core-filter
"remove" core-remove
"reduce" core-reduce
"take" core-take
"drop" core-drop
"take-while" core-take-while
"drop-while" core-drop-while
"concat" core-concat
"reverse" core-reverse
"nth" core-nth
"sort" core-sort
"sort-by" core-sort-by
"distinct" core-distinct
"group-by" core-group-by
"frequencies" core-frequencies
"partition" core-partition
"partition-by" core-partition-by
"range" core-range
"repeat" core-repeat
"iterate" core-iterate
"repeatedly" core-repeatedly
"identity" core-identity
"constantly" core-constantly
"complement" core-complement
"comp" core-comp
"partial" core-partial
"juxt" core-juxt
"memoize" core-memoize
"vector" core-vector
"hash-map" core-hash-map
"array-map" core-array-map
"hash-set" core-hash-set
"set" core-set
"list" core-list
"set?" core-set?
"disj" core-disj
"lazy-seq" core-lazy-seq
"make-lazy-seq" make-lazy-seq
"str" core-str
"name" core-name
"subs" core-subs
"print" core-print
"println" core-println
"pr" core-pr
"prn" core-prn
# Array primitives (for persistent data structures)
"alength" core-alength
"aget" core-aget
"aset" core-aset
"aclone" core-aclone
"object-array" core-object-array
"int-array" core-int-array
"to-array" core-to-array
# Bit operations
"bit-and" core-bit-and
"bit-or" core-bit-or
"bit-xor" core-bit-xor
"bit-not" core-bit-not
"bit-shift-left" core-bit-shift-left
"bit-shift-right" core-bit-shift-right
"unsigned-bit-shift-right" core-unsigned-bit-shift-right
# Integer coercion / unchecked math
"int" core-int
"unchecked-inc" core-unchecked-inc
"unchecked-dec" core-unchecked-dec
"unchecked-add" core-unchecked-add
"unchecked-subtract" core-unchecked-subtract
# Hash
"hash" core-hash
"atom" core-atom
"atom?" core-atom?
"deref" core-deref
"reset!" core-reset!
"swap!" core-swap!
"not" core-not
"and" core-and
"or" core-or
"when" core-when
"when-not" core-when-not
"if-let" core-if-let
"when-let" core-when-let
"if-some" core-if-some
"when-some" core-when-some
"doto" core-doto
"defn" core-defn
"defn-" core-defn-
"derive" core-derive
"isa?" core-isa?
"ancestors" core-ancestors
"descendants" core-descendants
"make-hierarchy" core-make-hierarchy
"underive" core-underive
"remove-method" core-remove-method
"remove-all-methods" core-remove-all-methods
"prefer-method" core-prefer-method
"Object" core-Object
"declare" core-declare
"fn" core-fn
"let" core-let
"loop" core-loop
"defprotocol" core-defprotocol
"extend-type" core-extend-type
"extend-protocol" core-extend-protocol
"extend" core-extend
"reify" core-reify
"satisfies?" core-satisfies?
"extends?" core-extends?
"implements?" core-implements?
"type->str" core-type->str
"volatile!" core-volatile!
"vswap!" core-vswap!
"vreset!" core-vreset!
"proxy" core-proxy
"Thread" core-Thread
"ThreadLocal" core-ThreadLocal
"IllegalStateException" core-IllegalStateException
"definterface" core-definterface
"defrecord" core-defrecord
"resolve" core-resolve
"update" core-update
"copy-core-var" core-copy-core-var
"copy-var" core-copy-var
"macrofy" core-macrofy
"new-var" core-new-var
"avoid-method-too-large" core-avoid-method-too-large
"qualified-symbol?" core-qualified-symbol?
"meta" core-meta
"var-get" core-var-get
"var-set" core-var-set
"var?" core-var?
"alter-var-root" core-alter-var-root
"alter-meta!" core-alter-meta!
"reset-meta!" core-reset-meta!
"intern" core-intern
"binding" core-binding
"push-thread-bindings" core-push-thread-bindings
"pop-thread-bindings" core-pop-thread-bindings
# Dynamic vars — stubs for SCI bootstrap
"*unchecked-math*" false
"*clojure-version*" @{:major 1 :minor 11 :incremental 0 :qualifier nil}
"*1" :jolt/nil-sentinel
"*2" :jolt/nil-sentinel
"*3" :jolt/nil-sentinel
"*e" :jolt/nil-sentinel
"*assert" true})
(defn core-macro-names
"Set of core binding names that are macros."
[]
@{"and" true "or" true "when" true "when-not" true "if-let" true "when-let" true "if-some" true "when-some" true "doto" true "defn" true "defn-" true "declare" true "fn" true "let" true "loop" true "defrecord" true "defprotocol" true "extend-type" true "extend-protocol" true "extend" true "reify" true "proxy" true "definterface" true "comment" true "binding" true "lazy-seq" true})
(def init-core!
(fn [& args]
(case (length args)
1 (let [ctx (args 0)
ns (ctx-find-ns ctx "clojure.core")]
(loop [[name fn] :pairs core-bindings]
(def v (ns-intern ns name (if (= fn :jolt/nil-sentinel) nil fn)))
(when (get (core-macro-names) name)
(put v :macro true)))
ns)
2 (let [ctx (args 0) ns-name (args 1)
ns (ctx-find-ns ctx ns-name)]
(loop [[name fn] :pairs core-bindings]
(def v (ns-intern ns name (if (= fn :jolt/nil-sentinel) nil fn)))
(when (get (core-macro-names) name)
(put v :macro true)))
ns)
(error "Wrong number of args passed to: init-core!"))))