• Top
    • Documentation
    • Books
    • Recursion-and-induction
    • Boolean-reasoning
    • Projects
    • Debugging
    • Std
    • Proof-automation
    • Macro-libraries
    • ACL2
      • Theories
      • Rule-classes
      • Proof-builder
      • Hons-and-memoization
      • Events
      • History
      • Parallelism
      • Programming
      • Start-here
      • Real
      • Debugging
      • Miscellaneous
        • Term
        • Ld
          • Wormhole
          • Ld-skip-proofsp
          • Ld-redefinition-action
          • Lp
          • Ld-error-action
          • Ld-history
            • Guarantees-of-the-top-level-loop
            • Ld-post-eval-print
            • Ld-keyword-aliases
            • Current-package
            • Ld-query-control-alist
            • Ld-prompt
            • Keyword-commands
            • Redef+
            • Rebuild
            • Prompt
            • Ld-pre-eval-print
            • Calling-ld-in-bad-contexts
            • Ld-pre-eval-filter
            • P!
            • Ld-error-triples
            • Ld-verbose
            • Ld-evisc-tuple
            • A!
            • Default-print-prompt
            • Reset-ld-specials
            • Ld-always-skip-top-level-locals
            • Ld-missing-input-ok
            • Redef
            • Redef!
            • Redef-
            • I-am-here
            • Abort!
          • Hints
          • Type-set
          • Ordinals
          • ACL2-customization
          • With-prover-step-limit
          • With-prover-time-limit
          • Set-prover-step-limit
          • Local-incompatibility
          • Set-case-split-limitations
          • Subversive-recursions
          • Specious-simplification
          • Defsum
          • Oracle-timelimit
          • Thm
          • Defopener
          • Gcl
          • Case-split-limitations
          • Set-gc-strategy
          • Default-defun-mode
          • Top-level
          • Reader
          • Ttags-seen
          • Adviser
          • Ttree
          • Abort-soft
          • Defsums
          • Gc$
          • With-timeout
          • Coi-debug::fail
          • Expander
          • Gc-strategy
          • Coi-debug::assert
          • Sin-cos
          • Def::doc
          • Syntax
          • Subversive-inductions
        • Output-controls
        • Macros
        • Interfacing-tools
      • Interfacing-tools
      • Hardware-verification
      • Software-verification
      • Testing-utilities
      • Math
    • Ld
    • History

    Ld-history

    Saving and querying command history

    See ld for background on the ACL2 read-eval-print loop. The present topic pertains to a history kept for commands issued to that loop, which we call an ``ld-history'' (pronounced ``ell dee history''). Here are some things to keep in mind when reading this topic.

    • Each entry in the history includes the input command, the value returned, and other information, as explained further below.
    • This is about commands, not events: that is, we are concerned with forms that are submitted for evaluation to the top-level loop. See command.
    • An entry is saved for every command submitted by the user, even if it doesn't change the ACL2 world — e.g., (+ 3 4) — and even if it undoes commands — e.g., :ubt.
    • Keyword commands are turned into s-expressions before saving an entry; see keyword-commands. For example, the input :ubt :x is stored in an entry as the input (ubt ':x).
    • When an entry is saved for a command C that is evaluated in the context of a call of local, where C evaluates to an error-triple, then C is stored in the entry as (local C) unless C is already a call of local. (Technical Aside: This behavior supports local portcullis commands.)
    • The ld-history saves entries not only for commands issued in the original top-level loop, but also for commands issued in (recursive) calls of ld — but not during make-event expansion.
    • Entries are generally saved even when there are errors. However, entries are not saved for commands that exit with raw Lisp errors.

    Also see community-books file books/demos/ld-history-input.lsp for examples. The output from calling ld on that file (by calling the run-script tool in books/demos/ld-history-book.acl2) is in community-books file books/demos/ld-history-log.txt.

    The ld-history is a stack, represented as a list with the most recent commands at the front. But by default ACL2 is in single-entry mode, where the list is kept at length 1: an entry is saved in the ld-history only for the most recent command, and the previous entry is discarded. We now describe relevant utilities, including one that can switch to multiple-entry mode, where all entries are kept until a utility is called explicitly to discard old entries. Note that the mode is determined by the length of the ld-history: single-entry mode when length 1, multiple-entry mode when length 2 or more.

    • (ld-history state)
      This utility returns a list of structures, denoted ``ld-history entries'', with the most recent one first. By default, this list has length 1, but that can be changed; see adjust-ld-history below. Each entry in the list is recognized by the following predicate. NOTE: This query is evaluated before the ld-history stored in the ACL2 state is updated with a new entry, based on the current command; so the previous command will be at the top of the returned stack, not the current command. (In particular, submitting the form (ld-history state) at the ACL2 prompt does not put that form at the front of the returned list.)
    • (weak-ld-history-entry-p x)
      This function returns t if x has the shape of an entry in the ld-history list, else nil.
    • Here are accessors for an ld-history entry, which we think of as returning its fields. The formal parameter entry below is an entry in (i.e., member of) (ld-history state); an example call is thus (ld-history-entry-input (car (ld-history state))).
      • (ld-history-entry-input entry)
        The user input
      • (ld-history-entry-error-flg entry)
        Non-nil when there was an error translating the user input
      • (ld-history-entry-stobjs-out/value entry)
        When (ld-history-entry-error-flg entry) is nil, this is a cons whose car is is the stobjs-out — a list whose length is the number of values returned, with nil in each position except when occupied by a symbol indicating a returned stobj for that position — and whose cdr is the returned value in the single-value case, but is the list of returned values in the multiple-value case.
      • (ld-history-entry-stobjs-out entry)
        When (ld-history-entry-error-flg entry) is nil, this is the stobjs-out as described above; otherwise this is nil.
      • (ld-history-entry-value entry)
        When (ld-history-entry-error-flg entry) is nil, this is the value or values as described above; otherwise this is nil.
      • (ld-history-entry-user-data entry)
        This is nil by default. However, code can be provided to compute this field, as discussed below.
    • (adjust-ld-history x state)
      X is t, nil, or an integer. The result is an error-triple (mv nil value state), where value and the effect are as follows, and where if there is no change (i.e., the effect is a no-op) then value is (:no-change :length N) where N is the current length of the ld-history.
      • T:
        Change to multiple-entry mode, where an entry is saved for every command, not just the most recent command. There is no change if already in multiple-entry mode; otherwise the returned value is (:saving-ld-history t).
      • NIL:
        Change to single-entry mode, where an entry is saved only for the most recent command. There is no change if already in single-entry mode; otherwise the returned value is (:saving-ld-history nil), and all old entries will be discarded (to produce a single-element ld-history).
      • Positive integer k:
        Replace the current ld-history by its first k entries, except there is no change if in single-entry mode or if k is not less than the length of the current ld-history. Note that by ``current ld-history'' we refer to the ld-history in effect at the time adjust-ld-history is invoked, which does not include the current command being evaluated. (Thus, even if k is 1, multiple-entry mode will be preserved: the ld-history will have 2 entries immediately after the current command completes.) The returned value is (:ld-history-truncated :old-length LEN :new-length k), where LEN is the length of the current ld-history before the change.
      • Negative integer -k:
        This is intended to specify removal of the oldest k entries from the current ld-history. Thus, it is treated identically to argument k2 where k2 is the sum of -k and the length of the current ld-history, but only if that sum is positive; else there is no change. For example, suppose that -k is -3. If the current ld-history, h, has length 2 or 3, then there is no change; but if h has length 10, then it is to be replaced by (take 7 h) and the length will actually thus be 8 after the current command completes.

    Note that a call of adjust-ld-history is not an event that can be placed directly in books or encapsulate forms.

    Remark. If (adjust-ld-history n state) is evaluated while in multiple-entry mode, where n is a positive integer less than the current length of the ld-history, then the new ld-history after returning to the prompt will have length n+1. That's essentially because it will have length n immediately after that call of adjust-ld-history is evaluated, and then a new entry for the current command (which could be that call itself, if that's what was submitted at the prompt) will be pushed onto the ld-entry just before returning to the prompt. We say ``essentially'' because there is a Special Case: when n is 1 then a 2-element list of entries (e1 e2) is created where e2 has fields that are all nil; then when the new entry e is pushed onto the ld-history, e2 is dropped so that that the new ld-history is (e e1). This special-case trick is also used in multiple-entry mode when n is -k where k is one less than the length of the current ld-history, since that is treated the same as (adjust-ld-history 1 state); and this trick is also used when (adjust-ld-history t state) switches from single-entry mode to multiple-entry mode. End of Remark.

    Finally we discuss the user-data field of a ld-history entry, which (as noted above) has default nil. It is accessed using (ld-history-entry-user-data entry). It is set automatically when the ld-history is extended with a new entry: the function call (set-ld-history-entry-user-data input error-flg stobjs-out/value state), is executed where the actuals are the other fields of the entry as indicated, e.g., the first actual is the input field of the new entry (as returned by the function, ld-history-entry-input). Although set-ld-history-entry-user-data returns nil by default, this can be changed by providing your own function with a :guard of t and the same formal parameters (which however may be renamed, other than state). To make that change, define a function, which here we call my-user-data, and then attach it to set-ld-history-entry-user-data, as follows.

    (defun my-set-user-data (input error-flg stobjs-out/value state)
      (declare (xargs :guard t))
      ...)
    (defattach-system set-ld-history-entry-user-data my-set-user-data)

    The following example illustrates how to store the length of the ACL2 world in the user-data. Note that the world present in the state at the time the user-data is set, computed as (w state), is almost the final world produced by the command — it is missing just one triple, a so-called command marker.

    (defun my-world-length (input error-flg stobjs-out/value state)
      (declare (xargs :guard t :stobjs state)
               (ignore input error-flg stobjs-out/value))
      (len (w state)))
    
    (defattach-system set-ld-history-entry-user-data my-world-length)

    A subsequent inspection of the stored user-data shows the length of the current world, for example as follows.

    ACL2 !>(ld-history-entry-user-data (car (ld-history state)))
    125914
    ACL2 !>

    Notice that we used len, not length, since the :guard specified for our function needs to be t. Alternative definitions, which however are less efficienct, are as follows.

    (defun my-world-length (input error-flg stobjs-out/value state)
      (declare (xargs :guard t :stobjs state)
               (ignore input error-flg stobjs-out/value))
      (and (true-listp (w state))
           (length (w state))))
    
    (defun my-world-length (input error-flg stobjs-out/value state)
      (declare (xargs :guard t :stobjs state)
               (ignore input error-flg stobjs-out/value))
      (ec-call (length (w state))))

    Here is how to restore the original behavior, i.e., the default where the user-data is set to nil.

    (defattach-system set-ld-history-entry-user-data
                      set-ld-history-entry-user-data-default)