Skip to content

Commit bd392de

Browse files
author
dnolen
committed
CLJS-1152: (require 'some.ns :reload) causes printing to stop working in browser REPL
REPL require and require-macros now canonicalizes spec into vector form, remove :reload and :reload-all from spec and instead annotate the spec vector with this information. Analyzer now checks for reload metadata on specs. If available populates reloads atom which maps ns and macro nses to reload type. handle individual ns macro reloads based on reloads map The ns AST now includes :reloads populated from reloads map in compiler emit :ns case, reload and reload-all libs based on :reloads information in ns form AST
1 parent ddede75 commit bd392de

File tree

3 files changed

+79
-55
lines changed

3 files changed

+79
-55
lines changed

src/clj/cljs/analyzer.clj

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1473,6 +1473,7 @@
14731473
:import (partial parse-import-spec env deps)}
14741474
valid-forms (atom #{:use :use-macros :require :require-macros :import})
14751475
reload (atom {:use nil :require nil :use-macros nil :require-macros nil})
1476+
reloads (atom {})
14761477
{uses :use requires :require use-macros :use-macros require-macros :require-macros imports :import :as params}
14771478
(reduce
14781479
(fn [m [k & libs]]
@@ -1481,11 +1482,16 @@
14811482
(when-not (@valid-forms k)
14821483
(throw (error env (str "Only one " k " form is allowed per namespace definition"))))
14831484
(swap! valid-forms disj k)
1485+
;; check for spec type reloads
14841486
(when-not (= :import k)
14851487
(when (some #{:reload} libs)
14861488
(swap! reload assoc k :reload))
14871489
(when (some #{:reload-all} libs)
14881490
(swap! reload assoc k :reload-all)))
1491+
;; check for individual ns reloads from REPL interactions
1492+
(when-let [xs (seq (filter #(-> % meta :reload) libs))]
1493+
(swap! reloads assoc k
1494+
(zipmap (map first xs) (map #(-> % meta :reload) xs))))
14891495
(apply merge-with merge m
14901496
(map (spec-parsers k)
14911497
(remove #{:reload :reload-all} libs))))
@@ -1498,13 +1504,15 @@
14981504
(when *load-macros*
14991505
(load-core)
15001506
(doseq [nsym (vals use-macros)]
1501-
(let [k (:use-macros @reload)]
1507+
(let [k (or (:use-macros @reload)
1508+
(get-in @reloads [:use-macros nsym]))]
15021509
(if k
15031510
(clojure.core/require nsym k)
15041511
(clojure.core/require nsym))
15051512
(intern-macros nsym k)))
15061513
(doseq [nsym (vals require-macros)]
1507-
(let [k (:require-macros @reload)]
1514+
(let [k (or (:require-macros @reload)
1515+
(get-in @reloads [:require-macros nsym]))]
15081516
(if k
15091517
(clojure.core/require nsym k)
15101518
(clojure.core/require nsym))
@@ -1535,7 +1543,8 @@
15351543
ns-info))
15361544
ns-info)]
15371545
(swap! env/*compiler* update-in [::namespaces name] merge ns-info)
1538-
(merge {:env env :op :ns :form form}
1546+
(merge {:env env :op :ns :form form
1547+
:reloads @reloads}
15391548
(cond-> ns-info
15401549
(@reload :use)
15411550
(update-in [:uses]

src/clj/cljs/compiler.clj

Lines changed: 36 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -839,46 +839,47 @@
839839
(emit-wrap env (emits target " = " val)))
840840

841841
(defn load-libs
842-
([libs] (load-libs libs nil))
843-
([libs seen]
844-
(let [loaded-libs (munge 'cljs.core.*loaded-libs*)
845-
loaded-libs-temp (munge (gensym 'cljs.core.*loaded-libs*))]
846-
(when (-> libs meta :reload-all)
847-
(emitln "if(!COMPILED) " loaded-libs-temp " = " loaded-libs " || cljs.core.set();")
848-
(emitln "if(!COMPILED) " loaded-libs " = cljs.core.set();"))
849-
(doseq [lib (remove (set (vals seen)) (distinct (vals libs)))]
850-
(cond
851-
(ana/foreign-dep? lib)
852-
(let [{:keys [target optimizations]} (get @env/*compiler* :options)]
853-
;; we only load foreign libraries under optimizations :none
854-
(when (= :none optimizations)
855-
(if (= :nodejs target)
856-
;; under node.js we load foreign libs globally
857-
(let [{:keys [js-dependency-index options]} @env/*compiler*
858-
ijs-url (get-in js-dependency-index [(name lib) :url])]
859-
(emitln "cljs.core.load_file(\""
860-
(str (io/file (util/output-directory options) (util/get-name ijs-url)))
861-
"\");"))
862-
(emitln "goog.require('" (munge lib) "');"))))
863-
864-
(-> libs meta :reload)
865-
(emitln "goog.require('" (munge lib) "', 'reload');")
866-
867-
(-> libs meta :reload-all)
868-
(emitln "goog.require('" (munge lib) "', 'reload-all');")
869-
870-
:else
871-
(emitln "goog.require('" (munge lib) "');")))
872-
(when (-> libs meta :reload-all)
873-
(emitln "if(!COMPILED) " loaded-libs " = cljs.core.into(" loaded-libs-temp ", " loaded-libs ");")))))
842+
[libs seen reloads]
843+
(let [loaded-libs (munge 'cljs.core.*loaded-libs*)
844+
loaded-libs-temp (munge (gensym 'cljs.core.*loaded-libs*))]
845+
(when (-> libs meta :reload-all)
846+
(emitln "if(!COMPILED) " loaded-libs-temp " = " loaded-libs " || cljs.core.set();")
847+
(emitln "if(!COMPILED) " loaded-libs " = cljs.core.set();"))
848+
(doseq [lib (remove (set (vals seen)) (distinct (vals libs)))]
849+
(cond
850+
(ana/foreign-dep? lib)
851+
(let [{:keys [target optimizations]} (get @env/*compiler* :options)]
852+
;; we only load foreign libraries under optimizations :none
853+
(when (= :none optimizations)
854+
(if (= :nodejs target)
855+
;; under node.js we load foreign libs globally
856+
(let [{:keys [js-dependency-index options]} @env/*compiler*
857+
ijs-url (get-in js-dependency-index [(name lib) :url])]
858+
(emitln "cljs.core.load_file(\""
859+
(str (io/file (util/output-directory options) (util/get-name ijs-url)))
860+
"\");"))
861+
(emitln "goog.require('" (munge lib) "');"))))
862+
863+
(or (-> libs meta :reload)
864+
(= (get reloads lib) :reload))
865+
(emitln "goog.require('" (munge lib) "', 'reload');")
866+
867+
(or (-> libs meta :reload-all)
868+
(= (get reloads lib) :reload-all))
869+
(emitln "goog.require('" (munge lib) "', 'reload-all');")
870+
871+
:else
872+
(emitln "goog.require('" (munge lib) "');")))
873+
(when (-> libs meta :reload-all)
874+
(emitln "if(!COMPILED) " loaded-libs " = cljs.core.into(" loaded-libs-temp ", " loaded-libs ");"))))
874875

875876
(defmethod emit* :ns
876-
[{:keys [name requires uses require-macros env]}]
877+
[{:keys [name requires uses require-macros reloads env]}]
877878
(emitln "goog.provide('" (munge name) "');")
878879
(when-not (= name 'cljs.core)
879880
(emitln "goog.require('cljs.core');"))
880-
(load-libs requires)
881-
(load-libs uses requires))
881+
(load-libs requires nil (:require reloads))
882+
(load-libs uses requires (:use reloads)))
882883

883884
(defmethod emit* :deftype*
884885
[{:keys [t fields pmasks body]}]

src/clj/cljs/repl.clj

Lines changed: 31 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -519,6 +519,32 @@
519519
((or (:wrap opts) wrap-fn) form)
520520
opts)))
521521

522+
(defn canonicalize-specs [specs]
523+
(letfn [(canonicalize [quoted-spec-or-kw]
524+
(if (keyword? quoted-spec-or-kw)
525+
quoted-spec-or-kw
526+
(as-> (second quoted-spec-or-kw) spec
527+
(if (vector? spec) spec [spec]))))]
528+
(map canonicalize specs)))
529+
530+
(defn decorate-specs [specs]
531+
(if-let [k (some #{:reload :reload-all} specs)]
532+
(->> specs (remove #{k}) (map #(vary-meta % assoc :reload k)))
533+
specs))
534+
535+
(comment
536+
(canonicalize-specs
537+
'['foo.bar '[bar.core :as bar]])
538+
539+
(canonicalize-specs
540+
'['foo.bar '[bar.core :as bar] :reload])
541+
542+
(map meta
543+
(decorate-specs
544+
(canonicalize-specs
545+
'['foo.bar '[bar.core :as bar] :reload])))
546+
)
547+
522548
;; Special REPL fns, these provide compatiblity with Clojure functions
523549
;; that are not possible to reproduce given ClojureScript's compilation model
524550
;; All functions should have the following signature
@@ -578,43 +604,31 @@
578604
(evaluate-form repl-env env "<cljs repl>"
579605
(with-meta
580606
`(~'ns ~target-ns
581-
(:require
582-
~@(map
583-
(fn [quoted-spec-or-kw]
584-
(if (keyword? quoted-spec-or-kw)
585-
quoted-spec-or-kw
586-
(second quoted-spec-or-kw)))
587-
specs)))
607+
(:require ~@(-> specs canonicalize-specs decorate-specs)))
588608
{:merge true :line 1 :column 1})
589609
identity opts)
590610
(when is-self-require?
591611
(set! ana/*cljs-ns* restore-ns)))))
592-
'import
612+
'require-macros
593613
(fn self
594614
([repl-env env form]
595615
(self repl-env env form nil))
596616
([repl-env env [_ & specs :as form] opts]
597617
(evaluate-form repl-env env "<cljs repl>"
598618
(with-meta
599619
`(~'ns ~ana/*cljs-ns*
600-
(:import
601-
~@(map
602-
(fn [quoted-spec-or-kw]
603-
(if (keyword? quoted-spec-or-kw)
604-
quoted-spec-or-kw
605-
(second quoted-spec-or-kw)))
606-
specs)))
620+
(:require-macros ~@(-> specs canonicalize-specs decorate-specs)))
607621
{:merge true :line 1 :column 1})
608622
identity opts)))
609-
'require-macros
623+
'import
610624
(fn self
611625
([repl-env env form]
612626
(self repl-env env form nil))
613627
([repl-env env [_ & specs :as form] opts]
614628
(evaluate-form repl-env env "<cljs repl>"
615629
(with-meta
616630
`(~'ns ~ana/*cljs-ns*
617-
(:require-macros
631+
(:import
618632
~@(map
619633
(fn [quoted-spec-or-kw]
620634
(if (keyword? quoted-spec-or-kw)

0 commit comments

Comments
 (0)