sci

2025-08-13T19:23:45.380149Z

Has anyone written sci cljs bindings for core.match? I’m looking to add them to a forked nbb. I tried emulating the https://github.com/babashka/babashka/blob/master/feature-core-match/babashka/impl/match.clj with https://github.com/logseq/nbb-logseq/blob/add-core-match-failing/features/core.match/src/nbb/impl/core_match.cljs. However this failed with Unable to resolve var match/match. I thought I’d read somewhere that copy-var works for macros. In the meantime, I have a hacky approach I’ll expand on in a thread

2025-08-14T13:52:34.409029Z

Gotcha. The https://github.com/clojure/core.match/blob/753e8a30de9c487ceba8ff7d39435bf87edff505/src/main/clojure/cljs/core/match.clj#L19-L32 macro is dependent on a clojure var, https://github.com/clojure/core.match/blob/753e8a30de9c487ceba8ff7d39435bf87edff505/src/main/clojure/clojure/core/match.clj#L2083-L2096 ,which is at the bottom of a 2k line jvm ns. The fork is basically doing the work of converting that jvm ns to be cljs compatible. I’ll give the fork a try

2025-08-14T15:28:31.764669Z

I ran tests on viebel’s fork. Good news is that most match tests. Bad news is that ones involving a map fail hard because cljs.core/ILookup doesn’t exist. If you’re curious, you can checkout https://github.com/logseq/nbb-logseq/tree/add-core-match and just run bb test as the nbb compiled assets are included. I looked at modifying the ILookup calls in the fork but there are about https://github.com/viebel/abbinare/blob/master/src/main/clojure/cljs/core/match.cljc . Going down this path seems brittle and error prone. Unless I’m missing something, I’ll look at ripping out core.match for the code I’m making nbb compatible. I can add this use case to https://github.com/babashka/sci/issues/639 if it seems helpful

borkdude 2025-08-14T17:12:53.107419Z

this is only applicable if you are trying to run core.match from source? your original post was about SCI CLJS bindings (meaning configuration) which is a different use case?

2025-08-14T17:34:00.945079Z

Not sure I follow. I’m building nbb-logseq with https://github.com/logseq/nbb-logseq/blob/add-core-match/features/core.match/src/nbb/impl/core_match.cljs . When I run https://github.com/logseq/nbb-logseq/blob/add-core-match/test/core_match_match_test.cljs with nbb-logseq (via bb test), nbb fails hard with Could not resolve symbol: cljs.core/ILookup

borkdude 2025-08-14T17:45:14.136879Z

is this because a macro expands into that symbol?

2025-08-14T17:51:08.548869Z

Possibly. The full failure looks like:

Running core.match tests...
----- Error --------------------------------------
Message:  Could not resolve symbol: cljs.core/ILookup
Location: /Users/me/code/work/nbb-logseq/test/core_match_match_test.cljs:110:11
Phase:    analysis

