diff --git a/README.md b/README.md index e439b24..5e8f539 100644 --- a/README.md +++ b/README.md @@ -35,10 +35,14 @@ This compiles `src/jolt/*.janet` into a standalone `build/jolt` executable. Requ ## 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) @@ -51,6 +55,14 @@ user=> (fib 10) 55 ``` +Running a file evaluates its top-level forms: + +``` +$ echo '(println "hello" (* 6 7))' > hello.clj +$ build/jolt hello.clj +hello 42 +``` + ## Test ``` diff --git a/src/jolt/core.janet b/src/jolt/core.janet index 92625c0..3427d07 100644 --- a/src/jolt/core.janet +++ b/src/jolt/core.janet @@ -1207,20 +1207,32 @@ # I/O — minimal wrappers # ============================================================ -(def core-print print) -(def core-println (fn [& xs] (apply print xs) (print "\n") nil)) +# print/println use str semantics (bare strings); pr/prn use readable (quoted). +# 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] (var i 0) (while (< i (length xs)) (if (> i 0) (prin " ")) - (prin (xs i)) + (let [b @""] (pr-render b (xs i)) (prin (string b))) (++ i)) nil) (defn core-prn [& xs] (apply core-pr xs) - (print "\n") + (prin "\n") nil) (defn core-pr-str [& xs] diff --git a/src/jolt/main.janet b/src/jolt/main.janet index 5cad7b0..6e8a91f 100644 --- a/src/jolt/main.janet +++ b/src/jolt/main.janet @@ -163,10 +163,9 @@ (write-value v buf) (print (string buf))) -(defn main [&] +(defn- run-repl [] (print "Jolt — Clojure on Janet") (print "Type (exit) to quit.\n") - (var running true) (var pending "") # accumulates a form split across multiple input lines (while running @@ -190,3 +189,44 @@ (try (print-value (eval-string ctx input)) ([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))))