Skip to content

Commit 7e90ad5

Browse files
mfikesdnolen
authored andcommitted
CLJS-1773: Self-host: Don't resolve unqualified symbols / keywords with $macros
Revise cljs.js so that unqualified symbol and :: keyword namespace resolution strip off $macros if present on the namespace. Also, go through all of the existing ClojureScript code that employs explicit qualification simply for the purpose of self-hosted compatibility, and remove it, reverting to the simpler code previously being used.
1 parent 1d8964e commit 7e90ad5

5 files changed

Lines changed: 103 additions & 89 deletions

File tree

src/main/cljs/cljs/js.cljs

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -39,11 +39,25 @@
3939
0 (- (count file) 5))]
4040
(symbol (demunge lib-name))))
4141

42+
(defn- drop-macros-suffix
43+
[ns-name]
44+
(if (string/ends-with? ns-name "$macros")
45+
(subs ns-name 0 (- (count ns-name) 7))
46+
ns-name))
47+
48+
(defn- elide-macros-suffix
49+
[sym]
50+
(symbol (drop-macros-suffix (namespace sym)) (name sym)))
51+
4252
(defn- resolve-symbol
4353
[sym]
4454
(if (string/starts-with? (str sym) ".")
4555
sym
46-
(ana/resolve-symbol sym)))
56+
(elide-macros-suffix (ana/resolve-symbol sym))))
57+
58+
(defn- read [eof rdr]
59+
(binding [*ns* (symbol (drop-macros-suffix (str *ns*)))]
60+
(r/read {:eof eof :read-cond :allow :features #{:cljs}} rdr)))
4761

4862
(defn- atom? [x]
4963
(instance? Atom x))
@@ -528,7 +542,7 @@
528542
comp/*source-map-data* (:*sm-data* bound-vars)
529543
ana/*cljs-file* (:cljs-file opts)]
530544
(let [res (try
531-
{:value (r/read {:eof eof :read-cond :allow :features #{:cljs}} rdr)}
545+
{:value (read eof rdr)}
532546
(catch :default cause
533547
(wrap-error
534548
(ana/error aenv
@@ -692,7 +706,7 @@
692706
r/resolve-symbol resolve-symbol
693707
comp/*source-map-data* (:*sm-data* bound-vars)]
694708
(let [res (try
695-
{:value (r/read {:eof eof :read-cond :allow :features #{:cljs}} rdr)}
709+
{:value (read eof rdr)}
696710
(catch :default cause
697711
(wrap-error
698712
(ana/error aenv
@@ -792,7 +806,7 @@
792806
comp/*source-map-data* (:*sm-data* bound-vars)
793807
ana/*cljs-file* (:cljs-file opts)]
794808
(let [res (try
795-
{:value (r/read {:eof eof :read-cond :allow :features #{:cljs}} rdr)}
809+
{:value (read eof rdr)}
796810
(catch :default cause
797811
(wrap-error
798812
(ana/error aenv

src/main/cljs/cljs/spec.cljc

Lines changed: 38 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@
5757
(let [k (if (symbol? k) (ns-qualify &env k) k)
5858
form (res &env spec-form)]
5959
(swap! registry-ref assoc k form)
60-
`(cljs.spec/def-impl '~k '~form ~spec-form)))
60+
`(def-impl '~k '~form ~spec-form)))
6161

6262
(defmacro spec
6363
"Takes a single predicate form, e.g. can be the name of a predicate,
@@ -76,7 +76,7 @@
7676
Returns a spec."
7777
[form & {:keys [gen]}]
7878
(when form
79-
`(cljs.spec/spec-impl '~(res &env form) ~form ~gen nil)))
79+
`(spec-impl '~(res &env form) ~form ~gen nil)))
8080

8181
(defmacro multi-spec
8282
"Takes the name of a spec/predicate-returning multimethod and a
@@ -105,7 +105,7 @@
105105
though those values are not evident in the spec.
106106
"
107107
[mm retag]
108-
`(cljs.spec/multi-spec-impl '~(res &env mm) (var ~mm) ~retag))
108+
`(multi-spec-impl '~(res &env mm) (var ~mm) ~retag))
109109

110110
(defmacro keys
111111
"Creates and returns a map validating spec. :req and :opt are both
@@ -160,12 +160,12 @@
160160
pred-exprs (into pred-exprs (parse-req req-un unk))
161161
pred-forms (walk/postwalk #(res &env %) pred-exprs)]
162162
;; `(map-spec-impl ~req-keys '~req ~opt '~pred-forms ~pred-exprs ~gen)
163-
`(cljs.spec/map-spec-impl {:req '~req :opt '~opt :req-un '~req-un :opt-un '~opt-un
164-
:req-keys '~req-keys :req-specs '~req-specs
165-
:opt-keys '~opt-keys :opt-specs '~opt-specs
166-
:pred-forms '~pred-forms
167-
:pred-exprs ~pred-exprs
168-
:gfn ~gen})))
163+
`(map-spec-impl {:req '~req :opt '~opt :req-un '~req-un :opt-un '~opt-un
164+
:req-keys '~req-keys :req-specs '~req-specs
165+
:opt-keys '~opt-keys :opt-specs '~opt-specs
166+
:pred-forms '~pred-forms
167+
:pred-exprs ~pred-exprs
168+
:gfn ~gen})))
169169

170170
(defmacro or
171171
"Takes key+pred pairs, e.g.
@@ -182,7 +182,7 @@
182182
pred-forms (mapv second pairs)
183183
pf (mapv #(res &env %) pred-forms)]
184184
(clojure.core/assert (clojure.core/and (even? (count key-pred-forms)) (every? keyword? keys)) "spec/or expects k1 p1 k2 p2..., where ks are keywords")
185-
`(cljs.spec/or-spec-impl ~keys '~pf ~pred-forms nil)))
185+
`(or-spec-impl ~keys '~pf ~pred-forms nil)))
186186

187187
(defmacro and
188188
"Takes predicate/spec-forms, e.g.
@@ -192,7 +192,7 @@
192192
Returns a spec that returns the conformed value. Successive
193193
conformed values propagate through rest of predicates."
194194
[& pred-forms]
195-
`(cljs.spec/and-spec-impl '~(mapv #(res &env %) pred-forms) ~(vec pred-forms) nil))
195+
`(and-spec-impl '~(mapv #(res &env %) pred-forms) ~(vec pred-forms) nil))
196196

197197
(defmacro every
198198
"takes a pred and validates collection elements against that pred.
@@ -224,8 +224,8 @@
224224
See also - coll-of, every-kv
225225
"
226226
[pred & {:keys [into kind count max-count min-count distinct gen-max gen-into gen] :as opts}]
227-
(let [nopts (-> opts (dissoc :gen) (assoc :cljs.spec/kind-form `'~(res &env (:kind opts))))]
228-
`(cljs.spec/every-impl '~pred ~pred ~nopts ~gen)))
227+
(let [nopts (-> opts (dissoc :gen) (assoc ::kind-form `'~(res &env (:kind opts))))]
228+
`(every-impl '~pred ~pred ~nopts ~gen)))
229229

230230
(defmacro every-kv
231231
"like 'every' but takes separate key and val preds and works on associative collections.
@@ -235,7 +235,7 @@
235235
See also - map-of"
236236

237237
[kpred vpred & opts]
238-
`(every (tuple ~kpred ~vpred) :cljs.spec/kfn (fn [i# v#] (nth v# 0)) :into {} ~@opts))
238+
`(every (tuple ~kpred ~vpred) ::kfn (fn [i# v#] (nth v# 0)) :into {} ~@opts))
239239

240240
(defmacro coll-of
241241
"Returns a spec for a collection of items satisfying pred. Unlike
@@ -249,7 +249,7 @@
249249
250250
See also - every, map-of"
251251
[pred & opts]
252-
`(every ~pred :cljs.spec/conform-all true ~@opts))
252+
`(every ~pred ::conform-all true ~@opts))
253253

254254
(defmacro map-of
255255
"Returns a spec for a map whose keys satisfy kpred and vals satisfy
@@ -262,25 +262,25 @@
262262
263263
See also - every-kv"
264264
[kpred vpred & opts]
265-
`(every-kv ~kpred ~vpred :cljs.spec/conform-all true :kind map? ~@opts))
265+
`(every-kv ~kpred ~vpred ::conform-all true :kind map? ~@opts))
266266

267267
(defmacro *
268268
"Returns a regex op that matches zero or more values matching
269269
pred. Produces a vector of matches iff there is at least one match"
270270
[pred-form]
271-
`(cljs.spec/rep-impl '~(res &env pred-form) ~pred-form))
271+
`(rep-impl '~(res &env pred-form) ~pred-form))
272272

273273
(defmacro +
274274
"Returns a regex op that matches one or more values matching
275275
pred. Produces a vector of matches"
276276
[pred-form]
277-
`(cljs.spec/rep+impl '~(res &env pred-form) ~pred-form))
277+
`(rep+impl '~(res &env pred-form) ~pred-form))
278278

279279
(defmacro ?
280280
"Returns a regex op that matches zero or one value matching
281281
pred. Produces a single value (not a collection) if matched."
282282
[pred-form]
283-
`(cljs.spec/maybe-impl ~pred-form '~pred-form))
283+
`(maybe-impl ~pred-form '~pred-form))
284284

285285
(defmacro alt
286286
"Takes key+pred pairs, e.g.
@@ -297,7 +297,7 @@
297297
pred-forms (mapv second pairs)
298298
pf (mapv #(res &env %) pred-forms)]
299299
(clojure.core/assert (clojure.core/and (even? (count key-pred-forms)) (every? keyword? keys)) "alt expects k1 p1 k2 p2..., where ks are keywords")
300-
`(cljs.spec/alt-impl ~keys ~pred-forms '~pf)))
300+
`(alt-impl ~keys ~pred-forms '~pf)))
301301

302302
(defmacro cat
303303
"Takes key+pred pairs, e.g.
@@ -313,23 +313,23 @@
313313
pf (mapv #(res &env %) pred-forms)]
314314
;;(prn key-pred-forms)
315315
(clojure.core/assert (clojure.core/and (even? (count key-pred-forms)) (every? keyword? keys)) "cat expects k1 p1 k2 p2..., where ks are keywords")
316-
`(cljs.spec/cat-impl ~keys ~pred-forms '~pf)))
316+
`(cat-impl ~keys ~pred-forms '~pf)))
317317

318318
(defmacro &
319319
"takes a regex op re, and predicates. Returns a regex-op that consumes
320320
input as per re but subjects the resulting value to the
321321
conjunction of the predicates, and any conforming they might perform."
322322
[re & preds]
323323
(let [pv (vec preds)]
324-
`(cljs.spec/amp-impl ~re ~pv '~(mapv #(res &env %) pv))))
324+
`(amp-impl ~re ~pv '~(mapv #(res &env %) pv))))
325325

326326
(defmacro conformer
327327
"takes a predicate function with the semantics of conform i.e. it should return either a
328328
(possibly converted) value or :cljs.spec/invalid, and returns a
329329
spec that uses it as a predicate/conformer. Optionally takes a
330330
second fn that does unform of result of first"
331-
([f] `(cljs.spec/spec-impl '~f ~f nil true))
332-
([f unf] `(cljs.spec/spec-impl '~f ~f nil true ~unf)))
331+
([f] `(spec-impl '~f ~f nil true))
332+
([f unf] `(spec-impl '~f ~f nil true ~unf)))
333333

334334
(defmacro fspec
335335
"takes :args :ret and (optional) :fn kwargs whose values are preds
@@ -347,7 +347,7 @@
347347
that returns a test.check generator."
348348
[& {:keys [args ret fn gen]}]
349349
(let [env &env]
350-
`(cljs.spec/fspec-impl (spec ~args) '~(res env args)
350+
`(fspec-impl (spec ~args) '~(res env args)
351351
(spec ~ret) '~(res env ret)
352352
(spec ~fn) '~(res env fn) ~gen)))
353353

@@ -357,7 +357,7 @@
357357
will be referred to in paths using its ordinal."
358358
[& preds]
359359
(clojure.core/assert (not (empty? preds)))
360-
`(cljs.spec/tuple-impl '~(mapv #(res &env %) preds) ~(vec preds)))
360+
`(tuple-impl '~(mapv #(res &env %) preds) ~(vec preds)))
361361

362362
(def ^:private _speced_vars (atom #{}))
363363

@@ -398,7 +398,7 @@
398398
:ret symbol?)"
399399
[fn-sym & specs]
400400
(swap! _speced_vars conj (ns-qualify &env fn-sym))
401-
`(cljs.spec/def ~fn-sym (cljs.spec/fspec ~@specs)))
401+
`(cljs.spec/def ~fn-sym (fspec ~@specs)))
402402

403403
(defmacro keys*
404404
"takes the same arguments as spec/keys and returns a regex op that matches sequences of key/values,
@@ -416,13 +416,13 @@
416416
{:i1 42, :m {:a 1, :c 2, :d 4}, :i2 99}"
417417
[& kspecs]
418418
`(let [mspec# (keys ~@kspecs)]
419-
(cljs.spec/with-gen (cljs.spec/& (* (cat :cljs.spec/k keyword? :cljs.spec/v cljs.core/any?)) :cljs.spec/kvs->map mspec#)
420-
(fn [] (gen/fmap (fn [m#] (apply concat m#)) (cljs.spec/gen mspec#))))))
419+
(with-gen (& (* (cat ::k keyword? ::v cljs.core/any?)) ::kvs->map mspec#)
420+
(fn [] (gen/fmap (fn [m#] (apply concat m#)) (gen mspec#))))))
421421

422422
(defmacro nilable
423423
"returns a spec that accepts nil and values satisfiying pred"
424424
[pred]
425-
`(and (or :cljs.spec/nil nil? :cljs.spec/pred ~pred) (conformer second)))
425+
`(and (or ::nil nil? ::pred ~pred) (conformer second)))
426426

427427
(defmacro inst-in
428428
"Returns a spec that validates insts in the range from start
@@ -431,7 +431,7 @@
431431
`(let [st# (cljs.core/inst-ms ~start)
432432
et# (cljs.core/inst-ms ~end)
433433
mkdate# (fn [d#] (js/Date. d#))]
434-
(spec (and cljs.core/inst? #(cljs.spec/inst-in-range? ~start ~end %))
434+
(spec (and cljs.core/inst? #(inst-in-range? ~start ~end %))
435435
:gen (fn []
436436
(gen/fmap mkdate#
437437
(gen/large-integer* {:min st# :max et#}))))))
@@ -440,7 +440,7 @@
440440
"Returns a spec that validates longs in the range from start
441441
(inclusive) to end (exclusive)."
442442
[start end]
443-
`(spec (and c/int? #(cljs.spec/int-in-range? ~start ~end %))
443+
`(spec (and c/int? #(int-in-range? ~start ~end %))
444444
:gen #(gen/large-integer* {:min ~start :max (dec ~end)})))
445445

446446
(defmacro merge
@@ -450,7 +450,7 @@
450450
predicates. Unlike 'and', merge can generate maps satisfying the
451451
union of the predicates."
452452
[& pred-forms]
453-
`(cljs.spec/merge-spec-impl '~(mapv #(res &env %) pred-forms) ~(vec pred-forms) nil))
453+
`(merge-spec-impl '~(mapv #(res &env %) pred-forms) ~(vec pred-forms) nil))
454454

455455
(defmacro exercise-fn
456456
"exercises the fn named by sym (a symbol) by applying it to
@@ -467,10 +467,10 @@
467467
(= (first sym) 'quote))
468468
second)]
469469
`(let [fspec# ~(if-not fspec
470-
`(cljs.spec/get-spec '~(:name (resolve &env sym)))
470+
`(get-spec '~(:name (resolve &env sym)))
471471
fspec)
472472
f# ~sym]
473-
(for [args# (gen/sample (cljs.spec/gen (:args fspec#)) ~n)]
473+
(for [args# (gen/sample (gen (:args fspec#)) ~n)]
474474
[args# (apply f# args#)])))))
475475

476476
(defmacro ^:private init-compile-asserts []
@@ -489,8 +489,8 @@ If (check-asserts?) is false at runtime, always returns x. Defaults to
489489
value of 'cljs.spec/*runtime-asserts*', or false if not set. You can
490490
toggle check-asserts? with (check-asserts bool)."
491491
[spec x]
492-
`(if cljs.spec/*compile-asserts*
493-
(if cljs.spec/*runtime-asserts*
494-
(cljs.spec/assert* ~spec ~x)
492+
`(if *compile-asserts*
493+
(if *runtime-asserts*
494+
(assert* ~spec ~x)
495495
~x)
496496
~x))

src/main/cljs/cljs/spec/impl/gen.cljc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@
3434
generator that delegates to that, but delays
3535
creation until used."
3636
[& body]
37-
`(cljs.spec.impl.gen/delay-impl (c/delay ~@body)))
37+
`(delay-impl (c/delay ~@body)))
3838

3939
(defmacro ^:skip-wiki lazy-combinator
4040
"Implementation macro, do not call directly."

src/main/cljs/cljs/spec/test.cljc

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -43,15 +43,15 @@ returns the set of all symbols naming vars in those nses."
4343
(defmacro with-instrument-disabled
4444
"Disables instrument's checking of calls, within a scope."
4545
[& body]
46-
`(binding [cljs.spec.test/*instrument-enabled* nil]
46+
`(binding [*instrument-enabled* nil]
4747
~@body))
4848

4949
(defmacro instrument-1
5050
[[quote s] opts]
5151
(let [v (ana-api/resolve &env s)]
5252
(when v
5353
(swap! instrumented-vars conj (:name v))
54-
`(let [checked# (cljs.spec.test/instrument-1* ~s (var ~s) ~opts)]
54+
`(let [checked# (instrument-1* ~s (var ~s) ~opts)]
5555
(when checked# (set! ~s checked#))
5656
'~(:name v)))))
5757

@@ -60,7 +60,7 @@ returns the set of all symbols naming vars in those nses."
6060
(let [v (ana-api/resolve &env s)]
6161
(when v
6262
(swap! instrumented-vars disj (:name v))
63-
`(let [raw# (cljs.spec.test/unstrument-1* ~s (var ~s))]
63+
`(let [raw# (unstrument-1* ~s (var ~s))]
6464
(when raw# (set! ~s raw#))
6565
'~(:name v)))))
6666

0 commit comments

Comments
 (0)