Skip to content

Commit

Permalink
REPL improvements (squint-cljs#329)
Browse files Browse the repository at this point in the history
  • Loading branch information
borkdude authored Sep 17, 2023
1 parent 69332c2 commit 20ab42f
Show file tree
Hide file tree
Showing 5 changed files with 44 additions and 25 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,5 @@ public
.test
scratch.js
compiler-common
garbage.js
playground
4 changes: 3 additions & 1 deletion bb/node_repl_tests.clj
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,9 @@
(is (str/includes? (:out (repl "(defn foo [x] x) (foo 1)")) "1"))
(is (str/includes? (:out (repl "\"foo\"")) "foo"))
(is (str/includes? (:out (repl "(ns foo (:require [\"playwright$default\" :as pw])) (let [chrome pw/chromium] (when (some? chrome) :success))")) "success"))
(is (str/includes? (:out (repl "(require '[\"playwright$default\" :as pw]) (let [chrome pw/chromium] (when (some? chrome) :success))")) "success")))
(is (str/includes? (:out (repl "(require '[\"playwright$default\" :as pw]) (let [chrome pw/chromium] (when (some? chrome) :success))")) "success"))
(is (str/includes? (:out (repl "(loop [] 1)")) "1"))
(is (str/includes? (:out (repl "(defn ^:async foo [] (let [x (js-await (js/Promise.resolve 10))] (str \"the-answer\"(inc x)))) (foo)")) "the-answer11")))

