\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.
49 lines
2.9 KiB
Text
49 lines
2.9 KiB
Text
# Specification: regular expressions — #"…" literals and the re-* fns.
|
|
# (Whole area previously unspecced; some cases adapted from jank reader-macro/regex.)
|
|
(use ../support/harness)
|
|
|
|
(defspec "regex / literals & predicate"
|
|
["regex? literal" "true" "(regex? #\"\\d+\")"]
|
|
["regex? non-regex" "false" "(regex? \"\\d+\")"]
|
|
["escaped digits" "\"42\"" "(re-find #\"\\d+\" \"x42y\")"]
|
|
["escaped ws/non-ws" "\"x a\"" "(re-find #\"\\S\\s\\S\" \"x a b y\")"])
|
|
|
|
(defspec "regex / re-find"
|
|
["match" "\"123\"" "(re-find #\"\\d+\" \"abc123def\")"]
|
|
["no match nil" "nil" "(re-find #\"\\d+\" \"abc\")"]
|
|
["with groups" "[\"a1\" \"a\" \"1\"]" "(re-find #\"([a-z])(\\d)\" \"--a1--\")"]
|
|
["first match only" "\"1\"" "(re-find #\"\\d\" \"1 2 3\")"])
|
|
|
|
(defspec "regex / re-matches"
|
|
["full match" "\"123\"" "(re-matches #\"\\d+\" \"123\")"]
|
|
["partial = nil" "nil" "(re-matches #\"\\d+\" \"123abc\")"]
|
|
["groups" "[\"12\" \"1\" \"2\"]" "(re-matches #\"(\\d)(\\d)\" \"12\")"]
|
|
["no match nil" "nil" "(re-matches #\"x+\" \"yyy\")"])
|
|
|
|
(defspec "regex / re-seq"
|
|
["all matches" "(quote (\"1\" \"22\" \"333\"))" "(re-seq #\"\\d+\" \"a1b22c333\")"]
|
|
["empty when none" "nil" "(seq (re-seq #\"z\" \"abc\"))"]
|
|
["words" "(quote (\"foo\" \"bar\"))" "(re-seq #\"\\w+\" \"foo bar\")"])
|
|
|
|
(defspec "regex / re-pattern & string ops"
|
|
["re-pattern build" "\"hi\"" "(re-find (re-pattern \"\\\\w+\") \"hi!\")"]
|
|
["re-pattern is regex?" "true" "(regex? (re-pattern \"a\"))"]
|
|
["split on regex" "[\"a\" \"b\" \"c\"]" "(do (require '[clojure.string :as s]) (s/split \"a1b2c\" #\"\\d\"))"]
|
|
["replace regex" "\"X-X\"" "(do (require '[clojure.string :as s]) (s/replace \"a-b\" #\"[a-z]\" \"X\"))"]
|
|
["replace $1" "\"[a][b]\"" "(do (require '[clojure.string :as s]) (s/replace \"ab\" #\"([a-z])\" \"[$1]\"))"])
|
|
|
|
# Unicode property classes (jolt-xlp), byte-PEG approximation: ASCII exact,
|
|
# any high byte (inside a UTF-8 sequence) counts as a LETTER for \p{L}.
|
|
# Acceptance target was cuerdas (kebab/snake/capital now pass conformance).
|
|
(defspec "regex / \\p property classes"
|
|
["p{L} ascii" "\"hello\"" `(re-matches #"^\p{L}+$" "hello")`]
|
|
["p{L} utf-8" "true" `(boolean (re-matches #"^\p{L}+$" "héllo"))`]
|
|
["p{L} rejects digits" "false" `(boolean (re-matches #"^\p{L}+$" "ab1"))`]
|
|
["p{N}" "(quote (\"12\" \"345\"))" `(re-seq #"\p{N}+" "a12b345")`]
|
|
["P{N} negation" "\"abc\"" `(re-matches #"^\P{N}+$" "abc")`]
|
|
["inside class" "\"a-1_b\"" `(re-matches #"^[\p{N}\p{L}_-]+$" "a-1_b")`]
|
|
["p{Lu}/p{Ll}" "\"aB\"" `(re-matches #"^\p{Ll}\p{Lu}$" "aB")`]
|
|
["p{Z} space" "\" \"" `(re-matches #"(?u)^[\s\p{Z}]+$" " ")`]
|
|
["p{Ps}/p{Pe}" "\"(x)\"" `(re-matches #"^\p{Ps}x\p{Pe}$" "(x)")`]
|
|
["(?u) accepted" "\"hi\"" `(re-matches #"(?u)^hi$" "hi")`]
|
|
["unknown class throws" :throws `(re-pattern "\p{Greek}")`])
|