elisp: Catch and Throw

 
 10.6.1 Explicit Nonlocal Exits: ‘catch’ and ‘throw’
 ---------------------------------------------------
 
 Most control constructs affect only the flow of control within the
 construct itself.  The function ‘throw’ is the exception to this rule of
 normal program execution: it performs a nonlocal exit on request.
 (There are other exceptions, but they are for error handling only.)
 ‘throw’ is used inside a ‘catch’, and jumps back to that ‘catch’.  For
 example:
 
      (defun foo-outer ()
        (catch 'foo
          (foo-inner)))
 
      (defun foo-inner ()
        ...
        (if x
            (throw 'foo t))
        ...)
 
 The ‘throw’ form, if executed, transfers control straight back to the
 corresponding ‘catch’, which returns immediately.  The code following
 the ‘throw’ is not executed.  The second argument of ‘throw’ is used as
 the return value of the ‘catch’.
 
    The function ‘throw’ finds the matching ‘catch’ based on the first
 argument: it searches for a ‘catch’ whose first argument is ‘eq’ to the
 one specified in the ‘throw’.  If there is more than one applicable
 ‘catch’, the innermost one takes precedence.  Thus, in the above
 example, the ‘throw’ specifies ‘foo’, and the ‘catch’ in ‘foo-outer’
 specifies the same symbol, so that ‘catch’ is the applicable one
 (assuming there is no other matching ‘catch’ in between).
 
    Executing ‘throw’ exits all Lisp constructs up to the matching
 ‘catch’, including function calls.  When binding constructs such as
 ‘let’ or function calls are exited in this way, the bindings are
 unbound, just as they are when these constructs exit normally (See
 Local Variables).  Likewise, ‘throw’ restores the buffer and position
 saved by ‘save-excursion’ (SeeExcursions), and the narrowing status
 saved by ‘save-restriction’.  It also runs any cleanups established with
 the ‘unwind-protect’ special form when it exits that form (See
 Cleanups).
 
    The ‘throw’ need not appear lexically within the ‘catch’ that it
 jumps to.  It can equally well be called from another function called
 within the ‘catch’.  As long as the ‘throw’ takes place chronologically
 after entry to the ‘catch’, and chronologically before exit from it, it
 has access to that ‘catch’.  This is why ‘throw’ can be used in commands
 such as ‘exit-recursive-edit’ that throw back to the editor command loop
 (SeeRecursive Editing).
 
      Common Lisp note: Most other versions of Lisp, including Common
      Lisp, have several ways of transferring control nonsequentially:
      ‘return’, ‘return-from’, and ‘go’, for example.  Emacs Lisp has
      only ‘throw’.  The ‘cl-lib’ library provides versions of some of
      these.  See(cl)Blocks and Exits.
 
  -- Special Form: catch tag body...
      ‘catch’ establishes a return point for the ‘throw’ function.  The
      return point is distinguished from other such return points by TAG,
      which may be any Lisp object except ‘nil’.  The argument TAG is
      evaluated normally before the return point is established.
 
      With the return point in effect, ‘catch’ evaluates the forms of the
      BODY in textual order.  If the forms execute normally (without
      error or nonlocal exit) the value of the last body form is returned
      from the ‘catch’.
 
      If a ‘throw’ is executed during the execution of BODY, specifying
      the same value TAG, the ‘catch’ form exits immediately; the value
      it returns is whatever was specified as the second argument of
      ‘throw’.
 
  -- Function: throw tag value
      The purpose of ‘throw’ is to return from a return point previously
      established with ‘catch’.  The argument TAG is used to choose among
      the various existing return points; it must be ‘eq’ to the value
      specified in the ‘catch’.  If multiple return points match TAG, the
      innermost one is used.
 
      The argument VALUE is used as the value to return from that
      ‘catch’.
 
      If no return point is in effect with tag TAG, then a ‘no-catch’
      error is signaled with data ‘(TAG VALUE)’.