From 8bc5bd6f617e5c5f1ea9dcbf991bcf855f0b5ad2 Mon Sep 17 00:00:00 2001 From: Yogthos Date: Sun, 7 Jun 2026 19:49:27 -0400 Subject: [PATCH] =?UTF-8?q?core:=20port=20when-let=20to=20the=20overlay=20?= =?UTF-8?q?=E2=80=94=20finishes=20the=20Phase=203=20macro=20migration?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Last core macro still in Janet. Goes in 00-syntax (not 30-macros with its if-let/if-some/when-some siblings) because 20-coll's not-empty uses it and 20-coll loads before 30. Via `let` so the binding form may destructure, matching Clojure — the old Janet version used let* and wouldn't. Drops core-when-let + the sym* helper + the intern entry, and empties core-macro-names (no seed binding is a macro anymore). --- jolt-core/clojure/core/00-syntax.clj | 9 +++++++++ jolt-core/clojure/core/30-macros.clj | 2 ++ src/jolt/core.janet | 25 +++++-------------------- 3 files changed, 16 insertions(+), 20 deletions(-) diff --git a/jolt-core/clojure/core/00-syntax.clj b/jolt-core/clojure/core/00-syntax.clj index 447f572..a549bee 100644 --- a/jolt-core/clojure/core/00-syntax.clj +++ b/jolt-core/clojure/core/00-syntax.clj @@ -321,3 +321,12 @@ ;; (for handles :when/:let/:while and multiple bindings). (defmacro doseq [bindings & body] `(do (count (for ~bindings (do ~@body nil))) nil)) + +;; when-let must live in this (early) tier, not 30-macros with its if-let/if-some/ +;; when-some siblings: 20-coll uses it (not-empty), and 20-coll loads before 30. The +;; name binds only in the taken branch (temp# tests the value); via `let` so the +;; binding form may itself destructure, matching Clojure. +(defmacro when-let [bindings & body] + (let [form (bindings 0) tst (bindings 1)] + `(let [temp# ~tst] + (if temp# (let [~form temp#] ~@body) nil)))) diff --git a/jolt-core/clojure/core/30-macros.clj b/jolt-core/clojure/core/30-macros.clj index 8678a57..6e3c900 100644 --- a/jolt-core/clojure/core/30-macros.clj +++ b/jolt-core/clojure/core/30-macros.clj @@ -25,6 +25,8 @@ `(let [temp# ~tst] (if temp# (let [~form temp#] ~then) ~else)))) +;; when-let lives in 00-syntax (not here): 20-coll uses it, which loads before this tier. + (defmacro if-some [bindings then & [else]] (let [form (bindings 0) tst (bindings 1)] `(let [temp# ~tst] diff --git a/src/jolt/core.janet b/src/jolt/core.janet index 8bf5f57..596e1ff 100644 --- a/src/jolt/core.janet +++ b/src/jolt/core.janet @@ -2048,23 +2048,8 @@ {:jolt/type :symbol :ns nil :name (string prefix-string n)}) -# if-let / when-let / if-some / when-some bind the name ONLY in the then/body -# branch — the else branch must see the surrounding scope, not the binding (so -# (let [x 5] (if-let [x nil] x x)) returns 5, like Clojure). Achieved with a fresh -# temp around the if; the name is rebound to the temp inside the taken branch only. -(defn- sym* [name] {:jolt/type :symbol :ns nil :name name}) - -(defn core-when-let - "Macro: (when-let [binding val-expr] & body)" - [bindings & body] - (def form-sym (in bindings 0)) - (def val-form (in bindings 1)) - (def temp (gensym "when_let__")) - @[(sym* "let*") @[temp val-form] - @[(sym* "if") temp - @[(sym* "let*") @[form-sym temp] @[(sym* "do") ;body]] - nil]]) - +# if-let/when-let/if-some/when-some now live in the Clojure overlay +# (core/30-macros.clj) as defmacros. (defn core-push-thread-bindings [b] (push-thread-bindings b)) (defn core-pop-thread-bindings [] (pop-thread-bindings)) @@ -3090,7 +3075,6 @@ "add-watch" core-add-watch "remove-watch" core-remove-watch "not" core-not - "when-let" core-when-let "derive" core-derive "isa?" core-isa? "parents" core-parents @@ -3156,9 +3140,10 @@ "*assert" true}) (defn core-macro-names - "Set of core binding names that are macros." + "Set of core binding names that are macros. Empty now that every core macro + lives in the Clojure overlay (clojure.core.*-syntax / *-macros tiers)." [] - @{"when-let" true}) + @{}) (def init-core! (fn [& args]