To help catch predictable errors, I've written my own linting tasks that read the code and report any inconsistencies it finds. One of the hackier pieces to this right now is the following function:

(defun lint-get-forms (filename)
  "Read FILENAME and return a list of its Lisp forms."
  (let ((pos 0) forms)
      (insert-file-contents filename)
      (condition-case _
          (while t
            (when-let ((cell (read-from-string (buffer-string) pos)))
              (push (car cell) forms)
              (goto-char (setq pos (cdr cell)))))
        (error forms)))

Is there a better way to do this (preferably without condition-case)?

Ideally these checks would be done at compile-time, but they're not stable enough yet to move to the other repository.

  • Why convert buffer text to a string and read from that string? Why not read directly from the buffer? The latter is typically how to read from a Lisp file.
    – Drew
    May 15, 2017 at 14:22
  • @Drew Hence why I'm posting this question :-) I think I neglected to consider read's optional argument. May 16, 2017 at 2:46
  • Got it. It's a good question.
    – Drew
    May 16, 2017 at 14:13

1 Answer 1


See Drew's answer to a related question.

If you do not mind ignoring all errors (I do not know which errors read might signal), you should use ignore-errors. Otherwise, your error handler should probably be specific to end-of-file errors.

Personally, I take (sometimes guilty) pleasure in K&R-style and functional brevity, so I would write your function like this:

(defun lint-get-forms (filename)
  "Read FILENAME and return a list of its Lisp forms."
    (let ((buf (current-buffer))
      (insert-file-contents filename)
      (while (ignore-errors (push (read buf) forms)))
      (nreverse forms))))

Regardless of whether you find this while form too terse, I recommend using read over read-from-string, as the former is much more powerful in the type of its argument. If, for some reason I am missing, you are intent on using read-from-string, I suggest caching the result of buffer-string.

P.S. Is there a reason you are calling goto-char?

  • re goto-char: read-string does not advance point. And terse is fine by me :-) May 16, 2017 at 2:47
  • @SeanAllred Yes, but you were already passing an updated pos to read-from-string.
    – Basil
    May 16, 2017 at 9:40

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.