(defn run-tests [_]
(let [{:keys [fail error]}
Expand Down
7 changes: 5 additions & 2 deletions src/squint/compiler.cljc
Original file line number Diff line number Diff line change
Expand Up @@ -383,8 +383,11 @@
imported-vars (atom {})
public-vars (atom #{})
aliases (atom {core-alias cc/*core-package*})
imports (atom (format "import * as %s from '%s';\n"
core-alias cc/*core-package*))]
imports (atom (if cc/*repl*
(format "var %s = await import('%s');\n"
core-alias cc/*core-package*)
(format "import * as %s from '%s';\n"
core-alias cc/*core-package*)))]
(binding [*imported-vars* imported-vars
*public-vars* public-vars
*aliases* aliases
Expand Down
34 changes: 21 additions & 13 deletions src/squint/compiler_common.cljc
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@
#?(:cljs (derive js/Number ::number))

(defn emit-repl [s env]
(if (and *repl*
s #_(if (and *repl*
(:top-level env))
(str "\nglobalThis._repl = " s)
s))
Expand Down Expand Up @@ -210,7 +210,7 @@
(munge resolved-ns)
sym-ns) "." #_#_sym-ns "_" (munged-name sn)))
(if *repl*
(str "globalThis." (munge *cljs-ns*) ".aliases." (munge (namespace expr)) "." (munge (name expr)))
(str "globalThis." (munge *cljs-ns*) "." #_".aliases." (munge (namespace expr)) "." (munge (name expr)))
(str (munge (namespace expr)) "." (munge (name expr))))))
(if-let [renamed (get (:var->ident env) expr)]
(munge** (str renamed))
Expand All @@ -228,12 +228,16 @@
env)
(emit-repl env))))))

(defn wrap-await [s]
(format "(%s)" (str "await " s)))
(defn wrap-await
([s] (wrap-await s false))
([s return?]
(format "%s(%s)" (if return? "return " "") (str "await " s))))

(defn wrap-iife [s]
(cond-> (format "(%sfunction () {\n %s\n})()" (if *async* "async " "") s)
*async* (wrap-await)))
(defn wrap-iife
([s] (wrap-iife s false))
([s return?]
(cond-> (format "(%sfunction () {\n %s\n})()" (if *async* "async " "") s)
*async* (wrap-await return?))))

(defn emit-do [env exprs]
(let [bl (butlast exprs)
Expand Down Expand Up @@ -274,7 +278,7 @@
["" upper-var->ident]
partitioned))
enc-env (assoc enc-env :var->ident var->ident :top-level false)]
(-> (cond->> (str
(-> (cond-> (str
bindings
(when is-loop
(str "while(true){\n"))
Expand All @@ -290,7 +294,7 @@
;; (loop [x 1] (+ 1 2 x)) breaks
(str ";break;\n}\n")))
iife?
(wrap-iife))
(wrap-iife (= :return (:context enc-env))))
(emit-repl env))))

(defmethod emit-special 'let* [_type enc-env [_let bindings & body]]
Expand Down Expand Up @@ -417,13 +421,17 @@
as (when as (munge as))
expr (str
(when (and as (= "default" p))
(statement (format "import %s from '%s'" as libname)))
(if *repl*
(statement (format "const %s = (await import('%s')).default" as libname))
(statement (format "import %s from '%s'" as libname))))
(when (and (not as) (not p) (not refer))
;; import presumably for side effects
(statement (format "import '%s'" libname)))
(when (and as (not= "default" p))
(swap! *imported-vars* update libname (fnil identity #{}))
(statement (format "import * as %s from '%s'" as libname)))
(statement (if *repl*
(format "var %s = await import('%s')" as libname)
(format "import * as %s from '%s'" as libname))))
(when refer
(statement (format "import { %s } from '%s'" (str/join ", " (map munge refer)) libname))))]
(swap! (:imports env) str expr)
Expand Down Expand Up @@ -475,7 +483,7 @@
(reduce-kv (fn [acc k _v]
(if (symbol? k)
(str acc
ns-obj ".aliases." k " = " k ";\n")
ns-obj "." #_".aliases." k " = " k ";\n")
acc))
""
@*aliases*))))))
Expand Down Expand Up @@ -511,7 +519,7 @@
(reduce-kv (fn [acc k _v]
(if (symbol? k)
(str acc
ns-obj ".aliases." k " = " k ";\n")
ns-obj "." #_".aliases." k " = " k ";\n")
acc))
""
@*aliases*)))))))
Expand Down
22 changes: 13 additions & 9 deletions src/squint/repl/node.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@

(def last-ns (atom *cljs-ns*))

(defn eval-js [js-str]
#_(defn eval-js [js-str]
(let [filename (str ".repl/" (gensym) ".mjs")]
(when-not (fs/existsSync ".repl")
(fs/mkdirSync ".repl"))
Expand All @@ -84,19 +84,23 @@
(defn compile [the-val rl socket]
(let [{js-str :javascript
cljs-ns :ns} (binding [*cljs-ns* @last-ns]
(compiler/compile-string* (pr-str the-val)))]
(compiler/compile-string* (binding [*print-meta* true]
(pr-str the-val)) {:context :return
:elide-exports true}))
js-str (str/replace "(async function () {\n%s\n}) ()" "%s" js-str)]
#_(println :js-str js-str)
(reset! last-ns cljs-ns)
(->
(eval-js js-str)
(.then (fn [^js _val]
(squint/println js/globalThis._repl)
(continue rl socket)))
(js/Promise.resolve (js/eval js-str))
(.then (fn [^js val]
(squint/println val)
(eval-next socket rl)))
(.catch (fn [err]
(squint/println err)
(continue rl socket))))))

(defn eval-next [socket rl]
(when-not (or @in-progress (str/blank? @pending-input))
(when (or @in-progress (not (str/blank? @pending-input)))
(reset! in-progress true)
(let [rdr (e/reader @pending-input)
the-val (try (e/parse-next rdr)
Expand All @@ -116,7 +120,7 @@
(if-not (= :edamame.core/eof the-val)
;; (prn :pending @pending)
(compile the-val rl socket)
(reset! in-progress false)))))))
(continue rl socket) #_(reset! in-progress false)))))))

(defn input-handler [socket rl input]
(swap! pending-input str input "\n")
Expand Down Expand Up @@ -174,7 +178,7 @@
(set! *repl* true)
(set! *async* true)
(when tty (.setRawMode js/process.stdin true))
(.then (eval-js "globalThis.user = globalThis.user || {};")
(.then (js/Promise.resolve (js/eval "globalThis.user = globalThis.user || {};"))
(fn [_]
(js/Promise. (fn [resolve]
(input-loop nil resolve)))))))

0 comments on commit 20ab42f

Please sign in to comment.