feat: read regex literals
e5a8bce parent: a59f466 modified
src/reader.nim +7 -0 | @@ -130,6 +130,13 @@ proc readForm(r: var Reader): Value = | ||
| 130 | 130 | if r.peek2 == '{': |
| 131 | 131 | discard r.advance; discard r.advance |
| 132 | 132 | return mkSet(r.readDelimited('}')) |
| 133 | + if r.peek2 == '"': | |
| 134 | + # A Clojure regex literal carries its pattern source at read time. The | |
| 135 | + # runtime's regular-expression operations accept that source string, so | |
| 136 | + # preserve the usual string escaping while avoiding a JVM-only Pattern | |
| 137 | + # object in the portable value representation. | |
| 138 | + discard r.advance | |
| 139 | + return r.readString | |
| 133 | 140 | if r.peek2 == '_': |
| 134 | 141 | discard r.advance; discard r.advance |
| 135 | 142 | discard r.readForm |
| @@ -130,6 +130,13 @@ proc readForm(r: var Reader): Value = | |||
| 130 | if r.peek2 == '{': | 130 | if r.peek2 == '{': |
| 131 | discard r.advance; discard r.advance | 131 | discard r.advance; discard r.advance |
| 132 | return mkSet(r.readDelimited('}')) | 132 | return mkSet(r.readDelimited('}')) |
| 133 | + if r.peek2 == '"': | ||
| 134 | + # A Clojure regex literal carries its pattern source at read time. The | ||
| 135 | + # runtime's regular-expression operations accept that source string, so | ||
| 136 | + # preserve the usual string escaping while avoiding a JVM-only Pattern | ||
| 137 | + # object in the portable value representation. | ||
| 138 | + discard r.advance | ||
| 139 | + return r.readString | ||
| 133 | if r.peek2 == '_': | 140 | if r.peek2 == '_': |
| 134 | discard r.advance; discard r.advance | 141 | discard r.advance; discard r.advance |
| 135 | discard r.readForm | 142 | discard r.readForm |
modified
tests/test_namespaces.nim +6 -0 | @@ -22,6 +22,12 @@ proc rejects(src, message: string, roots: seq[string] = @[]) = | ||
| 22 | 22 | check rejected |
| 23 | 23 | |
| 24 | 24 | suite "static namespace resolution": |
| 25 | + test "regex literals preserve their pattern source": | |
| 26 | + let forms = readAll("#\"(?i)^did:[a-z0-9]+:\"") | |
| 27 | + check forms.len == 1 | |
| 28 | + check forms[0].kind == kStr | |
| 29 | + check forms[0].s == "(?i)^did:[a-z0-9]+:" | |
| 30 | + | |
| 25 | 31 | test "definitions resolve sequentially, including core shadowing": |
| 26 | 32 | checkForms("(inc 1) (def inc (fn [x] x)) (inc 2)", |
| 27 | 33 | "(clojure.core/inc 1) (def user/inc (fn [x] x)) (user/inc 2)") |
| @@ -22,6 +22,12 @@ proc rejects(src, message: string, roots: seq[string] = @[]) = | |||
| 22 | check rejected | 22 | check rejected |
| 23 | 23 | ||
| 24 | suite "static namespace resolution": | 24 | suite "static namespace resolution": |
| 25 | + test "regex literals preserve their pattern source": | ||
| 26 | + let forms = readAll("#\"(?i)^did:[a-z0-9]+:\"") | ||
| 27 | + check forms.len == 1 | ||
| 28 | + check forms[0].kind == kStr | ||
| 29 | + check forms[0].s == "(?i)^did:[a-z0-9]+:" | ||
| 30 | + | ||
| 25 | test "definitions resolve sequentially, including core shadowing": | 31 | test "definitions resolve sequentially, including core shadowing": |
| 26 | checkForms("(inc 1) (def inc (fn [x] x)) (inc 2)", | 32 | checkForms("(inc 1) (def inc (fn [x] x)) (inc 2)", |
| 27 | "(clojure.core/inc 1) (def user/inc (fn [x] x)) (user/inc 2)") | 33 | "(clojure.core/inc 1) (def user/inc (fn [x] x)) (user/inc 2)") |