make-event
expansion
Major Section: MAKE-EVENT
The normal user of make-event
can probably ignore this section, but we
include it for completeness. We assume that the reader has read and
understood the basic documentation for make-event
(see make-event), but
we begin below with a summary of expansion.
Introduction
Here is a summary of how we handle expansion involving make-event
forms.
(make-event form :check-expansion nil)
This shows the :check-expansion
default of nil
, and is typical user
input. We compute the expansion exp
of form
, which is the expansion
of the original make-event
expression and is evaluated in place of that
expression.
(make-event form :check-expansion t)
The user presumably wants it checked that the expansion doesn't change in the
future, in particular during include-book
. If the expansion of
form
is exp
, then we will evaluate exp
to obtain the value as
before, but this time we record that the expansion of the original
make-event
expression is (make-event form :check-expansion exp)
rather than simply exp
.
(make-event form :check-expansion exp) ; exp a cons
This is generated for the case that :check-expansion
is t
, as
explained above. Evaluation is handled as described in that above case,
except here we check that the expansion result is the given exp
.
(Actually, the user is also allowed supply such a form.) The original
make-event
expression does not undergo any expansion (intuitively, it
expands to itself).
Now let us take a look at how we expand progn
forms (encapsulate
is handled similarly).
(progn ... (make-event form :check-expansion nil) ...)
The expansion is obtained by replacing the make-event
form as follows.
Let exp
be the expansion of form
, Then replace the above
make-event
form, which we denote as F
, by
(record-expansion F exp)
. Here, record-expansion
is a macro that
returns its second argument.
(progn ... (make-event form :check-expansion t) ...)
The expansion is of the form (record-expansion F exp)
as in the nil
case above, except that this time exp
is
(make-event form :check-expansion exp')
, where exp'
is the expansion
of form
.
(progn ... (make-event form :check-expansion exp) ...) ; exp a cons
No expansion takes place unless expansion takes place for at least one of the
other subforms of the progn
, in which case each such form F
is
replaced by (record-expansion F exp)
where exp
is the expansion of
F
.
Detailed semantics
In our explanation of the semantics of make-event
, we assume familiarity
with the notion of ``embedded event form'' (see embedded-event-form).
Let's say that the ``actual embedded event form'' corresponding to a given
form is the underlying call of an ACL2 event: that is, LOCAL
s are
dropped when ld-skip-proofsp
is 'include-book
, and macros are
expanded away, thus leaving us with a progn
, a make-event
, or an
event form (possibly encapsulate
), any of which might have surrounding
local
, skip-proofs
, or with-output
calls.
Thus, such an actual embedded event form can be viewed as having the form
(rebuild-expansion wrappers base-form)
where base-form
is a
progn
, a make-event
, or an event form (possibly encapsulate
), and
wrappers
are (as in ACL2 source function destructure-expansion
) the
result of successively removing the event form from the result of
macroexpansion, leaving a sequence of (local)
, (skip-proofs)
, and
(with-output ...)
forms. In this case we say that the form
``destructures into'' the indicated wrappers
and base-form
, and that
it can be ``rebuilt from'' those wrappers
and base-form
.
Elsewhere we define the notion of the ``expansion result'' from an evaluation
(see make-event), and we mention that when expansion concludes, the ACL2
logical world and most of the state
are restored to their
pre-expansion values. Specifically, after evaluation of the argument of
make-event
(even if it is aborted), the ACL2 logical world is restored to
its pre-evaluation value, as are all state global variables in the list
*protected-system-state-globals*
. Thus, assignments to
user-defined state globals (see assign) do persist after expansion, since
they are not in that list.
We recursively define the combination of evaluation and expansion of an
embedded event form, as follows. We also simultaneously define the notion of
``expansion takes place,'' which is assumed to propagate upward (in a sense
that will be obvious), such that if no expansion takes place, then the
expansion of the given form is considered to be itself. It is useful to keep
in mind a goal that we will consider later: Every make-event
subterm of
an expansion result has a :check-expansion
field that is a consp
,
where for this purpose make-event
is viewed as a macro that returns its
:check-expansion
field. (Implementation note: The latest expansion of a
make-event
, progn
, progn!
, or encapsulate
is stored
in state global 'last-make-event-expansion
, except that if no expansion
has taken place for that form then 'last-make-event-expansion
has value
nil
.)
If the given form is not an embedded event form, then simply cause a soft error,
(mv erp val state)
whereerp
is notnil
. Otherwise:If the evaluation of the given form does not take place (presumably because
local
events are being skipped), then no expansion takes place. Otherwise:Let
x
be the actual embedded event form corresponding to the given form, which destructures into wrappersW
and base-formB
. Then the original form is evaluated by evaluatingx
, and its expansion is as follows.If
B
is(make-event form :check-expansion val)
, then expansion takes place if and only ifval
is not aconsp
and no error occurs, as now described. LetR
be the expansion result from protected evaluation ofform
, if there is no error.R
must be an embedded event form, or it is an error. Then evaluate/expandR
, where ifval
is notnil
then state global'ld-skip-proofsp
is initialized tonil
. (This initialization is important so that subsequent expansions are checked in a corresponding environment, i.e., where proofs are turned on in both the original and subsquent environments.) It is an error if this evaluation causes an error. Otherwise, the evaluation yields a value, which is the result of evaluation of the originalmake-event
expression, as well as an expansion,E_R
. LetE
be rebuilt fromW
andE_R
. The expansion of the original form isE
ifval
isnil
, and otherwise is the result of replacing the original form's:check-expansion
field withE
, with the added requirement that ifval
is nott
(thus, aconsp
) thenE
must equalval
or else we cause an error.If
B
is either(progn form1 form2 ...)
or(encapsulate sigs form1 form2 ...)
, then after evaluatingB
, the expansion of the original form is the result of rebuilding fromB
, with wrappersW
, after replacing eachformi
inB
for which expansion takes place by(record-expansion formi formi')
, whereformi'
is the expansion offormi
. Note that these expansions are determined as theformi
are evaluated in sequence (where in the case ofencapsulate
, this determination occurs only during the first pass). Except, if no expansion takes place for anyformi
, then the expansion of the original form is itself.Otherwise, the expansion of the original form is itself.
Similarly to the progn
and encapsulate
cases above, book
certification causes a book to be replaced by its so-called ``book
expansion.'' There, each event ev
for which expansion took place during
the proof pass of certification -- say, producing ev'
-- is replaced
by (record-expansion ev ev')
.
Implementation Note. The book expansion is actually implemented by way of
the :expansion-alist
field of its certificate, which associates
0-based positions of top-level forms in the book (not including the initial
in-package
form) with their expansions. Thus, the book's source file
is not overwritten; rather, the certificate's expansion-alist is applied when
the book is included or compiled. End of Implementation Note.
It is straightforward by computational induction to see that for any
expansion of an embedded event form, every make-event
sub-event has a
consp
:check-expansion
field. Here, by ``sub-event'' we mean to
expand macros; and we also mean to traverse progn
and encapsulate
forms as well as :check-expansion
fields of make-event
forms. Thus,
we will only see make-event
forms with consp
:check-expansion
fields in the course of include-book
forms, the second pass of
encapsulate
forms, and raw Lisp. This fact guarantees that an event form
will always be treated as its original expansion.
Notes on ttags
See defttag for documentation of the notion of ``trust tag'' (``ttag''). We
note here that even if an event (defttag tag-name)
for non-nil
tag-name
is admitted only during the expansion phase of a
make-event
form, then such expansion will nevertheless still cause
tag-name
to be recorded in the logical world (assuming that the
make-event
form is admitted). So in order to certify such a book, a
suitable :ttags
argument must be supplied; see certify-book.
ACL2 does provide a way to avoid the need for :ttags
arguments in such
cases. The idea is to certify a book twice, where the results of
make-event
expansion are saved from the first call of certify-book
and provided to the second call. see set-write-acl2x.
Finally, we discuss a very unusual case where certification does not involve
trust tags but a subsequent include-book
does involve trust tags: a
make-event
call specifying :check-expansion t
, whose expansion
generates a defttag
event during include-book
but not
certify-book
. Consider the following book.
(in-package "ACL2") (make-event (er-progn (if (@ skip-notify-on-defttag) ; non-nil when including a certified book (pprogn (fms "Value of (@ skip-notify-on-defttag): ~x0~|" (list (cons #0 (@ skip-notify-on-defttag))) *standard-co* state nil) (encapsulate () (defttag :foo) (value-triple "Imagine something bad here!"))) (value nil)) (value '(value-triple :some-value))) :check-expansion t)This book certifies successfully without the need for a
:ttags
argument
for certify-book
. Indeed, the above book's certificate does not
specify :foo
as a trust tag associated with the book, because no
defttag
event was executed during book certification. Unfortunately, if
we try to include this book without specifying a value of :ttags
that
allows :foo
, book inclusion will cause executing of the above
defttag
. If that inclusion happens in the context of certifying some
superior book and the appropriate :ttags
arguments have not been
provided, that certification will fail.