Skip to content

Commit 02fcf1a

Browse files
authored
Addendum for #214: coerce strings as string nodes (#231)
1 parent d6d7885 commit 02fcf1a

File tree

4 files changed

+56
-50
lines changed

4 files changed

+56
-50
lines changed

src/rewrite_clj/node/coercer.cljc

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,11 @@
2121
[rewrite-clj.node.reader-macro :refer [reader-macro-node var-node]]
2222
[rewrite-clj.node.regex :refer [regex-node pattern-string-for-regex]]
2323
[rewrite-clj.node.seq :refer [vector-node list-node set-node map-node]]
24-
[rewrite-clj.node.stringz]
24+
[rewrite-clj.node.stringz :as stringz]
2525
[rewrite-clj.node.token :refer [token-node]]
2626
[rewrite-clj.node.uneval]
27-
[rewrite-clj.node.whitespace :as ws]]
27+
[rewrite-clj.node.whitespace :as ws]
28+
[rewrite-clj.parser.impl :as pimpl]]
2829
:cljs
2930
[[clojure.string :as string]
3031
[rewrite-clj.node.comment :refer [CommentNode]]
@@ -39,10 +40,12 @@
3940
[rewrite-clj.node.reader-macro :refer [ReaderNode ReaderMacroNode DerefNode reader-macro-node var-node]]
4041
[rewrite-clj.node.regex :refer [RegexNode regex-node pattern-string-for-regex]]
4142
[rewrite-clj.node.seq :refer [SeqNode vector-node list-node set-node map-node]]
42-
[rewrite-clj.node.stringz :refer [StringNode]]
43+
[rewrite-clj.node.stringz :as stringz :refer [StringNode]]
4344
[rewrite-clj.node.token :refer [TokenNode SymbolNode token-node]]
4445
[rewrite-clj.node.uneval :refer [UnevalNode]]
45-
[rewrite-clj.node.whitespace :refer [WhitespaceNode CommaNode NewlineNode] :as ws]]))
46+
[rewrite-clj.node.whitespace :refer [WhitespaceNode CommaNode NewlineNode] :as ws]
47+
[rewrite-clj.parser.impl :as pimpl]])
48+
[rewrite-clj.reader :as reader])
4649
#?(:clj
4750
(:import [rewrite_clj.node.comment CommentNode]
4851
[rewrite_clj.node.fn FnNode]
@@ -135,13 +138,8 @@
135138

136139
(extend-protocol NodeCoerceable
137140
#?(:clj java.lang.String :cljs string)
138-
;; You might we should be coercing to a string-node here.
139-
;; We did this initially for rewrite-clj v1 but found it made more sense to revert to v0 behaviour.
140-
;; The string-node was created to serve the parser and expects the strings to be escaped in a particular way.
141-
;; The token-node has no such expectations and is therefore, currently, what we use for coercing strings.
142-
;; If this makes future internal changes awkward we'll revisit.
143141
(coerce [v]
144-
(token-node v)))
142+
(stringz/string-node (pimpl/read-string-data (reader/string-reader (pr-str v))))))
145143

146144
#?(:clj
147145
(extend-protocol NodeCoerceable

src/rewrite_clj/parser/impl.cljc

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
(ns rewrite-clj.parser.impl
2+
{:no-doc true}
3+
(:require [rewrite-clj.reader :as reader])
4+
#?(:cljs (:import [goog.string StringBuffer])))
5+
6+
#?(:clj (set! *warn-on-reflection* true))
7+
8+
(defn flush-into
9+
"INTERNAL. Flush buffer and add string to the given vector."
10+
[lines ^StringBuffer buf]
11+
(let [s (.toString buf)]
12+
#?(:clj (.setLength buf 0) :cljs (.clear buf))
13+
(conj lines s)))
14+
15+
(defn read-string-data
16+
"INTERNAL."
17+
[#?(:cljs ^not-native reader :default reader)]
18+
(reader/ignore reader)
19+
(let [buf (StringBuffer.)]
20+
(loop [escape? false
21+
lines []]
22+
(if-let [c (reader/next reader)]
23+
(cond (and (not escape?) (identical? c \"))
24+
(flush-into lines buf)
25+
26+
(identical? c \newline)
27+
(recur escape? (flush-into lines buf))
28+
29+
:else
30+
(do
31+
(.append buf c)
32+
(recur (and (not escape?) (identical? c \\)) lines)))
33+
(reader/throw-reader reader "Unexpected EOF while reading string.")))))

src/rewrite_clj/parser/string.cljc

Lines changed: 3 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,42 +1,15 @@
11
(ns ^:no-doc rewrite-clj.parser.string
22
(:require [clojure.string :as string]
33
[rewrite-clj.node.stringz :as nstring]
4-
[rewrite-clj.reader :as reader])
5-
#?(:cljs (:import [goog.string StringBuffer])))
4+
[rewrite-clj.parser.impl :as pimpl]))
65

76
#?(:clj (set! *warn-on-reflection* true))
87

9-
(defn- flush-into
10-
"Flush buffer and add string to the given vector."
11-
[lines ^StringBuffer buf]
12-
(let [s (.toString buf)]
13-
#?(:clj (.setLength buf 0) :cljs (.clear buf))
14-
(conj lines s)))
15-
16-
(defn- read-string-data
17-
[#?(:cljs ^not-native reader :default reader)]
18-
(reader/ignore reader)
19-
(let [buf (StringBuffer.)]
20-
(loop [escape? false
21-
lines []]
22-
(if-let [c (reader/next reader)]
23-
(cond (and (not escape?) (identical? c \"))
24-
(flush-into lines buf)
25-
26-
(identical? c \newline)
27-
(recur escape? (flush-into lines buf))
28-
29-
:else
30-
(do
31-
(.append buf c)
32-
(recur (and (not escape?) (identical? c \\)) lines)))
33-
(reader/throw-reader reader "Unexpected EOF while reading string.")))))
34-
358
(defn parse-string
369
[#?(:cljs ^not-native reader :default reader)]
37-
(nstring/string-node (read-string-data reader)))
10+
(nstring/string-node (pimpl/read-string-data reader)))
3811

3912
(defn parse-regex
4013
[#?(:cljs ^not-native reader :default reader)]
41-
(let [h (read-string-data reader)]
14+
(let [h (pimpl/read-string-data reader)]
4215
(string/join "\n" h)))

test/rewrite_clj/node/coercer_test.cljc

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -41,15 +41,15 @@
4141
::1.5.1 :token :keyword
4242
:namespace/keyword :token :keyword
4343

44-
"" :token :token
45-
"hello, over there!" :token :token
46-
"multi\nline" :token :token
47-
" " :token :token
48-
"\n" :token :token
49-
"\n\n" :token :token
50-
"," :token :token
51-
"inner\"quote" :token :token
52-
"\\s+" :token :token
44+
"" :token :string
45+
"hello, over there!" :token :string
46+
"multi\nline" :token :string
47+
" " :token :string
48+
"\n" :token :string
49+
"\n\n" :token :string
50+
"," :token :string
51+
"inner\"quote" :token :string
52+
"\\s+" :token :string
5353

5454
;; seqs
5555
[] :vector :seq
@@ -69,7 +69,9 @@
6969
n (node/coerce s)]
7070
(is (= s (node/sexpr n)))))
7171
(testing "coerce string roundtrip"
72-
(is (= "\"hey \\\" man\"" (-> "hey \" man" node/coerce node/string)))))
72+
(is (= "\"hey \\\" man\"" (-> "hey \" man" node/coerce node/string))))
73+
(testing "coerce string equals parsed string"
74+
(is (= (p/parse-string "\"hello\"") (node/coerce "hello")))))
7375

7476
(deftest
7577
t-quoted-list-reader-location-metadata-elided

0 commit comments

Comments
 (0)