\p{L}/\p{Lu}/\p{Ll}/\p{N}/\p{Z}/\p{Ps}/\p{Pe} (+\P negation) land in
both escape positions of the regex compiler, mapped onto the byte PEGs:
ASCII exact, any high byte (inside a UTF-8 sequence) counts as a LETTER —
so ^\p{L}+$ accepts UTF-8 words while \p{N}/\p{Z} stay ASCII. (?u) was
already a tolerated no-op flag. Unknown property names error at compile.
Chasing the acceptance target (cuerdas via deps-conformance) pulled in the
rest of its clj-compat chain, each a real gap:
- the deps-conformance harness reads libraries under clj-compat reader
features (deps are clj/cljc by definition — without :clj, cuerdas's
#?(:clj (instance? Pattern x)) branches resolved to NIL bodies)
- instance? knows Pattern/java.util.regex.Pattern (regex values) and
Character (cuerdas's rx/regexp? gate on split)
- the java.lang.String method surface: .toLowerCase/.toUpperCase/.trim/
.indexOf(-1 on miss)/.lastIndexOf/.substring/.charAt/.startsWith/
.endsWith/.contains/.replace/.equalsIgnoreCase/... — ASCII case mapping,
unknown methods error (the old path silently returned nil)
- the (.method obj args) SUGAR now desugars to (. obj method args) in the
interpreter — it was never implemented (bare .method heads resolved as
vars, hence 'Cannot call nil')
- Long/MAX_VALUE / MIN_VALUE statics (f64 approximations)
deps-conformance: medley ok, cuerdas ok (was check-error); dependency now
loads its clj branches and fails only on its single-segment ns resolution.
30 new spec rows (11 regex, 19 interop). Gate exit 0.
63 lines
3.8 KiB
Text
63 lines
3.8 KiB
Text
# Specification: host (Janet) interop — the `.` forms and jolt.interop.
|
|
(use ../support/harness)
|
|
|
|
(defspec "interop / dot forms"
|
|
["method call" "\"v=41\""
|
|
"(. {:value 41 :describe (fn [self] (str \"v=\" (:value self)))} describe)"]
|
|
["method with args" "\"Hello Alice\""
|
|
"(. {:greet (fn [self n] (str \"Hello \" n))} greet \"Alice\")"]
|
|
["field access .-" "41" "(.-value {:value 41})"]
|
|
["dot field keyword" "41" "(. {:value 41} :value)"])
|
|
|
|
# The `janet` namespace segment is the explicit Janet-stdlib bridge added for
|
|
# the networking layer (and used by jolt.nrepl). `janet/<name>` resolves a Janet
|
|
# root binding; `janet.<module>/<name>` resolves a module binding. The boundary
|
|
# is explicit so it's visible where host semantics take over.
|
|
(defspec "interop / janet bridge"
|
|
["root builtin janet/<name>" "\"123\"" "(janet/string 1 2 3)"]
|
|
["root builtin janet/type" ":string" "(janet/type \"x\")"]
|
|
["module fn janet.<mod>/<name>" "4" "(janet.math/sqrt 16)"]
|
|
["janet.string module fn" "\"HI\"" "(janet.string/ascii-upper \"hi\")"]
|
|
["janet.os/clock is a number" "true" "(number? (janet.os/clock))"]
|
|
# crossing the boundary uses Janet representations: a Jolt vector is a table
|
|
["jolt vector crosses as a janet table" ":table" "(janet/type [1 2])"]
|
|
# interop is explicit-only: an unprefixed Janet module is not auto-exposed
|
|
["unprefixed janet module not exposed" :throws "net/server"]
|
|
["unknown janet symbol throws" :throws "(janet.os/definitely-not-a-real-fn)"])
|
|
|
|
(defspec "interop / jolt.interop"
|
|
["janet-type quoted list" ":array" "(do (require (quote [jolt.interop :as j])) (j/janet-type (quote (1 2))))"]
|
|
["janet-type list" ":array" "(do (require (quote [jolt.interop :as j])) (j/janet-type (list 1 2)))"]
|
|
["janet-type string" ":string" "(do (require (quote [jolt.interop :as j])) (j/janet-type \"x\"))"]
|
|
["janet-type number" ":number" "(do (require (quote [jolt.interop :as j])) (j/janet-type 1))"]
|
|
["janet-type keyword" ":keyword" "(do (require (quote [jolt.interop :as j])) (j/janet-type :a))"])
|
|
|
|
(defspec "interop / arrays (aget/aset/alength)"
|
|
["alength" "3" "(alength (object-array [1 2 3]))"]
|
|
["aget" "20" "(aget (object-array [10 20 30]) 1)"]
|
|
["aset returns val" "9" "(aset (object-array [1 2 3]) 1 9)"]
|
|
["aset mutates" "[7 2 3]" "(let [a (object-array [1 2 3])] (aset a 0 7) (vec a))"]
|
|
["aget 2d" "4" "(aget (to-array-2d [[1 2] [3 4]]) 1 1)"])
|
|
|
|
# java.lang.String surface + .method sugar (clj-compat: what portable cljc
|
|
# libraries call — landed for the cuerdas acceptance run). ASCII case mapping.
|
|
(defspec "interop / String methods"
|
|
[".toLowerCase" "\"hi\"" "(.toLowerCase \"HI\")"]
|
|
[".toUpperCase" "\"HI\"" "(.toUpperCase \"hi\")"]
|
|
["dot-form" "\"hi\"" "(. \"HI\" toLowerCase)"]
|
|
[".trim" "\"x\"" "(.trim \" x \")"]
|
|
[".length" "3" "(.length \"abc\")"]
|
|
[".isEmpty" "[true false]" "[(.isEmpty \"\") (.isEmpty \"a\")]"]
|
|
[".indexOf hit" "1" "(.indexOf \"abc\" \"b\")"]
|
|
[".indexOf miss is -1" "-1" "(.indexOf \"abc\" \"z\")"]
|
|
[".lastIndexOf" "3" "(.lastIndexOf \"abab\" \"b\")"]
|
|
[".substring" "\"bc\"" "(.substring \"abc\" 1)"]
|
|
[".substring end" "\"b\"" "(.substring \"abc\" 1 2)"]
|
|
[".startsWith" "true" "(.startsWith \"abc\" \"ab\")"]
|
|
[".endsWith" "true" "(.endsWith \"abc\" \"bc\")"]
|
|
[".contains" "true" "(.contains \"abc\" \"b\")"]
|
|
[".replace" "\"axc\"" "(.replace \"abc\" \"b\" \"x\")"]
|
|
[".charAt" "\\b" "(.charAt \"abc\" 1)"]
|
|
[".equalsIgnoreCase" "true" "(.equalsIgnoreCase \"AbC\" \"aBc\")"]
|
|
["Long/MAX_VALUE" "true" "(pos? Long/MAX_VALUE)"]
|
|
["unsupported method throws" :throws "(.frobnicate \"abc\")"])
|