Skip to content

Commit

Permalink
Fix #586: extend protocol to nil (#587)
Browse files Browse the repository at this point in the history
  • Loading branch information
borkdude authored Nov 29, 2024
1 parent 57f0301 commit bdb7ddc
Show file tree
Hide file tree
Showing 5 changed files with 53 additions and 13 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

[Squint](https://github.com/squint-cljs/squint): Light-weight ClojureScript dialect

## v0.8.126 (2024-11-29)

- [#586](https://github.com/squint-cljs/squint/issues/586): support extending protocol to `nil`

## v0.8.125 (2024-11-28)

- [#581](https://github.com/squint-cljs/squint/issues/581): support docstring in `defprotocol`
Expand Down
1 change: 1 addition & 0 deletions resources/squint/core.edn
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
_LT__EQ_
_PLUS_
_STAR_
__protocol_satisfies
_iterator
abs
aclone
Expand Down
5 changes: 5 additions & 0 deletions src/squint/core.js
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,12 @@ export function _(...xs) {
return xs.reduce((x, y) => x - y);
}

export const __protocol_satisfies = {};

export function satisfies_QMARK_(protocol, x) {
if (x == null) {
return __protocol_satisfies[protocol];
}
return x[protocol];
}

Expand Down
40 changes: 27 additions & 13 deletions src/squint/internal/protocols.cljc
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,13 @@
(:require [clojure.core :as core]))

(core/defn- emit-protocol-method-arity
[method-sym args]
`(~args
((unchecked-get ~(first args) ; this
~method-sym) ~@args)))
[mname method-sym args]
(let [this (first args)]
`(~args
(if (nil? ~this)
((unchecked-get ~mname nil) ~@args)
((unchecked-get ~(first args) ;; this
~method-sym) ~@args)))))

(core/defn- emit-protocol-method
[p method]
Expand All @@ -19,7 +22,7 @@
(js/Symbol ~(str p "_" mname)))
(defn ~mname
~@(when mdocs [mdocs])
~@(map #(emit-protocol-method-arity method-sym %) margs)))))
~@(map #(emit-protocol-method-arity mname method-sym %) margs)))))

(core/defn core-defprotocol
[_&env _&form p & doc+methods]
Expand Down Expand Up @@ -56,7 +59,8 @@
(defn insert-this [method-bodies]
(if (vector? (first method-bodies))
(list* (first method-bodies)
(list 'js* "const self__ = this")
(with-meta (list 'js* "const self__ = this;")
{:context :statement})
(rest method-bodies))
;; multi-arity
(map insert-this method-bodies)))
Expand All @@ -68,16 +72,26 @@
(str mname)
(symbol (str psym "_" mname)))
f `(fn ~@(insert-this (rest method)))]
`(let [f# ~f]
(unchecked-set
(.-prototype ~type-sym) ~msym f#))))
(if (nil? type-sym)
`(let [f# ~f]
(unchecked-set
~mname
~type-sym f#))
`(let [f# ~f]
(unchecked-set
(.-prototype ~type-sym) ~msym f#)))))

(core/defn- emit-type-methods
[type-sym [psym pmethods]]
`((unchecked-set
(.-prototype ~type-sym)
~psym true)
~@(map #(emit-type-method psym type-sym %) pmethods)))
(let [flag (if (nil? type-sym)
`(unchecked-set
~'clojure.core/__protocol_satisfies
~psym true)
`(unchecked-set
(.-prototype ~type-sym)
~psym true))]
`(~flag
~@(map #(emit-type-method psym type-sym %) pmethods))))

(core/defn core-extend-type
[_&env _&form type-sym & impls]
Expand Down
16 changes: 16 additions & 0 deletions test/squint/compiler_test.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -458,6 +458,22 @@
object (i [s] s))
[(i "dude") (i 1)])))))

(deftest defprotocol-extend-protocol-empty-body-test
(is (eq nil
(jsv! '(do (defprotocol Identity (i [this]))
(extend-protocol Identity string (i [s]))
(i "dude"))))))

(deftest defprotocol-extend-protocol-nil
(is (eq ["nil" "boolean" "string" true]
(jsv! '(do (defprotocol Identity (i [this]))
(extend-protocol Identity nil (i [s] "nil"))
(extend-protocol Identity boolean (i [s] "boolean"))
(extend-protocol Identity string (i [s] "string"))
[(i nil) (i false) (i "")
(satisfies? Identity nil)
])))))

(deftest deftype-test
(is (= 1 (jsv! '(do (deftype Foo [x]) (.-x (->Foo 1))))))
(is (eq [:foo :bar]
Expand Down

0 comments on commit bdb7ddc

Please sign in to comment.