(defn skip-whitespace
"Skips whitespace characters on stream s. Returns :line-start, :stream-end,
or :body to indicate the relative location of the next character on s.
Interprets comma as whitespace and semicolon as comment to end of line.
Does not interpret #! as comment to end of line because only one
character of lookahead is available. The stream must either be an
instance of LineNumberingPushbackReader or duplicate its behavior of both
supporting .unread and collapsing all of CR, LF, and CRLF to a single
\\newline."
[s]
(loop [c (.read s)]
(cond
(= c (int \newline)) :line-start
(= c -1) :stream-end
(= c (int \;)) (do (.readLine s) :line-start)
(or (Character/isWhitespace (char c)) (= c (int \,))) (recur (.read s))
:else (do (.unread s c) :body))))