A Clojure compiler implemented on top of Chez Scheme https://jolt-lang.github.io/
Find a file
Yogthos d33277c0b2 REPL fixes + an nREPL server for editor-connected dev
The line REPL was broken (read-line called nil — the __stdin-read-line host seam
the clojure.core *in* reader drives was never implemented on Chez) and didn't
load the project, so (require '[some.lib]) failed. Now:

- __stdin-read-line reads a line from stdin (get-line); read-line / read / the
  REPL work.
- repl resolves the project first (deps on the roots, native libs loaded), so
  libraries are available — same context a run gets.
- jolt.nrepl: a jolt-native nREPL server (bencode over a loopback jolt.ffi
  socket) speaking the real protocol — clone / describe / eval / load-file /
  close, with stdout capture, :ns-scoped eval (in-ns; binding *ns* doesn't drive
  load-string resolution here), and real error text. 'joltc nrepl [port]' applies
  the project then serves; writes .nrepl-port. Editors (CIDER/Calva/Cursive)
  connect and develop live; project libraries load in the session.
- ex-message returns nil for raw Chez conditions, so jolt.host/condition-message
  exposes the condition text; the REPL and nREPL surface it instead of an opaque
  #<compound condition>.

Why native, not real nREPL: nrepl.server is welded to java.util.concurrent
executors, two compiled Java helper classes, a DynamicClassLoader, Compiler
internals and a JVMTI agent — not faithfully shimmable. The wire protocol, which
is what clients depend on, is small and implemented directly.

Runtime .ss + jolt-core, no re-mint. Full gate green.
2026-06-22 15:18:52 -04:00
.github/workflows CI runs behavior gates; self-host fixpoint is dev-only (jolt-8479) 2026-06-21 15:46:40 -04:00
bench Docs: Chez-only, drop the Janet-era references and obsolete migration notes 2026-06-22 09:05:35 -04:00
bin deps.edn resolution + a file loader + a project-aware CLI 2026-06-22 02:06:05 -04:00
docs REPL fixes + an nREPL server for editor-connected dev 2026-06-22 15:18:52 -04:00
host/chez REPL fixes + an nREPL server for editor-connected dev 2026-06-22 15:18:52 -04:00
img ci: run jpm bootstrap from inside the jpm checkout 2026-06-05 18:30:27 -04:00
jolt-core REPL fixes + an nREPL server for editor-connected dev 2026-06-22 15:18:52 -04:00
spike/chez Docs: Chez-only, drop the Janet-era references and obsolete migration notes 2026-06-22 09:05:35 -04:00
src/jolt jolt.ffi: a :blocking option for collect-safe foreign calls 2026-06-22 12:00:14 -04:00
test Byte-array <-> bytevector interop + charset-aware (String. bytes cs) 2026-06-22 13:20:27 -04:00
tools core: one alias store (jolt-ark); '.' classified as the special form it is 2026-06-10 18:37:19 -04:00
vendor SCI conformance gate (pure Chez) 2026-06-21 12:06:18 -04:00
.DS_Store Compiler research (#10) 2026-06-09 07:30:25 +08:00
.gitignore remove .calva from git 2026-06-08 19:31:26 -04:00
.gitmodules SCI conformance gate (pure Chez) 2026-06-21 12:06:18 -04:00
AGENTS.md Compiler research (#10) 2026-06-09 07:30:25 +08:00
CLAUDE.md Docs: Chez-only, drop the Janet-era references and obsolete migration notes 2026-06-22 09:05:35 -04:00
clojuredocs-export.edn records as shape-recs carrying a type tag (jolt-t34 R3) 2026-06-13 20:40:50 -04:00
clojuredocs-export.json records as shape-recs carrying a type tag (jolt-t34 R3) 2026-06-13 20:40:50 -04:00
LICENSE Initial commit: Jolt — Clojure interpreter on Janet 2026-06-01 16:48:56 -04:00
Makefile Remove built-in jolt.http.server (ring-janet-adapter library replaces it) 2026-06-22 12:19:04 -04:00
README.md Docs: Chez-only, drop the Janet-era references and obsolete migration notes 2026-06-22 09:05:35 -04:00

Jolt

tests

A Clojure implementation on Chez Scheme. Jolt reads Clojure source, analyzes it to a host-neutral IR, emits Scheme, and runs it on Chez. The compiler is self-hosted: it is written in Clojure (jolt-core/) and compiles itself. It ships a Clojure-compatible standard library.

Requirements

Only Chez Scheme (the gate invokes it as chez). The conformance gate additionally uses Clojure on the JVM as an oracle, but running jolt does not.

Build

There is no build step. The bootstrap seed (host/chez/seed/{prelude,image}.ss) is checked in, so a fresh clone runs immediately:

git clone --recurse-submodules https://github.com/jolt-lang/jolt.git
cd jolt
bin/joltc -e '(+ 1 2)'        # => 3

After changing a compiler source — the reader (host/chez/reader.ss), the analyzer/IR/backend (jolt-core/jolt/*.clj), or the clojure.core overlay (jolt-core/clojure/core/*.clj) — re-mint the seed:

make remint                   # iterates host/chez/bootstrap.ss to a byte-fixpoint

Run

bin/joltc -e EXPR             # evaluate a Clojure expression and print the result
$ bin/joltc -e '(->> (range 10) (filter even?) (map (fn [x] (* x x))) (reduce +))'
120
$ bin/joltc -e '(/ 1 2)'
1/2

Architecture

A small Chez runtime (host/chez/*.ss: value model, persistent collections, seqs, vars/namespaces, host interop) hosts a portable Clojure overlay (jolt-core/): the reader/analyzer/IR/backend (jolt-core/jolt/) and clojure.core in dependency-ordered tiers (jolt-core/clojure/core/NN-*.clj). The stdlib namespaces (clojure.string/set/walk/edn/pprint/…) are portable Clojure under src/jolt/clojure/.

bin/joltc loads the checked-in seed and the spine, then compiles and evaluates on Chez (read → analyze → IR → emit → eval). host/chez/bootstrap.ss rebuilds that seed from source on pure Chez; the build is a self-hosting fixpoint (a rebuild reproduces the checked-in seed byte-for-byte).

Differences from Clojure

Jolt targets Clojure semantics but runs on Chez, not the JVM.

  • Host platform. No JVM and no Java interop — import, gen-class, proxy of Java classes, and java.* are unavailable. A class token resolves to a name; a small set of host classes is recognized for instance?.
  • Numbers. The full Scheme numeric tower, matching the JVM: exact integers and bignums, exact ratios ((/ 1 2)1/2), and flonum doubles. = is category-aware ((= 3 3.0)false); == is value-equality ((== 3 3.0)true). integer?/int? are exact integers, float?/double? are flonums, ratio? is an exact non-integer. No BigDecimal (decimal? is always false).
  • Concurrency. future/promise/agent/pmap run on real OS threads over a shared heap, matching JVM semantics (not isolated-heap snapshots). Atoms use a per-atom mutex with JVM-style CAS. clojure.core.async provides blocking channels and go/<!/>!/alts!/timeout.
  • Regex. Backed by irregex (vendored), PCRE/Java-style patterns.
  • Collections. Immutable persistent vectors, cons lists, and HAMT maps/sets. Hash-map/hash-set iteration order is unspecified — use sorted-map/sorted-set when order matters. Transients are real mutable scratch collections.

Supported and Clojure-compatible: lazy/infinite sequences, transducers, destructuring, multimethods with hierarchies, protocols/records (deftype/defrecord/reify/extend-protocol), metadata, namespaces, runtime eval/load-string/defmacro, and the reader (#(), #_, #?, tagged literals, #"…").

Test

make test                     # the full gate
make corpus                   # conformance corpus vs the JVM-sourced spec
make unit                     # host-specific unit cases
make selfhost                 # bootstrap fixpoint (rebuild == checked-in seed)
make smoke                    # bin/joltc CLI smoke
make sci                      # load borkdude/sci's source through joltc (compat stress)
make ffi                      # HTTP-server GC-safety + http-client temp paths
make transient                # transient mutation + linear-time builds
make certify                  # JVM oracle (skips if clojure is absent)

The conformance corpus (test/chez/corpus.edn) is a host-neutral language spec whose expected values are sourced from reference JVM Clojure. See test/conformance/SPEC.md.

License

Eclipse Public License 1.0