(defun newline-p (input) (or (char= input #\Linefeed) (char= input #\Return))) (defun normalize-shader-source (input) (etypecase input (string (with-input-from-string (stream input) (normalize-shader-source stream))) (stream (with-output-to-string (output) (loop for char = (read-char input NIL) while char do (case char ;; Handle backslash escape (#\\ (cond ((newline-p (peek-char NIL input NIL)) (read-char input) (when (newline-p (peek-char NIL input NIL)) (read-char input))) (T (error "Illegal backslash without newline.")))) ;; Handle newline behaviour and such ((#\Return #\Linefeed) (when (newline-p (peek-char NIL input NIL)) (read-char input)) (write-char #\Newline output)) ;; Handle comments (#\/ (case (peek-char NIL input) (#\/ (loop for prev = #\ then char for char = (read-char input NIL) until (or (not char) (and (not (char= #\\ prev)) (newline-p char)))) (write-char #\Newline output)) (#\* (loop for prev = #\ then char for char = (read-char input) until (and (char= #\* prev) (char= #\/ char)))) (T (write-char char output)))) ;; Handle consecutive whitespace ((#\Tab #\Space) (loop for char = (read-char input NIL) while (or (eql char #\Tab) (eql char #\Space)) finally (when char (unread-char char input))) (write-char #\Space output)) ;; Handle other chars (T (write-char char output))))))))