From d0fce540ed9b75c3de039a53a26db1e2a7a9c76f Mon Sep 17 00:00:00 2001 From: Yogthos Date: Sat, 20 Jun 2026 06:53:05 -0400 Subject: [PATCH] Chez Phase 3 inc9b: pure-Chez runtime CLI (bin/joltc, no Janet) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The runtime counterpart to bootstrap.ss. host/chez/cli.ss loads the checked-in seed + the zero-Janet spine and compiles+evals a -e expression entirely on Chez; bin/joltc execs it. With the seed checked in, a clone runs jolt with only Chez installed — no Janet at build or run time. Multi-form -e wraps in (do ...) to match Clojure. test/chez/cli-test.janet 9/9. --- bin/joltc | 14 ++++++++++++ host/chez/cli.ss | 37 ++++++++++++++++++++++++++++++ test/chez/cli-test.janet | 49 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 100 insertions(+) create mode 100755 bin/joltc create mode 100644 host/chez/cli.ss create mode 100644 test/chez/cli-test.janet diff --git a/bin/joltc b/bin/joltc new file mode 100755 index 0000000..55e6664 --- /dev/null +++ b/bin/joltc @@ -0,0 +1,14 @@ +#!/bin/sh +# joltc (jolt-9phg, inc9b) — the pure-Chez jolt runtime. NO Janet. +# +# Runs a Clojure expression through the zero-Janet spine on Chez, using the +# checked-in bootstrap seed (host/chez/seed/). With only Chez installed and no +# Janet anywhere, this compiles and evaluates jolt code end to end. +# +# bin/joltc -e "(+ 1 2)" +# +# (bin/jolt-chez is the older Janet-hosted -e path still used as the corpus oracle; +# joltc is the fully self-hosted runtime.) +root="$(CDPATH= cd -- "$(dirname -- "$0")/.." && pwd)" +cd "$root" || exit 1 +exec chez --script host/chez/cli.ss "$@" diff --git a/host/chez/cli.ss b/host/chez/cli.ss new file mode 100644 index 0000000..b69c90a --- /dev/null +++ b/host/chez/cli.ss @@ -0,0 +1,37 @@ +;; cli.ss (jolt-9phg, Phase 3 inc9b) — the pure-Chez jolt runtime. NO Janet. +;; +;; This is the zero-Janet runtime counterpart to bootstrap.ss (the zero-Janet +;; build). It loads the checked-in seed (host/chez/seed/{prelude,image}.ss — the +;; bootstrap compiler) and the zero-Janet spine, reads a Clojure expression, and +;; compiles+evals it ON CHEZ (read -> analyze -> IR -> emit -> eval). With the seed +;; checked in, a clone of the repo runs jolt with only Chez installed — no Janet at +;; build or run time. +;; +;; Run from the repo root: +;; chez --script host/chez/cli.ss -e "EXPR" +(import (chezscheme)) + +(define cli-args (cdr (command-line))) ; drop the script name +(unless (and (= (length cli-args) 2) (string=? (car cli-args) "-e")) + (display "usage: cli.ss -e EXPR\n") + (exit 2)) +(define cli-expr (cadr cli-args)) + +;; Assemble the zero-Janet spine from the checked-in seed, exactly as +;; driver/program-zero-janet does — but with no Janet generating the program. +(load "host/chez/rt.ss") +(set-chez-ns! "clojure.core") +(load "host/chez/seed/prelude.ss") +(load "host/chez/post-prelude.ss") +(set-chez-ns! "user") +(load "host/chez/host-contract.ss") +(load "host/chez/seed/image.ss") +(load "host/chez/compile-eval.ss") + +;; Compile + eval on Chez; print the result (blank for nil, like the spine). Wrap +;; in (do ...) so a multi-form -e string evaluates every form and returns the last, +;; matching Clojure's -e (jolt-compile-eval reads a single form). +(let ((result (jolt-final-str + (jolt-compile-eval (string-append "(do " cli-expr ")") "user")))) + (unless (string=? result "") + (display result) (newline))) diff --git a/test/chez/cli-test.janet b/test/chez/cli-test.janet new file mode 100644 index 0000000..61451fb --- /dev/null +++ b/test/chez/cli-test.janet @@ -0,0 +1,49 @@ +# Chez Phase 3 inc9b (jolt-9phg) — the pure-Chez runtime CLI (no Janet). +# +# bin/joltc execs `chez --script host/chez/cli.ss`, which loads the checked-in +# bootstrap seed (host/chez/seed/) + the zero-Janet spine and compiles+evals a +# Clojure -e expression entirely on Chez. This test drives bin/joltc and checks +# results: with only Chez installed, jolt runs end to end — no Janet at build or +# run time. (This harness is Janet only to spawn the process; the compile+eval is +# 100% Chez.) +# +# janet test/chez/cli-test.janet +(import ../../host/chez/driver :as d) + +(var total 0) (var fails 0) +(defn ok [name pred &opt extra] + (++ total) + (if pred (printf "ok: %s" name) + (do (++ fails) (printf "FAIL: %s %s" name (or extra ""))))) + +(unless (d/chez-available?) + (print "chez not on PATH — skipping cli-test") + (os/exit 0)) + +(defn- joltc [expr] + (def proc (os/spawn ["bin/joltc" "-e" expr] :p {:out :pipe :err :pipe})) + (def out (string/trim (string (:read (proc :out) :all)))) + (def err (string/trim (string (or (:read (proc :err) :all) "")))) + (def code (os/proc-wait proc)) + [code out err]) + +(def cases + [["(+ 1 2)" "3"] + ["(defn fib [n] (if (< n 2) n (+ (fib (- n 1)) (fib (- n 2))))) (fib 15)" "610"] + ["(->> (range 10) (filter even?) (map #(* % %)) (reduce +))" "120"] + ["(let [{:keys [a b] :or {b 99}} {:a 1}] [a b])" "[1 99]"] + ["(require '[clojure.string :as s]) (s/upper-case \"hello\")" "HELLO"] + ["(case 3 1 :a 2 :b :other)" ":other"] + ["(reduce + (vals (reduce (fn [m k] (assoc m k (* k k))) {} [1 2 3])))" "14"] + ["(map inc [1 2 3])" "(2 3 4)"] + ["nil" ""]]) + +(each [src want] cases + (def [code out err] (joltc src)) + (ok (string "joltc: " (if (> (length src) 48) (string (string/slice src 0 48) "...") src)) + (and (= code 0) (= out want)) + (string "[" code "] got " (string/format "%j" out) " want " (string/format "%j" want) + (if (= "" err) "" (string " err: " (string/slice err 0 (min 120 (length err)))))))) + +(printf "\ncli-test: %d/%d checks passed" (- total fails) total) +(os/exit (if (zero? fails) 0 1))