Library ports: get hiccup running, verify malli (reader + interop fixes) (#127)

* Reader: #() params survive syntax-quote (auto-gensym names)

#(...) named its synthesized params with bare gensyms, so a #() written inside a
syntax-quote had its params qualified to the current ns by sq-symbol — and a
qualified symbol isn't a valid fn param. hiccup's compiler emits
`(let [sb# ..] (iterate! #(.append sb# %) ..)), which broke with "Unable to
resolve symbol: ns/_NNNN".

Name the params with a trailing # (auto-gensym suffix, like Clojure's p1__N#) so
syntax-quote maps them consistently and leaves them unqualified. Harmless outside
a backtick (just a regular symbol name).

* interop: String/valueOf static + String is a CharSequence

Two interop gaps surfaced bringing up hiccup and malli:
- String/valueOf(Object): hiccup's compiler stringifies attribute values with
  (String/valueOf (or arg "")). Added the static — "null" for nil, else core-str.
- (instance? CharSequence s) returned false for a string; String implements
  CharSequence, and malli's :re validator gates on it before matching, so :re
  schemas always failed. instance-check now answers true for strings.

---------

Co-authored-by: Yogthos <yogthos@gmail.com>
This commit is contained in:
Dmitri Sotnikov 2026-06-15 19:36:13 +00:00 committed by GitHub
parent d223f40c91
commit 61d621521b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 38 additions and 3 deletions

View file

@ -79,6 +79,14 @@
[".charAt" "\\b" "(.charAt \"abc\" 1)"]
[".equalsIgnoreCase" "true" "(.equalsIgnoreCase \"AbC\" \"aBc\")"]
["Long/MAX_VALUE" "true" "(pos? Long/MAX_VALUE)"]
# String/valueOf static (jolt-nkx): hiccup stringifies attribute values with it.
["String/valueOf num" "\"42\"" "(String/valueOf 42)"]
["String/valueOf str" "\"hi\"" "(String/valueOf \"hi\")"]
["String/valueOf kw" "\":k\"" "(String/valueOf :k)"]
["String/valueOf nil" "\"null\"" "(String/valueOf nil)"]
# String implements CharSequence (malli's :re gates on it, jolt-ltwk).
["instance? CharSequence" "true" "(instance? CharSequence \"aaa\")"]
["instance? CharSequence non-str" "false" "(instance? CharSequence 42)"]
["unsupported method throws" :throws "(.frobnicate \"abc\")"])
# java.time shims (jolt-ea7): epoch-ms backed values + a DateTimeFormatter