From 60980df7674687971caa8725cdd633ed5db4bf3d Mon Sep 17 00:00:00 2001 From: Yogthos Date: Mon, 15 Jun 2026 15:15:32 -0400 Subject: [PATCH] interop: String/valueOf static + String is a CharSequence MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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. --- src/jolt/eval_runtime.janet | 4 ++++ src/jolt/interop/host_io.janet | 6 ++++++ test/spec/host-interop-spec.janet | 8 ++++++++ 3 files changed, 18 insertions(+) diff --git a/src/jolt/eval_runtime.janet b/src/jolt/eval_runtime.janet index 0e20298..07b6b06 100644 --- a/src/jolt/eval_runtime.janet +++ b/src/jolt/eval_runtime.janet @@ -707,6 +707,10 @@ "Double" (number? val) "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)) "Keyword" (keyword? val) # regex patterns (cuerdas-style (instance? Pattern x) checks) diff --git a/src/jolt/interop/host_io.janet b/src/jolt/interop/host_io.janet index 4dc689b..4186233 100644 --- a/src/jolt/interop/host_io.janet +++ b/src/jolt/interop/host_io.janet @@ -288,6 +288,12 @@ # (String. bytes) / (String. bytes charset): UTF-8 bytes to string. (each nm ["String" "java.lang.String"] (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. # A protocol-less spec throws (selmer catches MalformedURLException and # prepends file:///), and getPath hands back a stat-able filesystem path. diff --git a/test/spec/host-interop-spec.janet b/test/spec/host-interop-spec.janet index 356e4df..ca7ed39 100644 --- a/test/spec/host-interop-spec.janet +++ b/test/spec/host-interop-spec.janet @@ -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