From 08c796c145aee59b4535f313df9373a42e772030 Mon Sep 17 00:00:00 2001 From: Yogthos Date: Sun, 7 Jun 2026 17:36:06 -0400 Subject: [PATCH] core: move defn and defn- to the syntax tier defn drops an optional leading docstring/attr-map then emits (def name (fn* ...)). Single- and multi-arity both reduce to (fn* ~@body) so no arity branching is needed. map? is true for symbol forms in Jolt, so the attr-map strip is guarded with symbol?. defn- delegates to defn (privacy isn't enforced, as in Clojure's own defn-). Placed before fresh-sym, which is itself a defn- now. All five fundamental macros (fn/let/loop/defn/defn-) are now in the overlay. conformance 228x3, fixpoint, clojure-test-suite 3930, full suite green. --- jolt-core/clojure/core/00-syntax.clj | 15 +++++++++++ src/jolt/core.janet | 38 +--------------------------- 2 files changed, 16 insertions(+), 37 deletions(-) diff --git a/jolt-core/clojure/core/00-syntax.clj b/jolt-core/clojure/core/00-syntax.clj index e558ea3..1f73d3c 100644 --- a/jolt-core/clojure/core/00-syntax.clj +++ b/jolt-core/clojure/core/00-syntax.clj @@ -80,6 +80,21 @@ (defmacro loop [bindings & body] `(loop* ~bindings ~@body)) +;; defn: drop an optional leading docstring and attr-map, then (def name (fn* ...)). +;; Both single- and multi-arity reduce to (fn* ~@body) — fn* takes either a params +;; vector + body or a sequence of ([params] body) clauses, so no arity branching is +;; needed. (map? is true for symbol forms too, so guard the attr-map with symbol?.) +;; Defined before fresh-sym below, which is a defn-. +(defmacro defn [fn-name & body] + (let [body (if (and (seq body) (string? (first body))) (rest body) body) + body (if (and (seq body) (map? (first body)) (not (symbol? (first body)))) + (rest body) body)] + `(def ~fn-name (fn* ~@body)))) + +;; Jolt doesn't enforce privacy, so defn- is just defn (matching how Clojure's own +;; defn- delegates to defn with :private metadata). +(defmacro defn- [fn-name & body] `(defn ~fn-name ~@body)) + ;; A fresh jolt symbol inside a macro body (a bare (gensym) returns a Janet symbol ;; the destructurer rejects). This defn compiles fine: by the time a tier triggers ;; the analyzer build the kernel is in place (the build is gated until then). diff --git a/src/jolt/core.janet b/src/jolt/core.janet index 00e6a81..3fb6487 100644 --- a/src/jolt/core.janet +++ b/src/jolt/core.janet @@ -2093,40 +2093,6 @@ (defn core-intern [ns-name sym-name val] val) -(defn- defn->def - "Shared expansion for defn/defn-: (name doc-string? attr-map? params body...) - or (name doc-string? attr-map? ([params] body)... attr-map?) -> (def name (fn* ...))." - [fn-name rest] - (var items (array/slice rest)) - # strip optional docstring - (when (and (> (length items) 0) (string? (first items))) - (set items (array/slice items 1))) - # strip optional attr-map (a map literal, i.e. struct/table that isn't a symbol) - (when (and (> (length items) 0) - (let [x (first items)] - (and (or (struct? x) (table? x)) - (not (and (struct? x) (= :symbol (get x :jolt/type))))))) - (set items (array/slice items 1))) - (def fn-form @[{:jolt/type :symbol :ns nil :name "fn*"}]) - (if (and (> (length items) 0) (array? (first items)) (indexed? (first (first items)))) - # multi-arity: each remaining item is an ([params] body...) clause - (each pair items (array/push fn-form pair)) - # single-arity: items = [params-vector body...] - (do - (array/push fn-form (first items)) - (each b (tuple/slice items 1) (array/push fn-form b)))) - @[{:jolt/type :symbol :ns nil :name "def"} fn-name fn-form]) - -(defn core-defn - "Macro: (defn name doc-string? attr-map? [args] body...) (or multi-arity) - -> (def name (fn* ...))" - [fn-name & rest] - (defn->def fn-name rest)) - -# defn- — same as defn (private not enforced in Jolt) -(defn core-defn- [fn-name & rest] - (defn->def fn-name rest)) - # Hierarchy stubs for sci bootstrap (def core-make-hierarchy make-hierarchy) (defn core-derive @@ -3390,8 +3356,6 @@ "remove-watch" core-remove-watch "not" core-not "when-let" core-when-let - "defn" core-defn - "defn-" core-defn- "derive" core-derive "isa?" core-isa? "parents" core-parents @@ -3467,7 +3431,7 @@ (defn core-macro-names "Set of core binding names that are macros." [] - @{"when-let" true "defn" true "defn-" true "defrecord" true "defprotocol" true "extend-type" true "extend-protocol" true "extend" true "reify" true "proxy" true "definterface" true "lazy-seq" true "lazy-cat" true}) + @{"when-let" true "defrecord" true "defprotocol" true "extend-type" true "extend-protocol" true "extend" true "reify" true "proxy" true "definterface" true "lazy-seq" true "lazy-cat" true}) (def init-core! (fn [& args]