1

When calling (read "(+ 1 2) (+ 2 3)"), I get (+ 1 2), as expected. How can I get the next expression, namely (+ 2 3)?

1

3 Answers 3

1

"(+ 1 2) (+ 2 3)" is not a stream, it is a string. Strings do not keep track of what has been read already and what should be read next, so if you call read on this string multiple times you will always get the first expression.

You probably want to read from a buffer instead. Calling read on a buffer will move point in that buffer as it goes, allowing the next call to read to pick up where the first left off.

See chapter 20.2 Input Streams in the Elisp manual for more information.

3
  • The question may well be an X-Y question. What is it that you're really trying to do? (Maybe @db48x has guessed correctly what you want to know, in which case great.) But read reads a single expression from its argument (a string in this case), and you passed it a string with two expressions. It read an expression from the string you gave it, and it returned that expression, (+ 1 2).
    – Drew
    May 17, 2022 at 1:25
  • In fairness the signature is (read &optional STREAM) and "STREAM or the value of ‘standard-input’ may be: ... a string (takes text from string, starting at the beginning)". That "starting at the beginning" part is the key here of course, as you've pointed out.
    – phils
    May 17, 2022 at 5:55
  • Thanks for the link to X-Y question. I am prompting the user with a minibuffer, and asking them to input s-expressions. So they might say (+ 1 2) and I want to read that and store it as s-expression. But I also want to support (+ 1 2) (+ 2 3) in the minibuffer as well so that I may read in multiple s-expressions at once.
    – Josh Cho
    May 17, 2022 at 20:45
1

If you want to read all the expressions from the string "(+ 1 2) (+ 2 3)" just wrap it by an extra pair of parantheses to represent a list, i.e., read "((+ 1 2) (+ 2 3))" instead.

The following Elisp snippets give you a hint how to do that:

(let ((str "(+ 1 2) (+ 2 3)"))
  (read (concat "(" str ")")))

or

(let ((str "(+ 1 2) (+ 2 3)"))
  (read (format "(%s)" str)))

Thereafter, you can iterate over the list with dolist or cl-loop for ... in ... do.

1
  • This does seem more elegant, thank you.
    – Josh Cho
    May 18, 2022 at 20:46
1

I slightly modified the answer in How should you read a Lisp file as Lisp for processing without condition-case? to get

(defun read-multiple (string)
  "Read STRING and return a list of its Lisp forms."
  (with-temp-buffer
    (let ((buf (current-buffer))
          forms)
      (insert string)
      (goto-char (point-min))
      (while (ignore-errors (push (read buf) forms)))
      (nreverse forms))))

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.