   "Creates a StringPushbackReader from a given string"
   (StringPushbackReader. (atom s)))
 
-;; Helper functions
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; predicates
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
 (defn- whitespace?
   "Checks whether a given character is whitespace"

(deftype StringPushbackReader [state]
  PushbackReader
  (read-char [reader] (let [original @state]
                      (reset! state (subs 1 original))
                      (first original)))
  (unread [reader ch] (reset! state (str ch @state))))


      reader
      (recur reader))))

(defn read-past
  "Read until first character that doesn't match pred, returning
   char."
  [pred rdr]
  (loop [ch (read-char rdr)]
    (if (pred ch)
      (recur (read-char rdr))
      ch)))

(defn read-delimited-list
  [delim rdr recursive?]
  (loop [a ()]
    (let [ch (read-past whitespace? rdr)]
      (when-not ch (throw "EOF"))
      (if (= delim ch)
        a
        (if-let [macrofn (get rmacros ch)]
          (let [mret (macrofn rdr ch)]
            (recur (if (= mret rdr) a (conj a mret))))
          (do
            (unread rdr ch)
            (let [o (read rdr true nil recursive?)]
              (recur (if (= o rdr) a (conj a o))))))))))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; data structure readers
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

(defn read-list
  [rdr _]
  (read-delimited-list ")" rdr true))

(defn read-vector
  [rdr _]
  (vec (read-delimited-list "]" rdr true)))

(defn read-map
  [rdr _]
  (let [l (read-delimited-list "}" rdr true)]
    (when (odd? (count l))
      (throw "Map literal must contain an even number of forms"))
    (apply hash-map l)))

(defn read-set
  [rdr _]
  (set (read-delimited-list "}" rdr true)))

(def rmacros
  {"{" read-set})

(defn read-number
  [reader initch])

(defn read-string
  [reader initch])

(defn read-symbol
  [reader initch is-recursive])

(defn read
  "Reads the first object from a PushbackReader. Returns the object read.
Returns sentinel if the reader did not contain any forms."
  [reader eof-is-error sentinel is-recursive]
  (let [ch (read-char reader)] 
    (cond
     (nil? ch) sentinel
     (whitespace? ch) (recur reader eof-is-error sentinel is-recursive)
     (comment-prefix? ch) (recur (skip-line reader) eof-is-error sentinel is-recursive)
     (number-literal? reader) (read-number reader ch)
     (string-prefix? ch) (read-string reader ch)
     (list-prefix? ch) (read-list reader ch)
     (vector-prefix? ch) (read-vector reader ch)
     (map-prefix? ch) (read-map reader ch)
     :default (read-symbol reader ch))))


(defn read-all
  "Reads a lazy sequence of objects from a reader."
  [reader]
  (lazy-seq (cons (read reader) (read-all reader))))
