Monday, March 1, 2010

Revenge of the reader

Yesterday, I was compiling a function in SLIME, and I consistently got error: illegal function call messages from SBCL. The function was a pretty complicated one, and I couldn't figure out the error. I even resorted to commenting out sections, until I had an empty shell, with only the docstring. Then realization dawned — here is a simplified example of how the function looked like:

(defun foo (bar)
  "Docstring, followed by accidental dot".
  (let ((baz (1+ bar)))
    baz))

Did you notice the dot? I didn't, for a while (guess I should take breaks every hour or so and rest my eyes, especially in the evening). But the reader did.

2 comments:

  1. Easily solved with a reader macro:


    (defconstant +string-escape+ #\\)

    (defun revenge-string-reader-macro (stream delimiter)
    (loop
    :for ch = (read-char stream)
    :until (char= ch delimiter)
    :collect (if (char= ch +string-escape+)
    (read-char stream)
    ch) :into chars
    :finally (let ((result (coerce chars 'string)))
    (when (eql #\. (peek-char nil stream nil nil))
    (warn "The revenge string reader macro detected a dot after the string ~S"
    result))
    (return result))))



    (set-macro-character #\" (function revenge-string-reader-macro) nil)



    C/USER[15]> '("abcl". d)
    WARNING: The revenge string reader macro detected a dot after the string "abcl"
    ("abcl" . D)
    C/USER[16]> '("abcl" . d)
    ("abcl" . D)

    ReplyDelete
  2. Thanks Pascal, but if I wanted a read macro for each idiotic mistake I make, I would soon run out of characters :-)

    ReplyDelete