Filtering...

def-error-checker

books/kestrel/error-checking/def-error-checker

Included Books

other
(in-package "ACL2")
include-book
(include-book "std/system/pseudo-event-formp" :dir :system)
include-book
(include-book "kestrel/utilities/er-soft-plus" :dir :system)
include-book
(include-book "std/basic/defs" :dir :system)
include-book
(include-book "std/util/define" :dir :system)
include-book
(include-book "xdoc/defxdoc-plus" :dir :system)
other
(defxdoc def-error-checker
  :parents (error-checking)
  :short "Generate an error checking function
          and an associated macro abbreviation."
  :long (topstring (p "This macro generates an error checking function
     and an associated macro abbreviation of the following form:")
    (codeblock "(define <name> (<x1> ... <xn>"
      "                (description msgp)"
      "                (error-erp (not (null error-erp))"
      "                           "Flag to return in case of error.")"
      "                (error-val "Value to return in case of error.")"
      "                (ctx "Context for errors.")"
      "                state)"
      "  :returns (mv <erp>"
      "               <val>"
      "               state)"
      "  :mode <mode>"
      "  :verify-guards <verify-guards> ; may be absent"
      "  :parents <parents> ; may be absent"
      "  :short <short> ; may be absent"
      "  :long <long> ; may be absent"
      "  (b* (((unless <condition1>) (er-soft+"
      "                               ctx error-erp error-val . <message1>))"
      "       ..."
      "       ((unless <conditionm>) (er-soft+"
      "                               ctx error-erp error-val . <messagem>)))"
      "    (value <result>))"
      "  :no-function t)"
      ""
      "(defsection <name>$"
      "  :parents (<name>)"
      "  :short "Calls @(tsee <name>) with"
      "          @('ctx') and @('state') as the last two arguments.""
      "  :long "@(def <name>$)""
      "  (defmacro <name>$ (<x1'> ... <xn'> description error-erp error-val)"
      "    `(<name> ,<x1'> ... ,<xn'> description error-erp error-val ctx state)))")
    (p "where each @('<...>'),
     except @('<erp>'), @('<val>'), and @('<x1'>'), ..., @('<xn'>'),
     is supplied as argument to the macro:")
    (ul (li "@('<name>') is the name of the function,
      and, with a @('$') added at the end, the name of the macro.")
      (li "Each @('<xi>') is a symbol or
      an "
        (seetopic "std::extended-formals" "extended formal")
        ".
      Let @('<xi'>') be:
      @('<xi>') if @('<xi>') is a symbol;
      the name of the @('<xi>') extended formal otherwise.")
      (li "@('<erp>') is a "
        (seetopic "std::returns-specifiers"
          "return specifier")
        " that describes the error flag returned
      inside the "
        (seetopic "error-triple" "error triple")
        ".
      This return specifier is:
      @('(erp (implies erp (equal erp error-erp)))')
      if @('<mode>') is @(':logic'); and
      @('(erp "@('nil') or @('error-erp').")')
      if @('<mode>') is @(':program').")
      (li "@('<val>') is a "
        (seetopic "std::returns-specifiers"
          "return specifier")
        " that describes the value returned
      inside the "
        (seetopic "error-triple" "error triple")
        ".
      This return specifier depends on the @('<returns>') argument to the macro
      (see below for the complete list of arguments to the macro)
      and on @('<mode>'):
      if no @('<returns>') argument is supplied and @('<mode>') is @(':logic'),
      then @('<val>') is
      @('(val (and (implies erp (equal val error-val))
                   (implies (and (not erp) error-erp) (not val))))');
      if no @('<returns>') argument is supplied and @('<mode>') is @(':program'),
      then @('<val>') is
      @('(val "@('nil') if @('erp') is @('nil'), otherwise @('error-val').")');
      if a @('<returns>') argument is supplied,
      then @('<val>') is @('<returns>').")
      (li "@('<mode>') is either @(':logic') or @(':program').")
      (li "@('<verify-guards>') is either @('t') or @('nil').
      If @('<verify-guards>') is not supplied as argument,
      @(':verify-guards') is absent.")
      (li "@('<parents>') is a list of parent XDOC topics.
      If @('<parents>') is not supplied as argument, @(':parents') is absent.")
      (li "@('<short>') and @('<long>') are strings that document the function.
      If @('<short>') is not supplied as argument, @(':short') is absent.
      If @('<long>') is not supplied as argument, @(':long') is absent.")
      (li "Each @('<conditionj>') is a term
      whose evaluation checks a condition
      on the @('<x1>'), ..., @('<xn>') arguments.
      The conditions are checked in order.")
      (li "Each @('<messagej>') is a list that consists of
      a "
        (seetopic "fmt" "format string")
        "
      followed by up to 10 terms,
      whose values fill in the placeholders of the format string.
      Generally, one of these terms should be @('description')
      and it should correspond to a @('~@') placeholder
      in the format string,
      which is appropriate for the @(tsee msgp) type of @('description').
      The @('<messagej>') list is inserted into the @(tsee er-soft+) call,
      providing an error message when @('<conditionj>') is not satisfied
      (but the previous conditions are).")
      (li "@('<result>') is a term whose value is returned
      when all the conditions are satisfied."))
    (p "The generated formal arguments
     @('description'), @('error-erp'), and @('error-val')
     and the generated return variables @('erp') and @('val')
     are symbols with those names in the same package as
     the @('<name>') symbol used as the name of the generated function.")
    (p "The macro is called as follows:")
    (codeblock "(def-error-checker <name>"
      "  (<x1> ... <xn>)"
      "  :body ((<condition1> . <message1>) ... (<conditionm> . <messagem>))"
      "  :returns <returns> ; default not used"
      "  :result <result> ; default is nil"
      "  :mode <mode> ; default is :logic"
      "  :verify-guards <verify-guards> ; default not used"
      "  :parents <parents> ; default not used"
      "  :short <short> ; default not used"
      "  :long <long> ; default not used"
      "  )")
    (p "A table keeps track of all the successful calls to this macro,
     for "
      (seetopic "redundant-events" "redundancy")
      " checking.")))
other
(defxdoc+ def-error-checker-implementation
  :parents (def-error-checker)
  :short "Implementation of @(tsee def-error-checker)."
  :order-subtopics t
  :default-parent t)
other
(defsection def-error-checker-table
  :short "Table of successful @(tsee def-error-checker) calls."
  :long (topstring-p "This table records these calls as keys, with associated @('nil') values.
    This is used of redundancy checking.")
  (table def-error-checker-calls
    nil
    nil
    :guard (and (pseudo-event-formp key)
      (eq (car key) 'def-error-checker)
      (null val))))
other
(define def-error-checker-bindings
  ((conditions-messages true-list-listp) (error-erp symbolp "The @('error-erp') formal.")
    (error-val symbolp "The @('error-val') formal."))
  :returns (bindings true-list-listp)
  :short "Generate the @(tsee b*) bindings of the error checking function."
  :long (topstring (p "These are the")
    (codeblock "((unless <conditionj>) (er-soft+ ctx error-erp error-val . <messagej>))")
    (p "bindings,
     but a binder of the form @('(unless (not <condition>))')
     is turned into @('(when <condition>)') to improve readability."))
  (b* (((when (endp conditions-messages)) nil) (condition-message (car conditions-messages))
      (condition (car condition-message))
      (message (cdr condition-message))
      ((mv unless/when condition) (case-match condition
          (('not negated-condition) (mv 'when negated-condition))
          (& (mv 'unless condition))))
      (binding `((,UNLESS/WHEN ,CONDITION) (er-soft+ ctx ,ERROR-ERP ,ERROR-VAL ,@MESSAGE)))
      (bindings (def-error-checker-bindings (cdr conditions-messages)
          error-erp
          error-val)))
    (cons binding bindings)))
other
(define def-error-checker-x-symbols
  ((xs true-listp))
  :returns (x-symbols true-listp)
  :short "Turn each @('xi') symbol into itself
          and each @('xi') extended formal into its underlying symbol."
  (b* (((when (endp xs)) nil) (x (car xs))
      (x-symbol (if (atom x)
          x
          (car x)))
      (x-symbols (def-error-checker-x-symbols (cdr xs))))
    (cons x-symbol x-symbols)))
other
(define def-error-checker-fn
  ((name symbolp) (xs true-listp)
    returns
    (returns-supplied-p booleanp)
    (conditions-messages true-list-listp)
    result
    (mode (member-eq mode '(:logic :program)))
    (verify-guards booleanp)
    (verify-guards-supplied-p booleanp)
    (parents (symbol-listp parents))
    (parents-supplied-p booleanp)
    short
    (short-supplied-p booleanp)
    long
    (long-supplied-p booleanp)
    (def-error-checker-call pseudo-event-formp)
    state)
  :returns (function+macro pseudo-event-formp)
  :verify-guards nil
  :short "Generate the function and the macro."
  (b* (((when (assoc-equal def-error-checker-call
          (table-alist 'def-error-checker-calls (w state)))) '(value-triple :redundant)) (function-name name)
      (macro-name (add-suffix name "$"))
      (description (intern-in-package-of-symbol "DESCRIPTION" name))
      (error-erp (intern-in-package-of-symbol "ERROR-ERP" name))
      (error-val (intern-in-package-of-symbol "ERROR-VAL" name))
      (erp (intern-in-package-of-symbol "ERP" name))
      (val (intern-in-package-of-symbol "VAL" name))
      (function `(define ,FUNCTION-NAME
          (,@XS (,DESCRIPTION msgp)
            (,ERROR-ERP "Flag to return in case of error.")
            (,ERROR-VAL "Value to return in case of error.")
            (ctx "Context for errors.")
            state)
          :returns (mv ,(CASE MODE
   (:LOGIC `(,ERP (IMPLIES ,ERP (EQUAL ,ERP ,ERROR-ERP))))
   (:PROGRAM `(,ERP "@('nil') or @('error-erp')."))
   (T (IMPOSSIBLE)))
            ,(IF RETURNS-SUPPLIED-P
     RETURNS
     (CASE MODE
       (:LOGIC
        `(,VAL
          (AND (IMPLIES ,ERP (EQUAL ,VAL ,ERROR-VAL))
               (IMPLIES (AND (NOT ,ERP) ,ERROR-ERP) (NOT ,VAL)))))
       (:PROGRAM
        `(,VAL "@('nil') if @('erp') is @('nil'),
                                   otherwise @('error-val')."))
       (T (IMPOSSIBLE))))
            state)
          :mode ,MODE
          ,@(AND VERIFY-GUARDS-SUPPLIED-P (LIST :VERIFY-GUARDS VERIFY-GUARDS))
          ,@(AND PARENTS-SUPPLIED-P (LIST :PARENTS PARENTS))
          ,@(AND SHORT-SUPPLIED-P (LIST :SHORT SHORT))
          ,@(AND LONG-SUPPLIED-P (LIST :LONG LONG))
          (b* ,(DEF-ERROR-CHECKER-BINDINGS CONDITIONS-MESSAGES ERROR-ERP ERROR-VAL)
            (value ,RESULT))
          :no-function t))
      (x-symbols (def-error-checker-x-symbols xs))
      (macro `(defmacro ,MACRO-NAME
          (,@X-SYMBOLS ,DESCRIPTION ,ERROR-ERP ,ERROR-VAL)
          (list ',FUNCTION-NAME
            ,@X-SYMBOLS
            ,DESCRIPTION
            ,ERROR-ERP
            ,ERROR-VAL
            'ctx
            'state)))
      (section-short (concatenate 'string
          "Calls @(tsee "
          (string-downcase (symbol-name function-name))
          ") with @('ctx') and @('state')"
          " as the last two arguments."))
      (section-long (concatenate 'string
          "@(def "
          (string-downcase (symbol-name macro-name))
          ")"))
      (section `(defsection ,MACRO-NAME
          :parents (,FUNCTION-NAME)
          :short ,SECTION-SHORT
          :long ,SECTION-LONG
          ,MACRO)))
    `(progn ,FUNCTION ,SECTION)))
other
(defsection def-error-checker-macro-definition
  :short "Definition of the @(tsee def-error-checker) macro."
  :long (topstring-@def "def-error-checker")
  (defmacro def-error-checker
    (&whole def-error-checker-call
      name
      xs
      &key
      body
      (returns 'nil returns-supplied-p)
      (result 'nil)
      (mode ':logic)
      (verify-guards 'nil verify-guards-supplied-p)
      (parents 'nil parents-supplied-p)
      (short '"" short-supplied-p)
      (long '"" long-supplied-p))
    `(make-event (def-error-checker-fn ',NAME
        ',XS
        ',RETURNS
        ',RETURNS-SUPPLIED-P
        ',BODY
        ',RESULT
        ',MODE
        ',VERIFY-GUARDS
        ',VERIFY-GUARDS-SUPPLIED-P
        ',PARENTS
        ',PARENTS-SUPPLIED-P
        ',SHORT
        ',SHORT-SUPPLIED-P
        ',LONG
        ',LONG-SUPPLIED-P
        ',DEF-ERROR-CHECKER-CALL
        state))))