The while loops

Two while loops follow. The first while has a true-or-false-test that tests true if the prefix argument for forward-sentence is a negative number. This is for going backwards. The body of this loop is similar to the body of the second while clause, but it is not exactly the same. We will skip this while loop and concentrate on the second while loop.

The second while loop is for moving point forward. Its skeleton looks like this:

(while (> arg 0)            ; true-or-false-test
  (let varlist
    (if (true-or-false-test)
        then-part
      else-part
  (setq arg (1- arg))))     ; while loop decrementer

The while loop is of the decrementing kind. (See A Loop with a Decrementing Counter.) It has a true-or-false-test that tests true so long as the counter (in this case, the variable arg) is greater than zero; and it has a decrementer that subtracts 1 from the value of the counter every time the loop repeats.

If no prefix argument is given to forward-sentence, which is the most common way the command is used, this while loop will run once, since the value of arg will be 1.

The body of the while loop consists of a let expression, which creates and binds a local variable, and has, as its body, an if expression.

The body of the while loop looks like this:

(let ((par-end
       (save-excursion (end-of-paragraph-text) (point))))
  (if (re-search-forward sentence-end par-end t)
      (skip-chars-backward " \t\n")
    (goto-char par-end)))

The let expression creates and binds the local variable par-end. As we shall see, this local variable is designed to provide a bound or limit to the regular expression search. If the search fails to find a proper sentence ending in the paragraph, it will stop on reaching the end of the paragraph.

But first, let us examine how par-end is bound to the value of the end of the paragraph. What happens is that the let sets the value of par-end to the value returned when the Lisp interpreter evaluates the expression

(save-excursion (end-of-paragraph-text) (point))

In this expression, (end-of-paragraph-text) moves point to the end of the paragraph, (point) returns the value of point, and then save-excursion restores point to its original position. Thus, the let binds par-end to the value returned by the save-excursion expression, which is the position of the end of the paragraph. (The end-of-paragraph-text function uses forward-paragraph, which we will discuss shortly.)

Emacs next evaluates the body of the let, which is an if expression that looks like this:

(if (re-search-forward sentence-end par-end t) ; if-part
    (skip-chars-backward " \t\n")              ; then-part
  (goto-char par-end)))                        ; else-part

The if tests whether its first argument is true and if so, evaluates its then-part; otherwise, the Emacs Lisp interpreter evaluates the else-part. The true-or-false-test of the if expression is the regular expression search.

It may seem odd to have what looks like the real work of the forward-sentence function buried here, but this is a common way this kind of operation is carried out in Lisp.