----- Context ------------------------------------
106: (deftest test-map-patterns
107:   (testing "Map patterns"
108:     (is
109:      (= (let [x {:a 1 :b 1}]
110:           (match [x]
               ^--- Could not resolve symbol: cljs.core/ILookup
111:             [{:a _ :b 2}] :a0
112:             [{:a 1 :b 1}] :a1
113:             [{:c 3 :d _ :e 4}] :a2
114:             :else nil))
115:         :a1))
The sci bindings compile https://github.com/viebel/abbinare/blob/master/src/main/clojure/cljs/core/match.cljc which has about a dozen references to cljs.core/ILookup

borkdude 2025-08-14T17:54:15.586459Z

This looks like it's used in a macro expansion: https://github.com/viebel/abbinare/blob/e1e4a3c9d083b495a02c080f86a05aa10275e6d0/src/main/clojure/cljs/core/match.cljc#L149

borkdude 2025-08-14T18:04:27.139019Z

you can at least add ILookup to nbb.core's core config to get past this

borkdude 2025-08-14T18:04:46.674049Z

probably still won't work but let's see what the next step is

2025-08-14T18:31:03.566479Z

Added ILookup to nbb.core and pushed to https://github.com/logseq/nbb-logseq/tree/add-core-match. Tests can now run with bb test but understandably 20 of 91 assertions now fail

borkdude 2025-08-14T18:32:10.857309Z

failing how? more info would be helpful

2025-08-14T18:34:25.808659Z

Sure. It seems tests are failing since maps aren’t matching like they should. Here’s the full test output:

$ bb test
Running cljs-time tests...

Testing cljs-time-format-test

Ran 1 tests containing 19 assertions.
0 failures, 0 errors.
Running core.match tests...
benchmarking
basic Maranget example hand written
2866665
"Elapsed time: 518.914458 msecs"
basic Maranget example
"Elapsed time: 2768.185958 msecs"

Testing core-match-match-test

FAIL in (test-map-patterns) (/Users/me/code/work/nbb-logseq/test/core_match_test_runner.cljs:109)
Map patterns
expected: (= (let [x {:a 1, :b 1}] (match [x] [{:a _, :b 2}] :a0 [{:a 1, :b 1}] :a1 [{:c 3, :d _, :e 4}] :a2 :else nil)) :a1)
  actual: (not (= nil :a1))

FAIL in (test-map-patterns) (/Users/me/code/work/nbb-logseq/test/core_match_test_runner.cljs:117)
Map patterns
expected: (= (let [x {:a 1, :b 2}] (match [x] [{:a _, :b 2}] :a0 [{:a 1, :b 1}] :a1 [{:c 3, :d _, :e 4}] :a2 :else nil)) :a0)
  actual: (not (= nil :a0))

FAIL in (test-map-patterns) (/Users/me/code/work/nbb-logseq/test/core_match_test_runner.cljs:125)
Map patterns
expected: (= (let [x {:c 3, :d 9, :e 4}] (match [x] [{:a _, :b 2}] :a0 [{:a 1, :b 1}] :a1 [{:c 3, :d _, :e 4}] :a2 :else nil)) :a2)
  actual: (not (= nil :a2))

FAIL in (test-map-patterns) (/Users/me/code/work/nbb-logseq/test/core_match_test_runner.cljs:141)
Map patterns
expected: (= (let [x {:a 1, :b 1}] (match [x] [{:a _, :b 1}] :a0 [{:a 1, :b _}] :a1 [{:c 3, :d _, :e 4}] :a2 :else [])) :a0)
  actual: (not (= [] :a0))

FAIL in (test-map-patterns) (/Users/me/code/work/nbb-logseq/test/core_match_test_runner.cljs:149)
Map patterns
expected: (= (let [x {:a 1, :b 1, :c 1}] (match [x] [{:a _, :b 2}] :a0 [{:a 1, :b _}] :a1 [{:c 3, :d _, :e 4}] :a2 :else [])) :a1)
  actual: (not (= [] :a1))

FAIL in (test-map-patterns) (/Users/me/code/work/nbb-logseq/test/core_match_test_runner.cljs:157)
Map patterns
expected: (= (let [x {:a 1, :b 1}] (match [x] [{:a _, :b 2}] :a0 [{:a _, :b _}] :a1 [{:c 3, :d _, :e 4}] :a2 :else [])) :a1)
  actual: (not (= [] :a1))

FAIL in (test-map-patterns) (/Users/me/code/work/nbb-logseq/test/core_match_test_runner.cljs:173)
Map patterns
expected: (= (let [x {:a 1, :b 1}] (match [x] [{:b 1}] :a0 [{:a _, :b _}] :a1 [{:a _, :b _}] :a2 :else [])) :a0)
  actual: (not (= [] :a0))

FAIL in (test-map-patterns) (/Users/me/code/work/nbb-logseq/test/core_match_test_runner.cljs:181)
Map patterns
expected: (= (let [x {:a 1, :b 1}] (match [x] [{}] :a0 [{:a _, :b _}] :a1 [{:a 1, :b 1}] :a2 :else [])) :a0)
  actual: (not (= [] :a0))

FAIL in (test-map-patterns) (/Users/me/code/work/nbb-logseq/test/core_match_test_runner.cljs:189)
Map patterns
expected: (= (let [x {:a 1, :b 1}] (match [x] [{:x nil, :y nil}] :a0 [{:a _, :b _}] :a1 [{:a 1, :b 1}] :a2 :else [])) :a1)
  actual: (not (= [] :a1))

FAIL in (test-map-patterns) (/Users/me/code/work/nbb-logseq/test/core_match_test_runner.cljs:197)
Map patterns
expected: (= (let [x {:a 1, :b 2}] (match [x] [({:a _, :b 2} :only [:a :b])] :a0 [{:a 1, :c _}] :a1 [{:c 3, :d _, :e 4}] :a2 :else [])) :a0)
  actual: (not (= [] :a0))

FAIL in (test-map-patterns) (/Users/me/code/work/nbb-logseq/test/core_match_test_runner.cljs:205)
Map patterns
expected: (= (let [x {:a 1, :b 2, :c 3}] (match [x] [({:a _, :b 2} :only [:a :b])] :a0 [{:a 1, :c _}] :a1 [{:c 3, :d _, :e 4}] :a2 :else [])) :a1)
  actual: (not (= [] :a1))

FAIL in (test-map-patterns) (/Users/me/code/work/nbb-logseq/test/core_match_test_runner.cljs:213)
Map patterns
expected: (= (let [x {:a 1, :b 2}] (match [x] [{:a a, :b b}] [:a0 a b] :else [])) [:a0 1 2])
  actual: (not (= [] [:a0 1 2]))

FAIL in (test-or-patterns) (/Users/me/code/work/nbb-logseq/test/core_match_test_runner.cljs:269)
Or patterns
expected: (= (let [x {:a 3} y nil z nil] (match [x y z] [{:a (:or 1 2)} _ _] :a0 [{:a (:or 3 4)} _ _] :a1 :else [])) :a1)
  actual: (not (= [] :a1))

FAIL in (test-else) (/Users/me/code/work/nbb-logseq/test/core_match_test_runner.cljs:357)
Test :else support
expected: (= (let [v {:a 1}] (match [v] [{:a a}] 1 :else 21)) 1)
  actual: (not (= 21 1))

FAIL in (test-edge-cases-4) (/Users/me/code/work/nbb-logseq/test/core_match_test_runner.cljs:556)
Edge cases 4
expected: (= (let [x {:a 1, :b 2, :c 10, :d 30}] (match [x] [({:a _, :b _, :c _, :d _} :only [:a :b :c :d])] :a-1 [({:a _, :b 2} :only [:a :b])] :a0 [{:a 1, :c _}] :a1 [{:c 3, :d _, :e 4}] :a2 :else [])) :a-1)
  actual: (not (= [] :a-1))

FAIL in (test-edge-cases-4) (/Users/me/code/work/nbb-logseq/test/core_match_test_runner.cljs:567)
Edge cases 4
expected: (and (= (let [m {:a 1}] (match [m] [({:a 1} :only [:a])] :a0 :else :a1)) :a0) (= (let [m {:a 1, :b 2}] (match [m] [({:a 1} :only [:a])] :a0 :else :a1)) :a1))
  actual: false

FAIL in (test-edge-cases-4) (/Users/me/code/work/nbb-logseq/test/core_match_test_runner.cljs:580)
Edge cases 4
expected: (= (let [m {:foo 1, "bar" 2}] (match [m] [{:foo 1, "bar" 2}] :a0 :else :a1)) :a0)
  actual: (not (= :a1 :a0))

FAIL in (test-app-patterns) (/Users/me/code/work/nbb-logseq/test/core_match_test_runner.cljs:902)
Function application patterns
expected: (= (match [m] [{:a (2 :<< inc), :b _}] :match1 [{:a (3 :<< inc), :b _}] :match2 :else :no-match) :match2)
  actual: (not (= :no-match :match2))

FAIL in (test-misc-tickets) (/Users/me/code/work/nbb-logseq/test/core_match_test_runner.cljs:918)
Misc. tickets
expected: (= (let [xqq {:cz 1, :dz 2}] (match [xqq] [{:z a, :zz b}] [:a0 a b] [{:cz a, :dz b}] [:a2 a b] :else [])) [:a2 1 2])
  actual: (not (= [] [:a2 1 2]))

FAIL in (test-misc-tickets) (/Users/me/code/work/nbb-logseq/test/core_match_test_runner.cljs:926)
Misc. tickets
expected: (= (let [xmm {:bz 2}] (match [xmm] [{:az a}] [:a0 a] [{:bz b}] [:a1 b] :else [])) [:a1 2])
  actual: (not (= [] [:a1 2]))

Ran 20 tests containing 91 assertions.
20 failures, 0 errors.

borkdude 2025-08-14T18:35:20.141659Z

This is because (instance? ILookup {}) is failing in nbb.

borkdude 2025-08-14T18:36:15.038809Z

oh no sorry about that, instance? isn't being used in cljs branch

borkdude 2025-08-14T18:36:57.172539Z

I suspect this one fails:

(satisfies? ILookup ~ocr)

borkdude 2025-08-14T18:37:35.312409Z

are you running with a fork of this library?

borkdude 2025-08-14T18:38:19.750979Z

if so, you can try to add a function that checks the satisfies condition like this:

'satisfies-ILookup? #(satifies? ILookup %)
to the namespace config and then substitute that instead

borkdude 2025-08-14T18:39:00.979209Z

then I bet some tests will start working!

2025-08-14T18:44:13.597349Z

I’m not running a fork of abbinare yet. I can try tomorrow. After I add that fn I can add a :org.babashka/nbb conditional to https://github.com/viebel/abbinare/blob/e1e4a3c9d083b495a02c080f86a05aa10275e6d0/src/main/clojure/cljs/core/match.cljc#L1277 . I’d be happily surprised if that’s the only ILookup call I have to change 🤞

borkdude 2025-08-14T18:44:59.788489Z

I think you're confusing things. That source code won't be seen by nbb if you add it via SCI bindings

borkdude 2025-08-14T18:46:07.822689Z

but you can however make this function as part of that lib and then it will work there as well

borkdude 2025-08-14T18:46:44.098059Z

so just something like

(defn satisfies-ILookup? [x] (satisfies? ILookup x))
and then use this function in the macro-expansion I pointed at

borkdude 2025-08-14T18:46:54.425119Z

you then have to change nothing about the SCI bindings I think

borkdude 2025-08-14T18:47:53.295179Z

oh yes, you do need to add that function to the SCI bindings as well of course since it's used in the macro-expansion

borkdude 2025-08-14T18:48:13.618799Z

anyway, in that case the lib will still work with SCI bindings and in regular CLJS

2025-08-14T18:51:23.810209Z

thumbsup_all🤞

2025-08-15T20:07:48.796779Z

Tests all pass! Thanks for the guidance. https://github.com/logseq-cldwalker/abbinare/commit/1d435ea6b3c6269196c6f1b137af78790a8b767c is the abbinare change. https://github.com/logseq/nbb-logseq/tree/add-core-match adds the core.match bindings. One weird quick is that when I pulled in the latest nbb with the updated sci, building nbb-logseq fails with

Error building classpath. Unable to compare versions for org.babashka/sci: {:mvn/version "0.10.46", :deps/manifest :mvn} and {:git/url "", :git/sha "56104c81cb7a3804f8ee84aa64b313dc7143f30e", :deps/manifest :deps, :deps/root "/Users/me/.gitlibs/libs/org.babashka/sci/56104c81cb7a3804f8ee84aa64b313dc7143f30e"}
I wasn’t seeing this before when I depended on https://github.com/babashka/nbb/blob/9119dbe9b5f660cb77d29058b3b762978ee4b939/deps.edn which also depended on a git-based sci. Anyways, I’ll figure it out and look forward to using core.match in nbb next week

borkdude 2025-08-15T20:24:43.806319Z

nice, congrats!

2025-08-13T19:24:58.526419Z

With chat-gpt’s help I was able to get https://github.com/logseq/nbb-logseq/blob/add-core-match/features/core.match/src/nbb/impl/core_match.cljs but it requires https://github.com/viebel/abbinare. Gonna have to poke at it more to see if it fully works

2025-08-13T19:25:42.781629Z

@borkdude I saw you gave some advice on these bindings in https://clojurians.slack.com/archives/C03DPCLCV9N/p1679434303385649?thread_ts=1679424994.838549&cid=C03DPCLCV9N . Is the above approach what you had in mind?

borkdude 2025-08-13T19:37:46.506629Z

it's just a matter of fixing the macro expansion to use fully qualified vars I think?

borkdude 2025-08-13T19:38:38.332469Z

I don't know if you have to fork core.match, but you need to copy the macros from clj to cljs

borkdude 2025-08-13T19:38:56.160279Z

since those are normally executed in JVM Clojure

borkdude 2025-08-13T20:09:07.672509Z

but perhaps that's just what viebel's version does, dunno