Skip to content

Instantly share code, notes, and snippets.

@Bronsa
Created July 16, 2012 23:43
Show Gist options
  • Save Bronsa/3125880 to your computer and use it in GitHub Desktop.
Save Bronsa/3125880 to your computer and use it in GitHub Desktop.
(defprotocol PushbackReader
(read-char [reader] "Returns the next char from the Reader, nil if the end of stream has been reached")
(unread [reader ch] "Push back a single character on to the stream"))
(defmacro update! [what f]
(list 'set! what (list f what)))
;;not thread-safe, but i guess i don't care?
(deftype StringPushbackReader
[^:unsynchronized-mutable ^String s ^"[C" buf ^:unsynchronized-mutable len ^:unsynchronized-mutable buf?]
PushbackReader
(read-char [reader]
(if buf?
(do (set! buf? false)
(aget buf 0))
(when (> len 0)
(let [r (.charAt s 0)]
(update! len dec)
(set! s (.substring s 1))
r))))
(unread [reader ch]
(if buf? (throw (RuntimeException. "Pushback buffer is full")))
(aset buf 0 ^char ch)
(set! buf? true)))
(defn push-back-reader [^String s]
"Creates a StringPushbackReader from a given string"
(StringPushbackReader. s (char-array 1) (.length s) false))
(defprotocol LineNumberingReader
(get-line-number [reader])
(read-line [reader]))
(deftype LineNumberingPushbackReader
[spr ^:unsynchronized-mutable line ^:unsynchronized-mutable line-start? ^:unsynchronized-mutable prev]
PushbackReader
(read-char [reader]
(when-let [ch (read-char spr)]
(let [ch (if (= \return ch)
(let [c (read-char spr)]
(when-not (= \formfeed ch)
(unread spr ch))
\newline)
ch)]
(set! prev line-start?)
(set! line-start? (= ch \newline))
(when line-start?
(update! line inc))
ch)))
(unread [reader ch]
(when line-start? (update! line dec))
(set! line-start? prev)
(unread spr ch))
LineNumberingReader
(get-line-number [reader] (inc line))
(read-line [reader]
(let [c (read-char reader)]
(case c
nil nil
\newline ""
(let [rest (read-line reader)]
(set! prev false)
(set! line-start? true)
(str c rest))))))
(defn line-numbering-push-back-reader [s]
(LineNumberingPushbackReader. (push-back-reader s) 0 true nil))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment