Skip to content

Commit d388905

Browse files
anmonteirodnolen
authored andcommitted
CLJS-1508: Extend ns form to support :rename option
1 parent e6f37a0 commit d388905

File tree

6 files changed

+298
-40
lines changed

6 files changed

+298
-40
lines changed

src/main/cljs/cljs/js.cljs

Lines changed: 28 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -306,11 +306,22 @@
306306
(if (and add-if-present?
307307
(some #{to} (vals replaced)))
308308
(assoc replaced from to)
309-
replaced)))))]
309+
replaced)))))
310+
patch-renames (fn [k]
311+
(swap! compiler update-in [::ana/namespaces in k]
312+
(fn [m]
313+
(when m
314+
(reduce (fn [acc [renamed qualified-sym :as entry]]
315+
(if (= (str from) (namespace qualified-sym))
316+
(assoc acc renamed (symbol (str to) (name qualified-sym)))
317+
(merge acc entry)))
318+
{} m)))))]
310319
(patch :requires true)
311320
(patch :require-macros true)
312321
(patch :uses false)
313-
(patch :use-macros false)))
322+
(patch :use-macros false)
323+
(patch-renames :renames)
324+
(patch-renames :rename-macros)))
314325

315326
(defn- load-deps
316327
([bound-vars ana-env lib deps cb]
@@ -409,9 +420,20 @@
409420

410421
(defn- rewrite-ns-ast
411422
[ast smap]
412-
(-> ast
413-
(update :uses #(walk/postwalk-replace smap %))
414-
(update :requires #(merge smap (walk/postwalk-replace smap %)))))
423+
(let [rewrite-renames (fn [m]
424+
(when m
425+
(reduce (fn [acc [renamed qualified-sym :as entry]]
426+
(let [from (symbol (namespace qualified-sym))
427+
to (get smap from)]
428+
(if (some? to)
429+
(assoc acc renamed (symbol (str to) (name qualified-sym)))
430+
(merge acc entry))))
431+
{} m)))]
432+
(-> ast
433+
(update :uses #(walk/postwalk-replace smap %))
434+
(update :requires #(merge smap (walk/postwalk-replace smap %)))
435+
(update :renames rewrite-renames)
436+
(update :rename-macros rewrite-renames))))
415437

416438
(defn- ns-side-effects
417439
([bound-vars ana-env ast opts cb]
@@ -1038,4 +1060,4 @@
10381060
(println error)
10391061
(println (.. error -cause -stack)))
10401062
(println res))))
1041-
)
1063+
)

src/main/clojure/cljs/analyzer.cljc

Lines changed: 141 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -781,6 +781,15 @@
781781
{:name (symbol (str full-ns) (str sym))
782782
:ns full-ns}))
783783

784+
(not (nil? (gets @env/*compiler* ::namespaces (-> env :ns :name) :renames sym)))
785+
(let [qualified-symbol (gets @env/*compiler* ::namespaces (-> env :ns :name) :renames sym)
786+
full-ns (symbol (namespace qualified-symbol))
787+
sym (symbol (name qualified-symbol))]
788+
(merge
789+
(gets @env/*compiler* ::namespaces full-ns :defs sym)
790+
{:name qualified-symbol
791+
:ns full-ns}))
792+
784793
(not (nil? (gets @env/*compiler* ::namespaces (-> env :ns :name) :imports sym)))
785794
(recur env (gets @env/*compiler* ::namespaces (-> env :ns :name) :imports sym) confirm)
786795

@@ -830,6 +839,12 @@
830839
(let [full-ns (get-in namespaces [ns :use-macros sym])]
831840
(get-in namespaces [full-ns :macros sym]))
832841

842+
(get-in namespaces [ns :rename-macros sym])
843+
(let [qualified-symbol (get-in namespaces [ns :rename-macros sym])
844+
full-ns (symbol (namespace qualified-symbol))
845+
sym (symbol (name qualified-symbol))]
846+
(get-in namespaces [full-ns :macros sym]))
847+
833848
:else
834849
(let [ns (cond
835850
(get-in namespaces [ns :macros sym]) ns
@@ -1727,14 +1742,29 @@
17271742
(not (= (get js-lib :group) :goog))
17281743
(not (get js-lib :closure-lib)))))
17291744

1745+
(defn missing-rename? [sym cenv]
1746+
(let [lib (symbol (namespace sym))
1747+
sym (symbol (name sym))]
1748+
(missing-use? lib sym cenv)))
1749+
17301750
(defn missing-use-macro? [lib sym]
17311751
(let [the-ns #?(:clj (find-ns lib) :cljs (find-macros-ns lib))]
17321752
(or (nil? the-ns) (nil? (.findInternedVar ^clojure.lang.Namespace the-ns sym)))))
17331753

1754+
(defn missing-rename-macro? [sym]
1755+
(let [lib (symbol (namespace sym))
1756+
sym (symbol (name sym))
1757+
the-ns #?(:clj (find-ns lib) :cljs (find-macros-ns lib))]
1758+
(or (nil? the-ns) (nil? (.findInternedVar ^clojure.lang.Namespace the-ns sym)))))
1759+
17341760
(defn missing-uses [uses env]
17351761
(let [cenv @env/*compiler*]
17361762
(into {} (filter (fn [[sym lib]] (missing-use? lib sym cenv)) uses))))
17371763

1764+
(defn missing-renames [renames]
1765+
(let [cenv @env/*compiler*]
1766+
(into {} (filter (fn [[_ qualified-sym]] (missing-rename? qualified-sym cenv)) renames))))
1767+
17381768
(defn missing-use-macros [use-macros env]
17391769
(let [cenv @env/*compiler*]
17401770
(into {} (filter (fn [[sym lib]] (missing-use-macro? lib sym)) use-macros))))
@@ -1743,6 +1773,9 @@
17431773
(let [cenv @env/*compiler*]
17441774
(into {} (filter (fn [[sym lib]] (not (missing-use-macro? lib sym))) use-macros))))
17451775

1776+
(defn inferred-rename-macros [rename-macros env]
1777+
(into {} (filter (fn [[_ qualified-sym]] (not (missing-rename-macro? qualified-sym))) rename-macros)))
1778+
17461779
(defn check-uses [uses env]
17471780
(let [cenv @env/*compiler*]
17481781
(doseq [[sym lib] uses]
@@ -1766,14 +1799,21 @@
17661799

17671800
(defn check-use-macros-inferring-missing
17681801
[ast name use-macros missing-uses env]
1769-
(let [remove-missing-uses #(apply dissoc % (keys missing-uses))
1802+
(let [remove-missing-uses #(apply dissoc % (keys missing-uses))
1803+
missing-renames (missing-renames (:renames ast))
1804+
missing-rename-macros (inferred-rename-macros missing-renames env)
1805+
remove-missing-renames #(apply dissoc % (keys missing-renames))
17701806
ast' (-> ast
17711807
(update-in [:use-macros] merge
17721808
(check-use-macros use-macros missing-uses env))
1773-
(update-in [:uses] remove-missing-uses))]
1809+
(update-in [:uses] remove-missing-uses)
1810+
(update-in [:rename-macros] merge missing-rename-macros)
1811+
(update-in [:renames] remove-missing-renames))]
17741812
(swap! env/*compiler* #(-> %
17751813
(update-in [::namespaces name :use-macros] merge (:use-macros ast'))
1776-
(update-in [::namespaces name :uses] remove-missing-uses)))
1814+
(update-in [::namespaces name :uses] remove-missing-uses)
1815+
(update-in [::namespaces name :rename-macros] merge (:rename-macros ast'))
1816+
(update-in [::namespaces name :renames] remove-missing-renames)))
17771817
ast'))
17781818

17791819
(defn parse-ns-error-msg [spec msg]
@@ -1795,12 +1835,12 @@
17951835
(throw
17961836
(error env
17971837
(parse-ns-error-msg spec
1798-
"Only :as alias and :refer (names) options supported in :require"))))
1799-
(when-not (every? #{:as :refer} (map first (partition 2 (next spec))))
1838+
"Only :as alias, :refer (names) and :rename {from to} options supported in :require"))))
1839+
(when-not (every? #{:as :refer :rename} (map first (partition 2 (next spec))))
18001840
(throw
18011841
(error env
18021842
(parse-ns-error-msg spec
1803-
"Only :as and :refer options supported in :require / :require-macros"))))
1843+
"Only :as, :refer and :rename options supported in :require / :require-macros"))))
18041844
(when-not (let [fs (frequencies (next spec))]
18051845
(and (<= (fs :as 0) 1)
18061846
(<= (fs :refer 0) 1)))
@@ -1811,24 +1851,76 @@
18111851

18121852
(defn parse-ns-excludes [env args]
18131853
(reduce
1814-
(fn [s [k exclude xs]]
1854+
(fn [s [k & filters]]
18151855
(if (= k :refer-clojure)
18161856
(do
1817-
(when-not (= exclude :exclude)
1818-
(throw (error env "Only [:refer-clojure :exclude (names)] form supported")))
18191857
(when (seq s)
18201858
(throw (error env "Only one :refer-clojure form is allowed per namespace definition")))
1821-
(into s xs))
1859+
(let [valid-kws #{:exclude :rename}
1860+
xs
1861+
(loop [fs (seq filters)
1862+
ret {:excludes #{}
1863+
:renames {}}
1864+
err (not (even? (count filters)))]
1865+
(cond
1866+
(true? err)
1867+
(throw
1868+
(error env "Only [:refer-clojure :exclude (names)] and optionally `:rename {from to}` specs supported"))
1869+
1870+
(not (nil? fs))
1871+
(let [kw (first fs)]
1872+
(if (valid-kws kw)
1873+
(let [refs (second fs)]
1874+
(cond
1875+
(not (or (and (= kw :exclude) (sequential? refs) (every? symbol? refs))
1876+
(and (= kw :rename) (map? refs) (every? #(every? symbol? %) refs))))
1877+
(recur fs ret true)
1878+
1879+
(= kw :exclude)
1880+
(recur (nnext fs) (update-in ret [:excludes] into refs) false)
1881+
1882+
(= kw :rename)
1883+
(recur (nnext fs) (update-in ret [:renames] merge refs) false)))
1884+
(recur fs ret true )))
1885+
1886+
:else ret))]
1887+
(merge-with into s xs)))
18221888
s))
1823-
#{} args))
1889+
{} args))
18241890

1825-
(defn use->require [env [lib kw referred :as spec]]
1826-
(when-not (and (symbol? lib) (= :only kw) (sequential? referred) (every? symbol? referred))
1891+
(defn use->require [env [lib & filters :as spec]]
1892+
(when-not (and (symbol? lib) (odd? (count spec)))
18271893
(throw
18281894
(error env
18291895
(parse-ns-error-msg spec
1830-
"Only [lib.ns :only (names)] specs supported in :use / :use-macros"))))
1831-
[lib :refer referred])
1896+
"Only [lib.ns :only (names)] and optionally `:rename {from to}` specs supported in :use / :use-macros"))))
1897+
(loop [fs (seq filters) ret [lib] err false]
1898+
(cond
1899+
(true? err)
1900+
(throw
1901+
(error env
1902+
(parse-ns-error-msg spec
1903+
"Only [lib.ns :only (names)] and optionally `:rename {from to}` specs supported in :use / :use-macros")))
1904+
1905+
(not (nil? fs))
1906+
(let [kw (first fs)
1907+
only? (= kw :only)]
1908+
(if (or only? (= kw :rename))
1909+
(if (some #{(if only? :refer kw)} ret)
1910+
(throw
1911+
(error env
1912+
(parse-ns-error-msg spec
1913+
"Each of :only and :rename options may only be specified once in :use / :use-macros")))
1914+
(let [refs (second fs)]
1915+
(if-not (or (and only? (sequential? refs) (every? symbol? refs))
1916+
(and (= kw :rename) (map? refs) (every? #(every? symbol? %) refs)))
1917+
(recur fs ret true)
1918+
(recur (nnext fs) (into ret [(if only? :refer kw) refs]) false))))
1919+
(recur fs ret true )))
1920+
1921+
:else (if (some #{:refer} ret)
1922+
ret
1923+
(recur fs ret true)))))
18321924

18331925
(defn parse-require-spec [env macros? deps aliases spec]
18341926
(if (symbol? spec)
@@ -1839,8 +1931,9 @@
18391931
lib (if-let [js-module-name (get-in @env/*compiler* [:js-module-index (name lib)])]
18401932
(symbol js-module-name)
18411933
lib)
1842-
{alias :as referred :refer :or {alias lib}} (apply hash-map opts)
1843-
[rk uk] (if macros? [:require-macros :use-macros] [:require :use])]
1934+
{alias :as referred :refer renamed :rename :or {alias lib}} (apply hash-map opts)
1935+
referred-without-renamed (seq (remove (set (keys renamed)) referred))
1936+
[rk uk renk] (if macros? [:require-macros :use-macros :rename-macros] [:require :use :rename])]
18441937
(when-not (or (symbol? alias) (nil? alias))
18451938
(throw
18461939
(error env
@@ -1866,7 +1959,14 @@
18661959
(merge
18671960
(when alias
18681961
{rk (merge {alias lib} {lib lib})})
1869-
(when referred {uk (apply hash-map (interleave referred (repeat lib)))}))))))
1962+
(when referred-without-renamed {uk (apply hash-map (interleave referred-without-renamed (repeat lib)))})
1963+
(when renamed
1964+
{renk (reduce (fn [m [original renamed]]
1965+
(when-not (some #{original} referred)
1966+
(throw (error env
1967+
(str "Renamed symbol " original " not referred"))))
1968+
(assoc m renamed (symbol (str lib) (str original))))
1969+
{} renamed)}))))))
18701970

18711971
(defn parse-import-spec [env deps spec]
18721972
(when-not (or (and (sequential? spec)
@@ -1977,6 +2077,7 @@
19772077
(if-not (reload-spec? x)
19782078
(->> x (remove-from-spec #{:include-macros})
19792079
(remove-from-spec #{:refer})
2080+
(remove-from-spec #{:rename})
19802081
(replace-refer-macros))
19812082
x)))))
19822083
remove-sugar (partial remove-from-spec sugar-keys)]
@@ -2034,7 +2135,10 @@
20342135
(if metadata (next args) args))
20352136
:cljs (if metadata (next args) args)))
20362137
name (vary-meta name merge metadata)
2037-
excludes (parse-ns-excludes env args)
2138+
{excludes :excludes core-renames :renames} (parse-ns-excludes env args)
2139+
core-renames (reduce (fn [m [original renamed]]
2140+
(assoc m renamed (symbol "cljs.core" (str original))))
2141+
{} core-renames)
20382142
deps (atom #{})
20392143
aliases (atom {:fns {} :macros {}})
20402144
spec-parsers {:require (partial parse-require-spec env false deps aliases)
@@ -2047,7 +2151,9 @@
20472151
valid-forms (atom #{:use :use-macros :require :require-macros :import})
20482152
reload (atom {:use nil :require nil :use-macros nil :require-macros nil})
20492153
reloads (atom {})
2050-
{uses :use requires :require use-macros :use-macros require-macros :require-macros imports :import :as params}
2154+
{uses :use requires :require renames :rename
2155+
use-macros :use-macros require-macros :require-macros
2156+
rename-macros :rename-macros imports :import :as params}
20512157
(reduce
20522158
(fn [m [k & libs]]
20532159
(when-not (#{:use :use-macros :require :require-macros :import} k)
@@ -2076,16 +2182,19 @@
20762182
:excludes excludes
20772183
:use-macros use-macros
20782184
:require-macros require-macros
2185+
:rename-macros rename-macros
20792186
:uses uses
20802187
:requires requires
2188+
:renames (merge renames core-renames)
20812189
:imports imports}
20822190
ns-info
20832191
(if (:merge form-meta)
20842192
;; for merging information in via require usage in REPLs
20852193
(let [ns-info' (get-in @env/*compiler* [::namespaces name])]
20862194
(if (pos? (count ns-info'))
20872195
(let [merge-keys
2088-
[:use-macros :require-macros :uses :requires :imports]]
2196+
[:use-macros :require-macros :rename-macros
2197+
:uses :requires :renames :imports]]
20892198
(merge
20902199
ns-info'
20912200
(merge-with merge
@@ -2458,10 +2567,20 @@
24582567
(when-not (or (not (nil? (gets env :locals sym))) ; locals hide macros
24592568
(and (excluded? env sym) (not (used? env sym))))
24602569
(let [nstr (namespace sym)]
2461-
(if-not (nil? nstr)
2570+
(cond
2571+
(not (nil? nstr))
24622572
(let [ns (get-expander-ns env nstr)]
24632573
(when-not (nil? ns)
24642574
(.findInternedVar ^clojure.lang.Namespace ns (symbol (name sym)))))
2575+
2576+
(not (nil? (gets env :ns :rename-macros sym)))
2577+
(let [qualified-symbol (gets env :ns :rename-macros sym)
2578+
nsym (symbol (namespace qualified-symbol))
2579+
sym (symbol (name qualified-symbol))]
2580+
(.findInternedVar ^clojure.lang.Namespace
2581+
#?(:clj (find-ns nsym) :cljs (find-macros-ns nsym)) sym))
2582+
2583+
:else
24652584
(let [nsym (gets env :ns :use-macros sym)]
24662585
(if-not (nil? nsym)
24672586
(.findInternedVar ^clojure.lang.Namespace
Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
(ns cljs.clojure-alias-test
22
"Tests requiring via `clojure.*` instead of `cljs.*`"
3-
(:require [clojure.test :refer [deftest is]]
4-
[clojure.spec :as s :refer [spec?]]))
3+
(:require [clojure.test :refer [deftest is] :rename {is is?}]
4+
[clojure.spec :as s :refer [spec? spec] :rename {spec foo}]))
55

66
(deftest normal-test
7-
(is (= 1 1)))
7+
(is? (= 1 1)))
88

99
(deftest aliases-test
10-
(is (= spec? clojure.spec/spec? cljs.spec/spec?)))
10+
(is? (= spec? clojure.spec/spec? cljs.spec/spec?))
11+
(is? (foo number?)))

src/test/cljs/cljs/ns_test.cljs

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
(ns cljs.ns-test
2-
(:refer-clojure :exclude [+ for])
3-
(:require-macros [clojure.core :as lang]
2+
(:refer-clojure :exclude [+ for] :rename {mapv core-mapv})
3+
(:require-macros [clojure.core :as lang :refer [when when-let] :rename {when always
4+
when-let always-let}]
45
[cljs.test :refer [deftest is]])
56
(:require [cljs.test]
67
[cljs.ns-test.foo :refer [baz]]
7-
[clojure.set :as s])
8+
[clojure.set :as s :refer [intersection] :rename {intersection itsc}])
89
(:use [cljs.ns-test.bar :only [quux]]))
910

1011
(def + -)
@@ -18,3 +19,11 @@
1819

1920
(is (= (range 5) (lang/for [x (range 5)] x)))
2021
(is (= #{1 2 3} (s/union #{1} #{2 3}))))
22+
23+
(deftest test-cljs-1508
24+
(is (= (itsc #{1 2 3} #{2}) #{2}))
25+
(is (= #'itsc #'clojure.set/intersection))
26+
(is (= itsc clojure.set/intersection))
27+
(is (= (always true 42) 42))
28+
(is (= (core-mapv inc [1 2]) [2 3]))
29+
(is (= (always-let [foo 42] foo) 42)))

0 commit comments

Comments
 (0)