Skip to content

Commit 8f7b1d0

Browse files
mfikesdnolen
authored andcommitted
CLJS-1551: Self-host: assert-args dormant in macros
Since self-host must call macros defined in a different compilation stage, the assert-args macro used in if-let and other macros must be defined in a different namespace entirely (they can't be in cljs.core because this namespace is already being compiled as a macros namespace at this point). Introduce a cljs.support namespace for this purpose, and to keep things simple, also arrange to have non-bootstrap use this namespace for the purpose of assert-args.
1 parent 89ec69f commit 8f7b1d0

File tree

3 files changed

+54
-25
lines changed

3 files changed

+54
-25
lines changed

src/main/clojure/cljs/core.cljc

Lines changed: 13 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@
77
; You must not remove this notice, or any other, from this software.
88

99
(ns cljs.core
10-
(:refer-clojure :exclude [-> ->> .. amap and areduce alength aclone assert binding bound-fn case comment cond condp
11-
declare definline definterface defmethod defmulti defn defn- defonce
10+
(:refer-clojure :exclude [-> ->> .. amap and areduce alength aclone assert assert-args binding bound-fn case comment
11+
cond condp declare definline definterface defmethod defmulti defn defn- defonce
1212
defprotocol defrecord defstruct deftype delay destructure doseq dosync dotimes doto
1313
extend-protocol extend-type fn for future gen-class gen-interface
1414
if-let if-not import io! lazy-cat lazy-seq let letfn locking loop
@@ -35,19 +35,21 @@
3535
cond-> cond->> as-> some-> some->>
3636

3737
if-some when-some test ns-interns ns-unmap var vswap! macroexpand-1 macroexpand
38-
#?@(:cljs [alias assert-args coercive-not coercive-not= coercive-= coercive-boolean
38+
#?@(:cljs [alias coercive-not coercive-not= coercive-= coercive-boolean
3939
truth_ js-arguments js-delete js-in js-debugger exists? divide js-mod
4040
unsafe-bit-and bit-shift-right-zero-fill mask bitpos caching-hash
4141
defcurried rfn specify! js-this this-as implements? array js-obj
4242
simple-benchmark gen-apply-to js-str es6-iterable load-file* undefined?
4343
specify copy-arguments goog-define js-comment js-inline-comment
4444
unsafe-cast])])
45-
#?(:cljs (:require-macros [cljs.core :as core]))
45+
#?(:cljs (:require-macros [cljs.core :as core]
46+
[cljs.support :refer [assert-args]]))
4647
(:require clojure.walk
4748
clojure.set
4849
[clojure.string :as string]
4950
[cljs.compiler :as comp]
5051
[cljs.env :as env]
52+
#?(:clj [cljs.support :refer [assert-args]])
5153
#?(:cljs [cljs.core :as core])
5254
#?(:cljs [cljs.analyzer :as ana])))
5355

@@ -338,9 +340,9 @@
338340
([bindings then]
339341
`(if-let ~bindings ~then nil))
340342
([bindings then else & oldform]
341-
(core/assert-args
343+
(assert-args if-let
342344
(vector? bindings) "a vector for its binding"
343-
(nil? oldform) "1 or 2 forms after binding vector"
345+
(empty? oldform) "1 or 2 forms after binding vector"
344346
(= 2 (count bindings)) "exactly 2 forms in binding vector")
345347
(core/let [form (bindings 0) tst (bindings 1)]
346348
`(let [temp# ~tst]
@@ -396,7 +398,7 @@
396398
397399
Roughly the same as (when (seq xs) (let [x (first xs)] body)) but xs is evaluated only once"
398400
[bindings & body]
399-
(core/assert-args
401+
(assert-args when-first
400402
(vector? bindings) "a vector for its binding"
401403
(= 2 (count bindings)) "exactly 2 forms in binding vector")
402404
(core/let [[x xs] bindings]
@@ -410,7 +412,7 @@
410412
411413
When test is true, evaluates body with binding-form bound to the value of test"
412414
[bindings & body]
413-
(core/assert-args
415+
(assert-args when-let
414416
(vector? bindings) "a vector for its binding"
415417
(= 2 (count bindings)) "exactly 2 forms in binding vector")
416418
(core/let [form (bindings 0) tst (bindings 1)]
@@ -504,9 +506,9 @@
504506
([bindings then]
505507
`(if-some ~bindings ~then nil))
506508
([bindings then else & oldform]
507-
(core/assert-args
509+
(assert-args if-some
508510
(vector? bindings) "a vector for its binding"
509-
(nil? oldform) "1 or 2 forms after binding vector"
511+
(empty? oldform) "1 or 2 forms after binding vector"
510512
(= 2 (count bindings)) "exactly 2 forms in binding vector")
511513
(core/let [form (bindings 0) tst (bindings 1)]
512514
`(let [temp# ~tst]
@@ -522,7 +524,7 @@
522524
When test is not nil, evaluates body with binding-form bound to the
523525
value of test"
524526
[bindings & body]
525-
(core/assert-args
527+
(assert-args when-some
526528
(vector? bindings) "a vector for its binding"
527529
(= 2 (count bindings)) "exactly 2 forms in binding vector")
528530
(core/let [form (bindings 0) tst (bindings 1)]
@@ -602,20 +604,6 @@
602604
`(when-not (exists? ~x)
603605
(def ~x ~init)))
604606

605-
(core/defmacro ^{:private true} assert-args [fnname & pairs]
606-
#?(:clj `(do (when-not ~(first pairs)
607-
(throw (IllegalArgumentException.
608-
~(core/str fnname " requires " (second pairs)))))
609-
~(core/let [more (nnext pairs)]
610-
(core/when more
611-
(list* `assert-args fnname more))))
612-
:cljs `(do (when-not ~(first pairs)
613-
(throw (js/Error.
614-
~(core/str fnname " requires " (second pairs)))))
615-
~(core/let [more (nnext pairs)]
616-
(core/when more
617-
(list* `assert-args fnname more))))))
618-
619607
(core/defn destructure [bindings]
620608
(core/let [bents (partition 2 bindings)
621609
pb (core/fn pb [bvec b v]

src/main/clojure/cljs/support.cljc

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
; Copyright (c) Rich Hickey. All rights reserved.
2+
; The use and distribution terms for this software are covered by the
3+
; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php)
4+
; which can be found in the file epl-v10.html at the root of this distribution.
5+
; By using this software in any fashion, you are agreeing to be bound by
6+
; the terms of this license.
7+
; You must not remove this notice, or any other, from this software.
8+
9+
(ns cljs.support)
10+
11+
(defmacro assert-args
12+
"Internal - do not use!"
13+
[fnname & pairs]
14+
`(do (when-not ~(first pairs)
15+
(throw (ex-info ~(str fnname " requires " (second pairs)) {})))
16+
~(let [more (nnext pairs)]
17+
(when more
18+
(list* `assert-args fnname more)))))

src/test/self/self_host/test.cljs

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -217,6 +217,29 @@
217217
(fn [{:keys [error value]}]
218218
(is (= "1" value)))))
219219

220+
(deftest test-CLJS-1551
221+
(cljs/eval-str st
222+
"(if-let [x true y true] 3)"
223+
nil
224+
{:eval node-eval}
225+
(fn [{:keys [error value]}]
226+
(is (nil? value))
227+
(is (= "if-let requires exactly 2 forms in binding vector at line 1 " (ex-message (ex-cause error))))))
228+
(cljs/eval-str st
229+
"(if-let [x true] 1 2 3)"
230+
nil
231+
{:eval node-eval}
232+
(fn [{:keys [error value]}]
233+
(is (nil? value))
234+
(is (= "if-let requires 1 or 2 forms after binding vector at line 1 " (ex-message (ex-cause error))))))
235+
(cljs/eval-str st
236+
"(if-let '(x true) 1)"
237+
nil
238+
{:eval node-eval}
239+
(fn [{:keys [error value]}]
240+
(is (nil? value))
241+
(is (= "if-let requires a vector for its binding at line 1 " (ex-message (ex-cause error)))))))
242+
220243
#_(deftest test-eval-str-with-require
221244
(async done
222245
(let [l (latch 3 done)]

0 commit comments

Comments
 (0)