ir/analyzer: omit absent fields instead of writing nil
def-node carried :meta nil when a def had no metadata, fn-node carried :name nil for anonymous fns, analyze-arity carried :rest nil for fixed arities, and empty-env carried :recur nil. These all mean genuine absence, and every consumer reads an absent key back as nil — so writing the nil is gratuitous. Dropping them keeps the common nodes (defs, fns, fixed arities) nil-free, so once user maps preserve nil they stay plain structs instead of becoming phm. Faithful nil values (a nil const :val) are left as-is; the back end handles those. No-op today since structs already drop nil: suite, conformance 218/218 x3, fixpoint, fib all unchanged.
This commit is contained in:
parent
22ff737f8b
commit
b2ff65972b
2 changed files with 19 additions and 9 deletions
|
|
@ -38,7 +38,7 @@
|
|||
(swap! gensym-counter inc)
|
||||
(str "_r$" prefix n)))
|
||||
|
||||
(defn- empty-env [] {:locals #{} :recur nil})
|
||||
(defn- empty-env [] {:locals #{}})
|
||||
(defn- local? [env nm] (contains? (:locals env) nm))
|
||||
(defn- add-locals [env names] (update env :locals #(reduce conj % names)))
|
||||
(defn- with-recur [env name] (assoc env :recur name))
|
||||
|
|
@ -82,9 +82,12 @@
|
|||
;; is a self-call carrying the rest seq directly — Clojure semantics.
|
||||
rname (gen-name "arity")
|
||||
names (cond-> (vec fixed) rst (conj rst) fn-name (conj fn-name))
|
||||
env* (-> (add-locals env names) (with-recur rname))]
|
||||
{:params fixed :rest rst :recur-name rname
|
||||
:body (analyze-seq ctx body env*)}))
|
||||
env* (-> (add-locals env names) (with-recur rname))
|
||||
arity {:params fixed :recur-name rname
|
||||
:body (analyze-seq ctx body env*)}]
|
||||
;; :rest only when variadic — an absent :rest reads back nil, same as before,
|
||||
;; but keeps a fixed arity a nil-free struct rather than a phm.
|
||||
(if rst (assoc arity :rest rst) arity)))
|
||||
|
||||
(defn- analyze-fn [ctx items env]
|
||||
(let [named (form-sym? (nth items 1))
|
||||
|
|
|
|||
|
|
@ -30,15 +30,22 @@
|
|||
(defn invoke [f args] {:op :invoke :fn f :args args})
|
||||
|
||||
;; meta is the var metadata (e.g. {:dynamic true} / {:redef true}) the back end
|
||||
;; applies to the cell; nil when the def name carried none.
|
||||
;; applies to the cell; absent when the def name carried none.
|
||||
(defn def-node
|
||||
([ns name init] {:op :def :ns ns :name name :init init :meta nil})
|
||||
([ns name init meta] {:op :def :ns ns :name name :init init :meta meta}))
|
||||
([ns name init] {:op :def :ns ns :name name :init init})
|
||||
([ns name init meta]
|
||||
(if meta
|
||||
{:op :def :ns ns :name name :init init :meta meta}
|
||||
{:op :def :ns ns :name name :init init})))
|
||||
|
||||
(defn let-node [bindings body] {:op :let :bindings bindings :body body})
|
||||
|
||||
;; A fn is one or more arities. Each arity: {:params [..] :rest name|nil :body ir}.
|
||||
(defn fn-node [name arities] {:op :fn :name name :arities arities})
|
||||
;; A fn is one or more arities. Each arity: {:params [..] :body ir}, plus :rest
|
||||
;; name when variadic. :name is absent for an anonymous fn.
|
||||
(defn fn-node [name arities]
|
||||
(if name
|
||||
{:op :fn :name name :arities arities}
|
||||
{:op :fn :arities arities}))
|
||||
|
||||
(defn vector-node [items] {:op :vector :items items})
|
||||
(defn map-node [pairs] {:op :map :pairs pairs})
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue