Skip to content

Commit 286a8f3

Browse files
author
Yannick Scherer
committed
Parse/Print multi-line Strings.
1 parent 1440172 commit 286a8f3

File tree

2 files changed

+58
-8
lines changed

2 files changed

+58
-8
lines changed

src/rewrite_clj/parser/core.clj

Lines changed: 38 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
\( :list \[ :vector \{ :map
1414
\} :unmatched \] :unmatched \) :unmatched
1515
\~ :unquote \' :quote \` :syntax-quote
16-
\; :comment \@ :deref})
16+
\; :comment \@ :deref \" :string})
1717

1818
(defmulti parse-next
1919
"Parse the next element from the given reader. Dispatch is done using the first
@@ -74,13 +74,15 @@
7474
opening quotation mark."
7575
[reader]
7676
(ignore reader)
77-
(loop [rx []
78-
escape? false]
79-
(if-let [c (r/read-char reader)]
80-
(cond (and (not escape?) (= c \")) (token :token (re-pattern (apply str rx)))
81-
(= c \\) (recur (conj rx c) true)
82-
:else (recur (conj rx c) false))
83-
(throw-reader reader "Unexpected EOF while reading regular expression."))))
77+
(let [buf (StringBuffer.)]
78+
(loop [escape? false]
79+
(if-let [c (r/read-char reader)]
80+
(if (and (not escape?) (= c \"))
81+
(token :token (re-pattern (.toString buf)))
82+
(do
83+
(.append buf c)
84+
(recur (and (not escape?) (= c \\)))))
85+
(throw-reader reader "Unexpected EOF while reading regular expression.")))))
8486

8587
(defn- parse-reader-macro
8688
"Parse token starting with '#'."
@@ -107,6 +109,33 @@
107109
(r/unread reader \~)
108110
(parse-prefixed :unquote reader delim)))))
109111

112+
(defn- parse-string-contents
113+
"Use EDN reader to transform the literal representation of a Clojure string
114+
to its Clojure representation, e.g. \"a\\\\nb\" -> \"a\\nb\"."
115+
[s]
116+
(edn/read-string (str "\"" s "\"")))
117+
118+
(defn- parse-string
119+
"Parse string. Produces `:token` for single-line strings and `:multi-line` for
120+
those spanning multiple lines."
121+
[reader delim]
122+
(ignore reader)
123+
(let [buf (StringBuffer.)]
124+
(loop [escape? false
125+
result-type :token
126+
results []]
127+
(if-let [c (r/read-char reader)]
128+
(cond (and (not escape?) (= c \")) (->> (conj results (.toString buf))
129+
(map parse-string-contents)
130+
(apply token result-type))
131+
(= c \newline) (let [s (.toString buf)]
132+
(.setLength buf 0)
133+
(recur escape? :multi-line (conj results s)))
134+
:else (do
135+
(.append buf c)
136+
(recur (and (not escape?) (= c \\)) result-type results)))
137+
(throw-reader reader "Unexpected EOF while reading regular expression.")))))
138+
110139
;; ## Register Parsers
111140

112141
(defmethod parse-next nil [reader delim]
@@ -130,3 +159,4 @@
130159
(defmethod parse-next :unquote [reader delim] (parse-unquote reader delim))
131160
(defmethod parse-next :quote [reader delim] (parse-prefixed :quote reader delim))
132161
(defmethod parse-next :syntax-quote [reader d] (parse-prefixed :syntax-quote reader d))
162+
(defmethod parse-next :string [reader delim] (parse-string reader delim))

src/rewrite_clj/printer.clj

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,20 @@
4040
(defmethod print-edn :unquote [data] (print-children "~" data))
4141
(defmethod print-edn :unquote-splicing [data] (print-children "~@" data))
4242

43+
(letfn [(print-line [^String s]
44+
(let [^String s (pr-str s)]
45+
(print (.substring s 1 (dec (count s))))))]
46+
(defmethod print-edn :multi-line [data]
47+
(print "\"")
48+
(loop [sq (rest data)]
49+
(if-not (= (count sq) 1)
50+
(let [[s0 & rst] sq]
51+
(print-line s0)
52+
(println)
53+
(recur rst))
54+
(print-line (first sq))))
55+
(print "\"")))
56+
4357
;; ## Others
4458

4559
(defn ->string
@@ -79,3 +93,9 @@
7993
(defmethod estimate-length :syntax-quote [data] (inc (estimate-children-length data)))
8094
(defmethod estimate-length :unquote [data] (inc (estimate-children-length data)))
8195
(defmethod estimate-length :unquote-splicing [data] (+ 2 (estimate-children-length data)))
96+
(defmethod estimate-length :multi-line [data]
97+
(let [parts (rest data)]
98+
(+ 2 (count parts)
99+
(reduce
100+
(fn [sum p]
101+
(+ sum (count p))) 0 parts))))

0 commit comments

Comments
 (0)