1

Context: Emacs 29.0.60

The and the empty lines after the script text below are point positions at which the interactively executed function eval-last-sexp echoes in the minibuffer and the *Messages* buffer: " DEMONSTRATION instead of explanation: ".

" DEMONSTRATION instead of explanation: "
;;▬ 'Lisp_Reader' is this part of Emacs which generates from the elisp 
;;▬ code text objects/symbols/values used in further steps to generate
;;▬ executable code and run it. The  'Lisp_Reader'  requires the elisp 
;;▬ code text to follow certain rules in order to be able to parse/scan 
;;▬ the text into meaningful result. 


If the point is positioned somewhere within the text the function will give an Error like for example: elisp--eval-last-sexp: Symbol’s value as variable is void: code .

How does it come that this function on "its way back" in the text from the marked positions and from the empty lines after the text are not complaining about all the words it meets on that way?

How does eval-last-sexp determine the expression for evaluation? Or in other words:

What is the principle of the algorithm used to determine the expression to evaluate?

3
  • The work is done by elisp--preceding-sexp which calls (forward-sexp -1). Trying that manually in the various places you mention shows that it is the one that's doing the heavy lifting. So you only (ahem) have to understand forward-sexp.
    – NickD
    Apr 23, 2023 at 17:59
  • I went already that path ... and failed to guess from the code what the core principle is in order to clearly see the reason for the observed behavior.
    – Claudio
    Apr 23, 2023 at 19:22
  • That was a tongue-in-cheek comment: understanding forward-sexp hinges on understanding scan_lists, a 400-line C function in syntax.c. If you look at it, it's probably not too bad, but it is full of low-level finicky details, so it's not going to be a cakewalk. Something to do on a rainy day when you have nothing better to do perhaps... But I doubt that there is much of a principle hidden in there: it's more a hard slog through all the cases.
    – NickD
    Apr 24, 2023 at 3:37

1 Answer 1

1

There are two ways of approaching the goal of finding out which principles guide the processing of eval-last-sexp:

  1. looking at the elisp and the underlying C source code fully understanding what it does and how it works in order to derive from that knowledge the underlying principle (if there is actually such there).

  2. observing what happens in various different cases of invoking eval-last-sexp and deduct from the observation the principle able to explain all of the observed cases making their outcome predictable

This answer uses the second approach and explains the observed cases using following test text:

;; "End of file during parsing"
▮
" DEMONSTRATION instead of explanation: "
;;▮ 'Lisp_Reader' is this part of Emacs which generates from the elisp 
;;▮ code text objects/symbols/values used in further steps to generate
;;▮ executable code and run it. The  'Lisp_Reader'  requires the elisp 
;;▮ code text to follow certain rules in order to  parse/scan the text
;;▮ into a meaningful result. 
;;,``,'',`','`,;; ;; ;; ;; ;; ;; ;; ;; ;; ;; ;; # # @ @  ;;;;;;;;;;▮"▮
 ?▮  ; <- PROBLEM -> elisp--preceding-sexp: End of file during parsing
     ;   \__ elisp expects that ? is followed by some character

The black rectangles mark the tested positions of the cursor/point in the process of finding out how eval-last-sexp works.

The deducted principle is:

The backward search consists of TWO different phases:

  • starting from the cursor position, in the first phase of going back, go character by character skipping characters which are considered not to be a part of an expression like: space, semicolon, comma, back-tick, ...:
;;,``,'',`','`, #, @
  • don't care going back about the correctness of detection of strings or comments by assuming that the start position is at end of an actual expression and not within a string or a comment.

  • if in the first phase (which ends with detection of a newline) no character which can belong to an expression has been found, proceed with a second phase and go the next backwards steps no more character by character but line by line parsing each line from its beginning to make sure it is not a comment line.

The above principle (splitting the backward search into two phases) does explain how it comes that positioning the cursor in an empty line below the text or at the end of line containing only "expression-neutral" characters results in detection of the string starting the block of comment lines.

Whether the in elisp and C coded algorithm actually works exactly as described above remains still open, but the described principle makes it at least possible to predict the result depending on cursor position and explains the surprising (when assuming going back only character by character) behavior.

A little bit fun is the Error message elisp raises in case when searching back hits the beginning of the text (or when it starts directly behind a question mark):

"End of file during parsing"

P.S. to make it easier to play around with eval-last-sexp I have bound it to F8:

(global-set-key (kbd "<f8>") 'eval-last-sexp)

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.