feat: CLI file execution — 'jolt file.clj [args]' runs a script (binds *command-line-args*/*file*), '-e EXPR' evaluates, '-h' help; fix print/println/pr/prn to space-separate, render collections, and not double-newline

This commit is contained in:
Yogthos 2026-06-04 16:40:04 -04:00
parent 37c8971d41
commit e87f6db10e
3 changed files with 72 additions and 8 deletions

View file

@ -35,10 +35,14 @@ This compiles `src/jolt/*.janet` into a standalone `build/jolt` executable. Requ
## Run ## Run
``` ```
build/jolt build/jolt # start a REPL
build/jolt file.clj [args] # run a Clojure file (binds *command-line-args*)
build/jolt -e EXPR [args] # evaluate EXPR and print the result
build/jolt -h # help
``` ```
Drops into a read-eval-print loop where you can type Clojure expressions: With no arguments it drops into a read-eval-print loop (multi-line forms are
accumulated until balanced):
``` ```
user=> (+ 1 2) user=> (+ 1 2)
@ -51,6 +55,14 @@ user=> (fib 10)
55 55
``` ```
Running a file evaluates its top-level forms:
```
$ echo '(println "hello" (* 6 7))' > hello.clj
$ build/jolt hello.clj
hello 42
```
## Test ## Test
``` ```

View file

@ -1207,20 +1207,32 @@
# I/O — minimal wrappers # I/O — minimal wrappers
# ============================================================ # ============================================================
(def core-print print) # print/println use str semantics (bare strings); pr/prn use readable (quoted).
(def core-println (fn [& xs] (apply print xs) (print "\n") nil)) # All space-separate their args, like Clojure.
(defn core-print [& xs]
(var i 0)
(while (< i (length xs))
(if (> i 0) (prin " "))
(prin (str-render-one (xs i)))
(++ i))
nil)
(defn core-println [& xs]
(apply core-print xs)
(prin "\n")
nil)
(defn core-pr [& xs] (defn core-pr [& xs]
(var i 0) (var i 0)
(while (< i (length xs)) (while (< i (length xs))
(if (> i 0) (prin " ")) (if (> i 0) (prin " "))
(prin (xs i)) (let [b @""] (pr-render b (xs i)) (prin (string b)))
(++ i)) (++ i))
nil) nil)
(defn core-prn [& xs] (defn core-prn [& xs]
(apply core-pr xs) (apply core-pr xs)
(print "\n") (prin "\n")
nil) nil)
(defn core-pr-str [& xs] (defn core-pr-str [& xs]

View file

@ -163,10 +163,9 @@
(write-value v buf) (write-value v buf)
(print (string buf))) (print (string buf)))
(defn main [&] (defn- run-repl []
(print "Jolt — Clojure on Janet") (print "Jolt — Clojure on Janet")
(print "Type (exit) to quit.\n") (print "Type (exit) to quit.\n")
(var running true) (var running true)
(var pending "") # accumulates a form split across multiple input lines (var pending "") # accumulates a form split across multiple input lines
(while running (while running
@ -190,3 +189,44 @@
(try (try
(print-value (eval-string ctx input)) (print-value (eval-string ctx input))
([err] (eprint "Error: " err)))))))))))) ([err] (eprint "Error: " err))))))))))))
(defn- set-command-line-args [argv]
# bind clojure.core/*command-line-args* to a vector of the remaining args
(ns-intern (ctx-find-ns ctx "clojure.core") "*command-line-args*"
(tuple/slice (tuple ;argv))))
(defn- run-file [path argv]
(set-command-line-args argv)
(ns-intern (ctx-find-ns ctx "clojure.core") "*file*" path)
(if (not (os/stat path))
(do (eprint "Error: file not found: " path) (os/exit 1))
(let [src (slurp path)]
(try
(load-string ctx src)
([err] (eprint "Error: " err) (os/exit 1))))))
(defn- run-eval [expr argv]
(set-command-line-args argv)
(try
(let [v (load-string ctx expr)]
(when (not (nil? v)) (print-value v)))
([err] (eprint "Error: " err) (os/exit 1))))
(defn- print-help []
(print "Jolt — a Clojure interpreter on Janet\n")
(print "Usage:")
(print " jolt Start a REPL")
(print " jolt FILE.clj [args] Run a Clojure file (binds *command-line-args*)")
(print " jolt -e EXPR [args] Evaluate EXPR and print the result")
(print " jolt -h | --help Show this help"))
(defn main [&]
(def args (or (dyn :args) @[])) # @["jolt" arg1 arg2 ...]
(def argv (if (> (length args) 1) (array/slice args 1) @[]))
(ctx-set-current-ns ctx "user")
(cond
(empty? argv) (run-repl)
(or (= (argv 0) "-h") (= (argv 0) "--help")) (print-help)
(= (argv 0) "-e") (run-eval (get argv 1 "") (array/slice argv 2))
(= (argv 0) "-") (run-file "/dev/stdin" (array/slice argv 1))
(run-file (argv 0) (array/slice argv 1))))