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:
parent
d223f40c91
commit
61d621521b
6 changed files with 38 additions and 3 deletions
|
|
@ -125,6 +125,11 @@ checks → UNVERIFIED (rows to add).
|
||||||
nested form including vector, map and set literals — `#(assoc {} :k %)`,
|
nested form including vector, map and set literals — `#(assoc {} :k %)`,
|
||||||
`#(hash-set % %2)` and `#(get {:t %} :t)` all see their `%`s. (A reader that
|
`#(hash-set % %2)` and `#(get {:t %} :t)` all see their `%`s. (A reader that
|
||||||
scanned only call forms would miscompile `#(identity {:text %})` as a 0-arg fn.)
|
scanned only call forms would miscompile `#(identity {:text %})` as a 0-arg fn.)
|
||||||
|
- The synthesized parameters are auto-gensyms (their names carry the `#` suffix,
|
||||||
|
like Clojure's `p1__N#`), so an `#()` written inside a syntax-quote survives:
|
||||||
|
the params are mapped consistently and left unqualified rather than being
|
||||||
|
qualified to the current namespace (a qualified symbol is not a valid
|
||||||
|
parameter). E.g. `` `(map #(inc %) xs) `` expands correctly inside a macro.
|
||||||
- `#()` literals MUST NOT nest.
|
- `#()` literals MUST NOT nest.
|
||||||
|
|
||||||
```clojure
|
```clojure
|
||||||
|
|
|
||||||
|
|
@ -707,6 +707,10 @@
|
||||||
"Double" (number? val)
|
"Double" (number? val)
|
||||||
"String" (string? val)
|
"String" (string? val)
|
||||||
"java.lang.String" (string? val)
|
"java.lang.String" (string? val)
|
||||||
|
# String implements CharSequence — malli's :re validator gates on
|
||||||
|
# (instance? CharSequence x) before matching (jolt-ltwk).
|
||||||
|
"CharSequence" (string? val)
|
||||||
|
"java.lang.CharSequence" (string? val)
|
||||||
"Boolean" (or (= true val) (= false val))
|
"Boolean" (or (= true val) (= false val))
|
||||||
"Keyword" (keyword? val)
|
"Keyword" (keyword? val)
|
||||||
# regex patterns (cuerdas-style (instance? Pattern x) checks)
|
# regex patterns (cuerdas-style (instance? Pattern x) checks)
|
||||||
|
|
|
||||||
|
|
@ -288,6 +288,12 @@
|
||||||
# (String. bytes) / (String. bytes charset): UTF-8 bytes to string.
|
# (String. bytes) / (String. bytes charset): UTF-8 bytes to string.
|
||||||
(each nm ["String" "java.lang.String"]
|
(each nm ["String" "java.lang.String"]
|
||||||
(register-class-ctor! nm (fn [x &opt charset] (string x))))
|
(register-class-ctor! nm (fn [x &opt charset] (string x))))
|
||||||
|
# String statics. valueOf(Object) yields "null" for nil, else toString —
|
||||||
|
# hiccup's compiler emits (String/valueOf (or arg "")) to stringify attribute
|
||||||
|
# values; core-str gives jolt's str semantics for keywords/numbers/etc.
|
||||||
|
(each nm ["String" "java.lang.String"]
|
||||||
|
(register-class-statics! nm
|
||||||
|
@{"valueOf" (fn [x &opt off cnt] (if (nil? x) "null" (core-str x)))}))
|
||||||
# java.net.URL: enough for selmer's template cache — file: URLs only.
|
# java.net.URL: enough for selmer's template cache — file: URLs only.
|
||||||
# A protocol-less spec throws (selmer catches MalformedURLException and
|
# A protocol-less spec throws (selmer catches MalformedURLException and
|
||||||
# prepends file:///), and getPath hands back a stat-able filesystem path.
|
# prepends file:///), and getPath hands back a stat-able filesystem path.
|
||||||
|
|
|
||||||
|
|
@ -448,10 +448,15 @@
|
||||||
nil))
|
nil))
|
||||||
(scan-pct form)
|
(scan-pct form)
|
||||||
# One canonical gensym per slot 1..max-n (placeholders for unused), plus rest.
|
# One canonical gensym per slot 1..max-n (placeholders for unused), plus rest.
|
||||||
|
# Param names carry a trailing `#` (auto-gensym suffix, matching Clojure's
|
||||||
|
# `p1__N#`) so a #() written inside a syntax-quote survives: sq-symbol treats
|
||||||
|
# `#`-suffixed names as auto-gensyms (mapped consistently, left unqualified)
|
||||||
|
# rather than qualifying them to the current ns — a qualified symbol is not a
|
||||||
|
# valid fn param. Harmless outside a backtick (just a regular symbol name).
|
||||||
(def slot-syms @{})
|
(def slot-syms @{})
|
||||||
(var i 1)
|
(var i 1)
|
||||||
(while (<= i max-n) (put slot-syms i (sym (string (gensym)))) (++ i))
|
(while (<= i max-n) (put slot-syms i (sym (string (gensym) "#"))) (++ i))
|
||||||
(def rest-sym (if has-rest (sym (string (gensym))) nil))
|
(def rest-sym (if has-rest (sym (string (gensym) "#")) nil))
|
||||||
# Pass 2: replace each %-symbol with its slot's gensym.
|
# Pass 2: replace each %-symbol with its slot's gensym.
|
||||||
(defn- replace-pct [f]
|
(defn- replace-pct [f]
|
||||||
(cond
|
(cond
|
||||||
|
|
|
||||||
|
|
@ -79,6 +79,14 @@
|
||||||
[".charAt" "\\b" "(.charAt \"abc\" 1)"]
|
[".charAt" "\\b" "(.charAt \"abc\" 1)"]
|
||||||
[".equalsIgnoreCase" "true" "(.equalsIgnoreCase \"AbC\" \"aBc\")"]
|
[".equalsIgnoreCase" "true" "(.equalsIgnoreCase \"AbC\" \"aBc\")"]
|
||||||
["Long/MAX_VALUE" "true" "(pos? Long/MAX_VALUE)"]
|
["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\")"])
|
["unsupported method throws" :throws "(.frobnicate \"abc\")"])
|
||||||
|
|
||||||
# java.time shims (jolt-ea7): epoch-ms backed values + a DateTimeFormatter
|
# java.time shims (jolt-ea7): epoch-ms backed values + a DateTimeFormatter
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,14 @@
|
||||||
["gensym unique" "false"
|
["gensym unique" "false"
|
||||||
"(= (gensym) (gensym))"]
|
"(= (gensym) (gensym))"]
|
||||||
["gensym# in template" "true"
|
["gensym# in template" "true"
|
||||||
"(do (defmacro m [] `(let [x# 1] x#)) (= 1 (m)))"])
|
"(do (defmacro m [] `(let [x# 1] x#)) (= 1 (m)))"]
|
||||||
|
# An #() lambda written inside a syntax-quote: its generated params must not be
|
||||||
|
# qualified to the ns (a qualified symbol is not a valid param). hiccup's
|
||||||
|
# compiler emits `(let [sb# ..] (run! #(.append sb# %) ..)) (jolt-nkx).
|
||||||
|
["#() inside syntax-quote" "[2 4 6]"
|
||||||
|
"(do (defmacro m [] `(mapv #(* % 2) [1 2 3])) (m))"]
|
||||||
|
["#() + auto-gensym share in template" "\"ab\""
|
||||||
|
"(do (defmacro m [] `(let [sb# (StringBuilder.)] (mapv #(.append sb# %) [\"a\" \"b\"]) (.toString sb#))) (m))"])
|
||||||
|
|
||||||
# Core macros ported from Janet to the Clojure overlay (jolt-1j0 phase 3,
|
# Core macros ported from Janet to the Clojure overlay (jolt-1j0 phase 3,
|
||||||
# jolt-core/clojure/core/30-macros.clj).
|
# jolt-core/clojure/core/30-macros.clj).
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue