|
247 | 247 | :cljs (defn ->record-impl [rec-name type var m] |
248 | 248 | (SciRecord. rec-name type var m nil))) |
249 | 249 |
|
250 | | -(defn defrecord [[_fname & _ :as form] _ ctx record-name & fields+raw-protocol-impls] |
251 | | - (if (:sci.impl/macroexpanding ctx) |
252 | | - (cons 'clojure.core/defrecord (rest form)) |
253 | | - (let [[ctx record-name fields raw-protocol-impls] |
254 | | - (if (symbol? ctx) |
255 | | - [(store/get-ctx) ctx record-name fields+raw-protocol-impls] |
256 | | - [ctx record-name (first fields+raw-protocol-impls) (next fields+raw-protocol-impls)]) |
257 | | - factory-fn-str (str "->" record-name) |
258 | | - factory-fn-sym (symbol factory-fn-str) |
259 | | - constructor-fn-sym (symbol (str "__" factory-fn-str "__ctor__")) |
260 | | - map-factory-sym (symbol (str "map" factory-fn-str)) |
261 | | - keys (mapv keyword fields) |
262 | | - rec-type (symbol (str (munge (utils/current-ns-name)) "." record-name)) |
263 | | - protocol-impls (utils/split-when symbol? raw-protocol-impls) |
264 | | - field-set (set fields) |
265 | | - protocol-impls |
266 | | - (mapcat |
267 | | - (fn [[protocol-name & impls] #?(:clj expr :cljs expr)] |
268 | | - (let [impls (group-by first impls) |
269 | | - protocol (@utils/eval-resolve-state ctx (:bindings ctx) protocol-name) |
270 | | - ;; _ (prn :protocol protocol) |
271 | | - #?@(:cljs [protocol (or protocol |
272 | | - (when (= 'Object protocol-name) |
273 | | - ::object))]) |
274 | | - _ (when-not protocol |
275 | | - (utils/throw-error-with-location |
276 | | - (str "Protocol not found: " protocol-name) |
277 | | - expr)) |
278 | | - #?@(:clj [_ (assert-no-jvm-interface protocol protocol-name expr)]) |
279 | | - protocol (if (utils/var? protocol) @protocol protocol) |
280 | | - protocol-var (:var protocol) |
281 | | - _ (when protocol-var |
282 | | - ;; TODO: not all externally defined protocols might have the :var already |
283 | | - (vars/alter-var-root protocol-var update :satisfies |
284 | | - (fnil conj #{}) (protocols/type->str rec-type))) |
285 | | - protocol-ns (:ns protocol) |
286 | | - pns (cond protocol-ns (str (types/getName protocol-ns)) |
287 | | - (= #?(:clj Object :cljs ::object) protocol) "sci.impl.records") |
288 | | - fq-meth-name #(if (simple-symbol? %) |
289 | | - (symbol pns (str %)) |
290 | | - %)] |
291 | | - (map (fn [[method-name bodies]] |
292 | | - (let [bodies (map rest bodies) |
293 | | - bodies (mapv (fn [impl] |
294 | | - (let [args (first impl) |
295 | | - body (rest impl) |
296 | | - destr (utils/maybe-destructured args body) |
297 | | - args (:params destr) |
298 | | - body (:body destr) |
299 | | - orig-this-sym (first args) |
300 | | - rest-args (rest args) |
301 | | - shadows-this? (some #(= orig-this-sym %) rest-args) |
302 | | - this-sym (if shadows-this? |
303 | | - (gensym "this_") |
304 | | - orig-this-sym) |
305 | | - args (if shadows-this? |
306 | | - (vec (cons this-sym rest-args)) |
307 | | - args) |
308 | | - bindings (mapcat (fn [field] |
309 | | - [field (list (keyword field) this-sym)]) |
310 | | - (reduce disj field-set args)) |
311 | | - bindings (if shadows-this? |
312 | | - (concat bindings [orig-this-sym this-sym]) |
313 | | - bindings) |
314 | | - bindings (vec bindings)] |
315 | | - `(~args |
316 | | - (let ~bindings |
317 | | - ~@body)))) bodies)] |
318 | | - `(defmethod ~(fq-meth-name method-name) ~rec-type ~@bodies))) |
319 | | - impls))) |
320 | | - protocol-impls |
321 | | - raw-protocol-impls) |
322 | | - arg-syms (mapv #(symbol (name %)) keys) |
323 | | - nil-map (zipmap (map keyword field-set) (repeat nil))] |
324 | | - `(do |
325 | | - (declare ~record-name ~factory-fn-sym ~constructor-fn-sym ~map-factory-sym) |
326 | | - (def ~(with-meta record-name |
327 | | - {:sci/record true}) |
328 | | - (sci.impl.records/-create-record-type |
329 | | - ~{:sci.impl/type-name (list 'quote rec-type) |
330 | | - :sci.impl/record true |
331 | | - :sci.impl/constructor (list 'var constructor-fn-sym) |
332 | | - :sci.impl/var (list 'var record-name) |
333 | | - :sci.impl.record/map-constructor (list 'var map-factory-sym)})) |
334 | | - (defn ~constructor-fn-sym |
335 | | - ([~@arg-syms] |
336 | | - (~constructor-fn-sym ~@arg-syms nil nil)) |
337 | | - ([~@arg-syms meta# ext#] |
338 | | - (sci.impl.records/->record-impl '~rec-type ~rec-type (var ~record-name) |
339 | | - (cond-> (zipmap ~keys ~arg-syms) |
340 | | - ext# (merge ext#) |
341 | | - meta# (with-meta meta#))))) |
342 | | - (defn ~factory-fn-sym |
343 | | - ([~@arg-syms] |
344 | | - (~constructor-fn-sym ~@arg-syms nil nil))) |
345 | | - (defn ~map-factory-sym [m#] |
346 | | - (sci.impl.records/->record-impl '~rec-type ~rec-type (var ~record-name) (merge '~nil-map m#))) |
347 | | - ~@protocol-impls |
348 | | - ~record-name)))) |
| 250 | +(defn defrecord [[_fname & _ :as form] _ record-name fields & raw-protocol-impls] |
| 251 | + (let [ctx (store/get-ctx)] |
| 252 | + (if (:sci.impl/macroexpanding ctx) |
| 253 | + (cons 'clojure.core/defrecord (rest form)) |
| 254 | + (let [factory-fn-str (str "->" record-name) |
| 255 | + factory-fn-sym (symbol factory-fn-str) |
| 256 | + constructor-fn-sym (symbol (str "__" factory-fn-str "__ctor__")) |
| 257 | + map-factory-sym (symbol (str "map" factory-fn-str)) |
| 258 | + keys (mapv keyword fields) |
| 259 | + rec-type (symbol (str (munge (utils/current-ns-name)) "." record-name)) |
| 260 | + protocol-impls (utils/split-when symbol? raw-protocol-impls) |
| 261 | + field-set (set fields) |
| 262 | + protocol-impls |
| 263 | + (mapcat |
| 264 | + (fn [[protocol-name & impls] #?(:clj expr :cljs expr)] |
| 265 | + (let [impls (group-by first impls) |
| 266 | + protocol (@utils/eval-resolve-state ctx (:bindings ctx) protocol-name) |
| 267 | + ;; _ (prn :protocol protocol) |
| 268 | + #?@(:cljs [protocol (or protocol |
| 269 | + (when (= 'Object protocol-name) |
| 270 | + ::object))]) |
| 271 | + _ (when-not protocol |
| 272 | + (utils/throw-error-with-location |
| 273 | + (str "Protocol not found: " protocol-name) |
| 274 | + expr)) |
| 275 | + #?@(:clj [_ (assert-no-jvm-interface protocol protocol-name expr)]) |
| 276 | + protocol (if (utils/var? protocol) @protocol protocol) |
| 277 | + protocol-var (:var protocol) |
| 278 | + _ (when protocol-var |
| 279 | + ;; TODO: not all externally defined protocols might have the :var already |
| 280 | + (vars/alter-var-root protocol-var update :satisfies |
| 281 | + (fnil conj #{}) (protocols/type->str rec-type))) |
| 282 | + protocol-ns (:ns protocol) |
| 283 | + pns (cond protocol-ns (str (types/getName protocol-ns)) |
| 284 | + (= #?(:clj Object :cljs ::object) protocol) "sci.impl.records") |
| 285 | + fq-meth-name #(if (simple-symbol? %) |
| 286 | + (symbol pns (str %)) |
| 287 | + %)] |
| 288 | + (map (fn [[method-name bodies]] |
| 289 | + (let [bodies (map rest bodies) |
| 290 | + bodies (mapv (fn [impl] |
| 291 | + (let [args (first impl) |
| 292 | + body (rest impl) |
| 293 | + destr (utils/maybe-destructured args body) |
| 294 | + args (:params destr) |
| 295 | + body (:body destr) |
| 296 | + orig-this-sym (first args) |
| 297 | + rest-args (rest args) |
| 298 | + shadows-this? (some #(= orig-this-sym %) rest-args) |
| 299 | + this-sym (if shadows-this? |
| 300 | + (gensym "this_") |
| 301 | + orig-this-sym) |
| 302 | + args (if shadows-this? |
| 303 | + (vec (cons this-sym rest-args)) |
| 304 | + args) |
| 305 | + bindings (mapcat (fn [field] |
| 306 | + [field (list (keyword field) this-sym)]) |
| 307 | + (reduce disj field-set args)) |
| 308 | + bindings (if shadows-this? |
| 309 | + (concat bindings [orig-this-sym this-sym]) |
| 310 | + bindings) |
| 311 | + bindings (vec bindings)] |
| 312 | + `(~args |
| 313 | + (let ~bindings |
| 314 | + ~@body)))) bodies)] |
| 315 | + `(defmethod ~(fq-meth-name method-name) ~rec-type ~@bodies))) |
| 316 | + impls))) |
| 317 | + protocol-impls |
| 318 | + raw-protocol-impls) |
| 319 | + arg-syms (mapv #(symbol (name %)) keys) |
| 320 | + nil-map (zipmap (map keyword field-set) (repeat nil))] |
| 321 | + `(do |
| 322 | + (declare ~record-name ~factory-fn-sym ~constructor-fn-sym ~map-factory-sym) |
| 323 | + (def ~(with-meta record-name |
| 324 | + {:sci/record true}) |
| 325 | + (sci.impl.records/-create-record-type |
| 326 | + ~{:sci.impl/type-name (list 'quote rec-type) |
| 327 | + :sci.impl/record true |
| 328 | + :sci.impl/constructor (list 'var constructor-fn-sym) |
| 329 | + :sci.impl/var (list 'var record-name) |
| 330 | + :sci.impl.record/map-constructor (list 'var map-factory-sym)})) |
| 331 | + (defn ~constructor-fn-sym |
| 332 | + ([~@arg-syms] |
| 333 | + (~constructor-fn-sym ~@arg-syms nil nil)) |
| 334 | + ([~@arg-syms meta# ext#] |
| 335 | + (sci.impl.records/->record-impl '~rec-type ~rec-type (var ~record-name) |
| 336 | + (cond-> (zipmap ~keys ~arg-syms) |
| 337 | + ext# (merge ext#) |
| 338 | + meta# (with-meta meta#))))) |
| 339 | + (defn ~factory-fn-sym |
| 340 | + ([~@arg-syms] |
| 341 | + (~constructor-fn-sym ~@arg-syms nil nil))) |
| 342 | + (defn ~map-factory-sym [m#] |
| 343 | + (sci.impl.records/->record-impl '~rec-type ~rec-type (var ~record-name) (merge '~nil-map m#))) |
| 344 | + ~@protocol-impls |
| 345 | + ~record-name))))) |
349 | 346 |
|
350 | 347 | (defn resolve-record-or-protocol-class |
351 | 348 | "A record class is represented by a symbol with metadata (currently). This is only an implementation detail. |
|
0 commit comments