Filtering...

outer-local

books/centaur/misc/outer-local

Included Books

other
(in-package "ACL2")
include-book
(include-book "xdoc/top" :dir :system)
include-book
(include-book "std/util/bstar" :dir :system)
other
(defxdoc outer-local
  :parents (macro-libraries)
  :short "Support for events that are local to the outer context."
  :long "<p>Think of @('outer-local') as being like @('progn'), except that the
events inside it are local to some encapsulate context above in which they are
sitting.  Outer-local only works when paired with @('with-outer-locals'), which
is essentially like @('(encapsulate nil ...)') except that it allows
@('outer-local') events to work.</p>

<p>Example:</p>
@({
 (with-outer-locals
   (defun exported-fn ...)
   (local (defthm lemma ...))
   (defthm exported-thm ...)
   (outer-local :depth 1 (defthm book-thm ...)))
})
<p>produces, essentially:</p>
@({
 (local
  (encapsulate nil
    (defun exported-fn ...)
    (local (defthm lemma ...))
    (defthm exported-thm ...)
    (defthm book-thm ...)))
 (defun exported-fn ...)
 (defthm exported-thm ...))
})

<p>Effectively, the event marked @('outer-local') is visible in book or
encapsulate surrounding this with-outer-locals event, but local to that
context.</p>

<p>The @(':depth') argument to @('outer-local') is optional but must occur
first if it is present.  It takes a positive integer, defaulting to 1.  There
must be @('depth') nestings of @('with-outer-locals') surrounding each
outer-local invocation in order for it to work as intended; in that case, the
events inside the outer-local are local to the context @('depth') levels
outside it.</p>

<p>Note: IN-THEORY events inside outer-local probably won't act as you would
like them to, at least in the presence of nonlocal IN-THEORY events.</p>")
outer-local-pushmacro
(defmacro outer-local-push
  (&key (level '1))
  `(progn (table outer-local-event-table :action :no-op)
    (table outer-local-event-table :action '(:push . ,LEVEL))
    (value-triple :invisible)))
outer-local-popmacro
(defmacro outer-local-pop
  nil
  '(progn (table outer-local-event-table :action :no-op)
    (table outer-local-event-table :action :pop)
    (value-triple :invisible)))
outer-localmacro
(defmacro outer-local
  (&rest args)
  (b* (((mv level events) (if (eq (car args) :level)
         (if (or (atom (cdr args)) (not (posp (cadr args))))
           (progn$ (er hard?
               'outer-local
               ":level must be provided a positive integer argument")
             (mv nil nil))
           (mv (cadr args) (cddr args)))
         (if (member :level args)
           (progn$ (er hard?
               'outer-local
               ":level must occur first in an outer-local form, if given")
             (mv nil nil))
           (mv 1 args)))))
    `(with-output :off :all :stack :push (progn (outer-local-push :level ,LEVEL)
        (with-output :stack :pop (progn . ,EVENTS))
        (outer-local-pop)))))
with-outer-local-collect-eventsfunction
(defun with-outer-local-collect-events
  (world context-depth event-stack-top event-stack)
  (declare (xargs :mode :program))
  (b* (((when (atom world)) (er hard?
         'with-outer-local
         "Reached end of world while scanning")) ((unless (eq (caar world) 'event-landmark)) (with-outer-local-collect-events (cdr world)
          context-depth
          event-stack-top
          event-stack))
      (event-tuple (cddr (car world)))
      (event-depth (access-event-tuple-depth event-tuple))
      ((when (<= event-depth context-depth)) (b* (((when (consp event-stack)) (er hard?
               'with-outer-local
               "Found the previous event while still in an outer-local context")))
          event-stack-top))
      ((unless (eql event-depth (+ 1 context-depth))) (with-outer-local-collect-events (cdr world)
          context-depth
          event-stack-top
          event-stack))
      (form (access-event-tuple-form event-tuple))
      ((unless (and (eq (first form) 'table)
           (eq (second form) 'outer-local-event-table)
           (eq (third form) :action))) (with-outer-local-collect-events (cdr world)
          context-depth
          (cons form event-stack-top)
          event-stack))
      ((when (eq (fourth form) :no-op)) (with-outer-local-collect-events (cdr world)
          context-depth
          event-stack-top
          event-stack))
      ((when (eq (fourth form) :pop)) (with-outer-local-collect-events (cdr world)
          context-depth
          nil
          (cons event-stack-top event-stack)))
      ((unless (and (consp (fourth form))
           (eq (car (fourth form)) 'quote)
           (eq (car (cadr (fourth form))) ':push)
           (posp (cdr (cadr (fourth form)))))) (er hard?
          'with-outer-local
          "bad outer-local-event-table form: ~x0"
          form))
      ((unless (consp event-stack)) (er hard?
          'with-outer-local
          "event stack was empty when we reached an outer-local-push event"))
      (level (cdr (cadr (fourth form))))
      ((when (eql level 1)) (with-outer-local-collect-events (cdr world)
          context-depth
          (car event-stack)
          (cdr event-stack))))
    (with-outer-local-collect-events (cdr world)
      context-depth
      (cons `(outer-local :level ,(1- LEVEL) . ,EVENT-STACK-TOP)
        (car event-stack))
      (cdr event-stack))))
with-outer-local-eventsfunction
(defun with-outer-local-events
  (world)
  (declare (xargs :mode :program))
  (b* ((world (scan-to-event world)) (tuple (cddr (car world)))
      (context-depth (access-event-tuple-depth tuple)))
    (cons 'progn
      (with-outer-local-collect-events (cdr world)
        context-depth
        nil
        nil))))
finish-with-outer-localmacro
(defmacro finish-with-outer-local
  nil
  `(make-event (with-outer-local-events (w state))))
with-outer-localsmacro
(defmacro with-outer-locals
  (&rest events)
  `(with-output :off :all :stack :push (progn (local (with-output :stack :pop (encapsulate nil . ,EVENTS)))
      (finish-with-outer-local))))