Skip to content

Commit d8a47d9

Browse files
JustinIACdnolen
authored andcommitted
CLJS-1456: require forms at REPL can corrupt the current namespace
Wrap repl special functions within save/restore compiler state.
1 parent c7e49a9 commit d8a47d9

File tree

1 file changed

+77
-56
lines changed

1 file changed

+77
-56
lines changed

src/main/clojure/cljs/repl.cljc

Lines changed: 77 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -617,6 +617,26 @@
617617
(= ns ana/*cljs-ns*))))
618618
specs))
619619

620+
(defn- wrap-self
621+
"Takes a self-ish fn and returns it wrapped with exception handling.
622+
Compiler state is restored if self-ish fn fails."
623+
[f]
624+
(fn g
625+
([a b c]
626+
(g a b c nil))
627+
([a b c d]
628+
(let [backup-comp @env/*compiler*]
629+
(try
630+
(apply f [a b c d])
631+
(catch #?(:clj Exception :cljs js/Error) e ;;Exception
632+
(reset! env/*compiler* backup-comp)
633+
(throw e)))))))
634+
635+
(defn- wrap-special-fns
636+
[wfn fns]
637+
"Wrap wfn around all (fn) values in fns hashmap."
638+
(into {} (for [[k v] fns] [k (wfn v)])))
639+
620640
(def default-special-fns
621641
(let [load-file-fn
622642
(fn self
@@ -637,62 +657,63 @@
637657
(-evaluate repl-env "<cljs repl>" 1
638658
(str "goog.provide('" (comp/munge ns-name) "');")))
639659
(set! ana/*cljs-ns* ns-name)))]
640-
{'in-ns in-ns-fn
641-
'clojure.core/in-ns in-ns-fn
642-
'require
643-
(fn self
644-
([repl-env env form]
645-
(self repl-env env form nil))
646-
([repl-env env [_ & specs :as form] opts]
647-
(let [is-self-require? (self-require? specs)
648-
[target-ns restore-ns]
649-
(if-not is-self-require?
650-
[ana/*cljs-ns* nil]
651-
['cljs.user ana/*cljs-ns*])]
652-
(evaluate-form repl-env env "<cljs repl>"
653-
(with-meta
654-
`(~'ns ~target-ns
655-
(:require ~@(-> specs canonicalize-specs decorate-specs)))
656-
{:merge true :line 1 :column 1})
657-
identity opts)
658-
(when is-self-require?
659-
(set! ana/*cljs-ns* restore-ns)))))
660-
'require-macros
661-
(fn self
662-
([repl-env env form]
663-
(self repl-env env form nil))
664-
([repl-env env [_ & specs :as form] opts]
665-
(evaluate-form repl-env env "<cljs repl>"
666-
(with-meta
667-
`(~'ns ~ana/*cljs-ns*
668-
(:require-macros ~@(-> specs canonicalize-specs decorate-specs)))
669-
{:merge true :line 1 :column 1})
670-
identity opts)))
671-
'import
672-
(fn self
673-
([repl-env env form]
674-
(self repl-env env form nil))
675-
([repl-env env [_ & specs :as form] opts]
676-
(evaluate-form repl-env env "<cljs repl>"
677-
(with-meta
678-
`(~'ns ~ana/*cljs-ns*
679-
(:import
680-
~@(map
681-
(fn [quoted-spec-or-kw]
682-
(if (keyword? quoted-spec-or-kw)
683-
quoted-spec-or-kw
684-
(second quoted-spec-or-kw)))
685-
specs)))
686-
{:merge true :line 1 :column 1})
687-
identity opts)))
688-
'load-file load-file-fn
689-
'clojure.core/load-file load-file-fn
690-
'load-namespace
691-
(fn self
692-
([repl-env env form]
693-
(self env repl-env form nil))
694-
([repl-env env [_ ns :as form] opts]
695-
(load-namespace repl-env ns opts)))}))
660+
(wrap-special-fns wrap-self
661+
{'in-ns in-ns-fn
662+
'clojure.core/in-ns in-ns-fn
663+
'require
664+
(fn self
665+
([repl-env env form]
666+
(self repl-env env form nil))
667+
([repl-env env [_ & specs :as form] opts]
668+
(let [is-self-require? (self-require? specs)
669+
[target-ns restore-ns]
670+
(if-not is-self-require?
671+
[ana/*cljs-ns* nil]
672+
['cljs.user ana/*cljs-ns*])]
673+
(evaluate-form repl-env env "<cljs repl>"
674+
(with-meta
675+
`(~'ns ~target-ns
676+
(:require ~@(-> specs canonicalize-specs decorate-specs)))
677+
{:merge true :line 1 :column 1})
678+
identity opts)
679+
(when is-self-require?
680+
(set! ana/*cljs-ns* restore-ns)))))
681+
'require-macros
682+
(fn self
683+
([repl-env env form]
684+
(self repl-env env form nil))
685+
([repl-env env [_ & specs :as form] opts]
686+
(evaluate-form repl-env env "<cljs repl>"
687+
(with-meta
688+
`(~'ns ~ana/*cljs-ns*
689+
(:require-macros ~@(-> specs canonicalize-specs decorate-specs)))
690+
{:merge true :line 1 :column 1})
691+
identity opts)))
692+
'import
693+
(fn self
694+
([repl-env env form]
695+
(self repl-env env form nil))
696+
([repl-env env [_ & specs :as form] opts]
697+
(evaluate-form repl-env env "<cljs repl>"
698+
(with-meta
699+
`(~'ns ~ana/*cljs-ns*
700+
(:import
701+
~@(map
702+
(fn [quoted-spec-or-kw]
703+
(if (keyword? quoted-spec-or-kw)
704+
quoted-spec-or-kw
705+
(second quoted-spec-or-kw)))
706+
specs)))
707+
{:merge true :line 1 :column 1})
708+
identity opts)))
709+
'load-file load-file-fn
710+
'clojure.core/load-file load-file-fn
711+
'load-namespace
712+
(fn self
713+
([repl-env env form]
714+
(self env repl-env form nil))
715+
([repl-env env [_ ns :as form] opts]
716+
(load-namespace repl-env ns opts)))})))
696717

697718
(defn analyze-source
698719
"Given a source directory, analyzes all .cljs files. Used to populate

0 commit comments

Comments
 (0)