MAKE-EVENT

Make-event is a utility for generating events. It provides a
capability not offered by Lisp macros (see defmacro), as it allows access to
the ACL2 state and logical world. In essence, the expression
(make-event form) replaces itself with the result of evaluating form,
say, ev, as though one had submitted ev instead of the make-event
call. But the evaluation of form may involve state and even modify
state, for example by attempting to admit some definitions and theorems.
Make-event protects the ACL2 logical world so that it is restored
after form is evaluated, before ev is submitted.

; Evaluate (generate-form state) to obtain (mv nil val state), and
; then evaluate val. (Generate-form is not specified here, but
; imagine for example that it explores the state and then generates
; some desired definition or theorem.)
(make-event (generate-form state))

; As above, but make sure that if this form is in a book, then when
; we include the book, the evaluation of (generate-form state)
; should return the same value as it did when the book was
; certified.
(make-event (generate-form state)
:check-expansion t)

; As above (where the :check-expansion value can be included or
; not), where if there is an error during expansion, then the error
; message will explain that expansion was on behalf of the indicated
; object, typically specified as the first argument.
(make-event (generate-form state)
:on-behalf-of (generate-form state))

where chk is nil (the default), t, or the intended ``expansion
result'' from the evaluation of form (as explained below); and if
supplied, obj is an arbitrary ACL2 object, used only in reporting errors
in expansion, i.e., in the evaluation of form.

We strongly recommend that you look at books/make-event/Readme.lsp, which
summarizes and suggests browsing of some .lisp files in that directory,
in order to understand make-event, perhaps before continuing to read this
documentation. For example, eval.lisp contains definitions of macros
must-succeed and must-fail that are useful for testing and are used
in many other books in that directory, especially eval-tests.lisp. Other
than the examples, the explanations here should suffice for most users. If
you want explanations of subtler details, see make-event-details.

Make-event is related to Lisp macroexpansion in the sense that its
argument is evaluated to obtain an expansion result, which is evaluated
again. Let us elaborate on each of these notions in turn: ``is evaluated,''
``expansion result'', and ``evaluated again.''

``is evaluated'' -- The argument can be any expression, which is evaluated
as would be any expression submitted to ACL2's top level loop. Thus,
state and user-defined stobjs may appear in the form supplied to
make-event. Henceforth, we will refer to this evaluation as
``expansion.'' Expansion is actually done in a way that restores ACL2's
built-in state global variables, including the logical world, to
their pre-expansion values (with a few exceptions --
see make-event-details -- and where we note that changes to user-defined
state global variables (see assign) are preserved). So, for example,
events might be evaluated during expansion, but they will disappear from the
logical world after expansion returns its result. Moreover, proofs are
enabled by default at the start of expansion (see ld-skip-proofsp), because
an anticipated use of make-event is to call the prover to decide which
event to generate, and that would presumably be necessary even if proofs had
been disabled.

``expansion result'' -- The above expansion may result in an ordinary
(non-state, non-stobj) value, which we call the ``expansion
result.'' Or, expansion may result in a multiple value of the form
(mv erp val state stobj-1 ... stobj-k), where k may be 0; in fact the
most common case is probably (mv erp val state). In that case, if
erp is not nil, then there is no expansion result, and the original
make-event evaluates to a soft error. If however erp is nil,
then the resulting value is val. Moreover, val must be an embedded
event form (see embedded-event-form); otherwise, the original make-event
evaluates to a soft error. Note that error messages from expansion are
printed as described under ``Error Reporting'' below.

``evaluated again'' -- the expansion result is evaluated in place of the
original make-event.

Note that the result of expansion can be an ordinary event, but it can
instead be another call of make-event, or even of a call of a macro that
expands to a call of make-event. Or, expansion itself can cause
subsidiary calls of make-event, for example if expansion uses ld to
evaluate some make-event forms. The state global variable
make-event-debug may be set to a non-nil value in order to see a
trace of the expansion process, where the level shown (as in ``3>'')
indicates the depth of expansions in progress.

Expansion of a make-event call will yield an event that replaces the
original make-event call. In particular, if you put a make-event
form in a book, then in essence it is replaced by its expansion result,
created during the proof pass of the certify-book process. We now
elaborate on this idea of keeping the original expansion.

By default, a make-event call in a certified book is replaced (by a
process hidden from the user, in an :expansion-alist field of the book's
certificate) by the expansion result from evaluation of its first
argument. Thus, although the book is not textually altered during
certification, one may imagine a ``book expansion'' corresponding to the
original book in which all of the events for which expansion took place
(during the proof phase of certification) have been replaced by their
expansions. A subsequent include-book will then include the book
expansion corresponding to the indicated book. When a book is compiled
during certify-book, it is actually the corresponding book expansion,
stored as a temporary file, that is compiled instead. That temporary file is
deleted after compilation unless one first evaluates the form
(assign keep-tmp-files t). Note however that all of the original forms
must still be legal events (see embedded-event-form). So for example,
if the first event in a book is (local (defmacro my-id (x) x)), followed
by (my-id (make-event ...)), the final ``include-book'' pass of
certify-book will fail because my-id is not defined when the
my-id call is encountered.

The preceding paragraph begins with ``by default'' because if you specify
:check-expansion t, then subsequent evaluation of the same make-event
call -- during the second pass of an encapsulate or during
include-book -- will do the expansion again and check that the
expansion result equals the original expansion result. In the unusual case
that you know the expected expansion result, res, you can specify
:check-expansion res. This will will cause a check that every subsequent
expansion result for the make-event form is res, including the
original one.

Error Reporting.

Suppose that expansion produces a soft error as described above. That is,
suppose that the argument of a make-event call evaluates to a multiple
value (mv erp val state ...) where erp is not nil. If erp is
a string, then that string is printed in the error message. If erp is
a cons pair whose car is a string, then the error prints
"~@0" with #\0 bound to that cons pair; see fmt. Any other
non-nil value of erp causes a generic error message to be printed.

Restriction to the Top Level.

Every form enclosing a make-event call must be an embedded event form
(see embedded-event-form). This restriction enables ACL2 to track
expansions produced by make-event. For example: