(defn
read
"Reads the first object from an IPushbackReader.\n Returns the object read. If EOF, throws if eof-error? is true otherwise returns eof.\n If no reader is provided, *in* will be used.\n\n Reads data in the edn format (subset of Clojure data):\n http://edn-format.org\n\n clojure.tools.reader.edn/read doesn't depend on dynamic Vars, all configuration\n is done by passing an opt map.\n\n opts is a map that can include the following keys:\n :eof - value to return on end-of-file. When not supplied, eof throws an exception.\n :readers - a map of tag symbols to data-reader functions to be considered before default-data-readers.\n When not supplied, only the default-data-readers will be used.\n :default - A function of two args, that will, if present and no reader is found for a tag,\n be called with the tag and the value."
([reader] (read {} reader))
([{:keys [eof], :as opts} reader]
(let
[eof-error? (not (contains? opts :eof))]
(read reader eof-error? eof opts)))
([reader eof-error? eof opts]
(try
(loop
[]
(let
[ch (read-char reader)]
(cond
(whitespace? ch)
(recur)
(nil? ch)
(if eof-error? (err/throw-eof-error reader nil) eof)
(number-literal? reader ch)
(read-number reader ch opts)
:else
(let
[f (macros ch)]
(if
f
(let
[res (f reader ch opts)]
(if (identical? res reader) (recur) res))
(read-symbol reader ch))))))
(catch
js/Error
e
(if
(ex-info? e)
(let
[d (ex-data e)]
(if
(= :reader-exception (:type d))
(throw e)
(throw
(ex-info
(.-message e)
(merge
{:type :reader-exception}
d
(if
(indexing-reader? reader)
{:line (get-line-number reader),
:column (get-column-number reader),
:file (get-file-name reader)}))
e))))
(throw
(ex-info
(.-message e)
(merge
{:type :reader-exception}
(if
(indexing-reader? reader)
{:line (get-line-number reader),
:column (get-column-number reader),
:file (get-file-name reader)}))
e)))))))