        \# read-dispatch
        })
 
+;; omitted by design: var reader, eval reader
 (def dispatch-macros
-  {"{" read-set})
+  {"{" read-set
+   "<" (throwing-reader "Unreadable form")
+   "\"" read-regex
+   "!" read-comment
+   "_" read-discard})
 
 (defn read
   "Reads the first object from a PushbackReader. Returns the object read.
-Returns sentinel if the reader did not contain any forms."
+   If EOF, throws if eof-is-error is true. Otherwise returns sentinel."
   [reader eof-is-error sentinel is-recursive]
   (let [ch (read-char reader)]
     (cond
-     (nil? ch) sentinel
+     (nil? ch) (if eof-is-error (reader-error reader "EOF") sentinel)
      (whitespace? ch) (recur reader eof-is-error sentinel is-recursive)
-     (comment-prefix? ch) (recur (skip-line reader) eof-is-error sentinel is-recursive)
-     (macros ch) ((macros ch) reader ch)
-     (number-literal? reader ch) (read-number reader ch)
-     :default (read-symbol reader ch))))+     (comment-prefix? ch) (recur (read-comment reader ch) eof-is-error sentinel is-recursive)
+     :else (let [res
+                 (cond
+                  (macros ch) ((macros ch) reader ch)
+                  (number-literal? reader ch) (read-number reader ch)
+                  :else (read-symbol reader ch))]
+     (if (= res reader)
+       (recur reader eof-is-error sentinel is-recursive)
+       res)))))

      mapresult
      (if (or (= \u ch) (numeric? ch))
        (read-unicode-char reader ch)
        (throw (str "Unsupported escape charater: \\" ch))))))

(defn read-past
  "Read until first character that doesn't match pred, returning

  (loop [buffer (gstring/StringBuffer.)
         ch (read-char reader)]
    (cond
     (nil? ch) (reader-error reader "EOF while reading string")
     (= "\\" ch) (recur (escape-char buffer reader) (read-char reader))
     (= \" ch) (. buffer (toString))
     :default (recur (do (.append buffer ch) buffer) (read-char reader)))))
