resolve-sym's last resort silently resolved any unknown Clojure symbol
against Janet's root environment — leaking Janet builtins with JANET
semantics into Clojure code: (type 1) was Janet's :number, (gensym) returned
Janet symbols (the long-documented (symbol (str (gensym))) macro landmine
existed BECAUSE of this), compare/slurp/int?/any? likewise. The explicit
janet/ prefix is the deliberate interop channel; the implicit fallback is
gone — an unresolved symbol is an error.
What the leak was masking, now proper interned vars:
- gensym: jolt's own (already existed, never interned) — returns real jolt
symbols; the macro landmine is dead
- compare: full Clojure total order (nil-first, numbers, strings, keywords,
symbols by ns/name, booleans, chars, uuid/inst, vectors by length then
elementwise; cross-type throws)
- type: :type metadata override, deftype/record tag as symbol, else a
taxonomy keyword (host-classified)
- int?: core-integer? — which had a latent bug the leak hid: (integer?
##Inf) was true (floor of inf is inf); NaN/infinities now excluded
- any?: constantly true (Clojure 1.9; SCI's namespaces.cljc needs it)
- jolt.interop/janet-type now uses the explicit (janet/type x) channel
- evaluator-test uses init (a bare make-ctx resolved EVERYTHING via the leak)
Suite 4470 -> 4532+ pass / 86-87 clean (proper compare unlocks the sort
files); baselines raised. Conformance 326x3 (+5 rows), +22 predicate spec
rows, stdlib battery green, all specs+unit. Coverage dashboard now counts
previously-leak-resolvable names honestly (missing-portable 19 -> 27).
map? treated ANY struct as a map, so (map? 'sym), (map? \a), and
(map? (random-uuid)) were all true; coll? had the same wart. Meanwhile both
were FALSE for sorted maps (and coll? for sorted sets and records), which are
collections in Clojure. Now: a map is a plain struct literal, a phm, a sorted
map, or a record; coll? additionally includes sorted sets. Tagged structs
(anything with :jolt/type) are values.
The loose-map? dependents (destructure's clause ordering, defn's attr-map
guard) already guarded with symbol? first, so nothing relied on the wart —
full gate green, and the suite gained: 4074 -> 4081 pass / 72 clean files
(map_qmark/coll_qmark assertions now correct); baselines raised. 22 new
strictness spec cases.
* core: fix jolt-265 — syntax-quote fully-qualifies core syms to clojure.core/
Re-attempt of the deferred gap, now unblocked. The earlier uberscript break
wasn't qualification itself but an aliased-ref resolution bug it exposed:
resolve-var looked up ns-aliases (e.g. g/foo) against the analyzer's REBOUND
ctx-current-ns (jolt.analyzer, since the analyzer runs interpreted in its own
ns) instead of the namespace being compiled. A user's aliased refs failed
mid-compile (g/hello -> nil in the bundled standalone).
- resolve-var resolves aliases against :compile-ns when set (same ns
h-current-ns uses), falling back to ctx-current-ns — correct for both modes.
- sq-symbol qualifies a resolved clojure.core name to clojure.core/<name>
(Clojure hygiene); special forms stay bare; unresolved syms -> current ns.
Tests updated to the qualified behavior (features-test, reader-forms-spec).
* test: comprehensive spec — regex + sorted colls + random/predicate gaps
Filling the biggest untested clojure.core areas found in a coverage audit
(168 of 506 provided fns had no spec). New + expanded suites:
- regex-spec.janet (20): #"…" literals, regex?, re-find/re-matches/re-seq
(match/no-match/groups), re-pattern, and clojure.string split/replace with
regex (incl $1 backrefs). Whole area was previously unspecced.
- sorted-spec.janet (14): sorted-map/sorted-set construction + ordering, sorted?,
subseq/rsubseq. Pins the working subset — get/conj/assoc/keys/vals on sorted
colls and the by-comparator ctors are not yet first-class (jolt-ti9).
- predicates-spec +14: seqable?, integer?, reduced?/unreduced, not-empty.
- numbers-spec +5: rand/rand-int/rand-nth invariants.
Fix: sorted? was bound to core-sorted-map? so it returned false for sorted-sets;
now true for both sorted maps and sets (core-sorted?).
Filed: jolt-ti9 (sorted collections incomplete: get/conj/assoc/keys/vals don't
operate on the sorted wrapper; sorted-*-by ignore the comparator).
Gate green incl full jpm build + jpm test.
* core: close surfaced gaps — first-class sorted colls, with-out-str, rand arity, deref reduced
jolt-ti9: sorted-map/sorted-set are now first-class across the collection fns —
get/assoc/dissoc/conj/contains?/keys/vals/disj and call-as-fn all operate on the
wrapper and preserve sort order. The by-comparator constructors (sorted-map-by/
sorted-set-by) now thread the user comparator (numeric or boolean-predicate) through
all derived colls. Sorted predicates/ctors/ops moved above core-conj so the
collection fns can branch on them; jolt-invoke (interpreter) gets inline branches.
jolt-rfw: add with-out-str (binds output to a string buffer) + the macro.
jolt-ek3: (rand n) arity and deref-of-reduced (uuid? still deferred).
Specs: new io-spec.janet; sorted-spec expanded to pin the now-working map/set ops
and by-comparator ordering; predicate/number spec restorations.
* remove old doc
* core: fix stale comment — by-comparator sorted ctors are implemented
---------
Co-authored-by: Yogthos <yogthos@gmail.com>
adds self-hosted compiler is functionally:
- The default compile path is the portable pipeline using jolt.analyzer (Clojure) → host-neutral IR → backend.janet.
- The analyzer is itself Clojure, compiled by jolt for true self-hosting.
- bootstrap-fixpoint passes (stage1 == stage2 == stage3): rebuilding the compiler on its own output.
- clojure.core is now self-hosted in the overlay.
- Stateful forms (defmacro/ns/deftype/defmulti/require/in-ns) are interpreted by design.
- case: quote list literals (read as arrays) in constant position so a wrapped
list ((a b c)) matches by value instead of being evaluated as a call; symbol
constants already quoted. Vector/map/set constants already worked. case errors
in the suite drop to 0 (60 pass).
- associative?: true only for vectors (pvec) and maps (phm/struct/sorted-map),
not lists/tuples-from-seq-fns/lazy-seqs/sets.
- reversible?: true for vectors and sorted-map/sorted-set only.
- update: coerce f via as-fn so (update m k :kw)/(update m k a-set) work; extra
args already handled.
- nth: (nth nil i)/(nth nil i default) returns nil/default instead of throwing.
clojure-test-suite pass 3649->3678, errors 122->105, clean files 44->46.
associative?/reversible? files now fully clean. spec: predicates + control/case.
jpm test green.
Mine the cljs port batteries into the spec layer and delete them (their behavior
is covered by spec; the unique functions they exercised are now specced).
Removed test/integration/ports/ entirely.
New/expanded spec coverage from the mining:
- spec/exceptions-spec: try/catch/finally, throw, ex-info/ex-message/ex-data/ex-cause
- doto, pr-str, keyword/symbol constructors, atom?, dynamic var binding
Two rare edges filed (jolt-...): rethrow of a caught ex-info re-wraps it; var-set
on a dynamic var inside binding no-ops. Core try/catch/ex-info and binding work.
Test layout is now spec (22 files, ~677 cases) / integration / unit / support.
conformance 218/218, jpm test green.
Add spec suites for numbers/arithmetic, strings (str + clojure.string), and
type/value predicates. Bugs they caught and fixed:
- <, >, <=, >= were binary-only; now variadic ((< 1 2 3) chains)
- seq? was true for vectors; vectors are not ISeq in Clojure, so (seq? [1])
is now false (true only for lists/lazy-seqs)
- clojure.string/index-of and last-index-of were 1-based (stray inc); now
0-based per Clojure
Corrected a systematic-coverage assertion that encoded the old seq? bug.
jpm test green, conformance 218/218.