Filtering...

messages

books/kestrel/utilities/messages

Included Books

other
(in-package "ACL2")
include-book
(include-book "std/strings/case-conversion" :dir :system)
include-book
(include-book "std/util/define" :dir :system)
include-book
(include-book "std/util/deflist" :dir :system)
include-book
(include-book "std/util/defrule" :dir :system)
include-book
(include-book "xdoc/constructors" :dir :system)
local
(local (include-book "kestrel/built-ins/disable" :dir :system))
local
(local (disable-most-builtin-logic-defuns))
local
(local (disable-builtin-rewrite-rules-for-defaults))
local
(local (in-theory (disable (tau-system))))
other
(set-induction-depth-limit 0)
local
(local (include-book "kestrel/alists-light/acons" :dir :system))
local
(local (include-book "kestrel/alists-light/assoc-equal" :dir :system))
local
(local (include-book "kestrel/strings-light/char" :dir :system))
local
(local (include-book "kestrel/utilities/acl2-count" :dir :system))
local
(local (include-book "kestrel/utilities/msgp" :dir :system))
local
(local (include-book "kestrel/utilities/ordinals" :dir :system))
other
(make-define-config :no-function t)
other
(defxdoc message-utilities
  :parents (kestrel-utilities)
  :short "Utilities for <see topic='@(url msgp)'>messages</see>.")
other
(defxdoc msg$
  :parents (msg message-utilities)
  :short "A variant of @('msg') which is easier to reason about."
  :long (topstring (p "@('msg$') is a macro which will rewrite to a call of @('msg$-logic').
       @('msg$-logic') is kept disabled and is known to produce a
       @('msgp'). For execution, @('msg$') expands to something which is
       inlined for efficiency.")))
other
(define maybe-msgp
  (x)
  :returns (yes/no booleanp)
  :parents (message-utilities)
  :short "Recognize @('nil') and messages."
  (or (msgp x) (null x))
  ///
  (defrule maybe-msgp-compound-recognizer
    (if (maybe-msgp x)
      (or (equal x nil)
        (stringp x)
        (and (consp x) (true-listp x)))
      (and (not (equal x nil)) (not (stringp x))))
    :rule-classes :compound-recognizer)
  (defrule maybe-msgp-when-msgp
    (implies (msgp x) (maybe-msgp x))))
other
(deflist msg-listp
  (x)
  (msgp x)
  :parents (message-utilities)
  :short "Recognize true lists of messages."
  :true-listp t
  :elementp-of-nil nil)
other
(define msg-fix
  ((msg msgp))
  :returns (msg$ msgp)
  (mbe :logic (if (msgp msg)
      msg
      "")
    :exec (the (or string cons) msg))
  :inline t)
in-theory
(in-theory (disable (:t msg-fix)))
msg-fix-type-prescriptiontheorem
(defrule msg-fix-type-prescription
  (or (stringp (msg-fix msg))
    (and (consp (msg-fix msg)) (true-listp (msg-fix msg))))
  :rule-classes :type-prescription :enable msg-fix)
msg-fix-when-msgptheorem
(defrule msg-fix-when-msgp
  (implies (msgp msg) (equal (msg-fix msg) msg))
  :enable msg-fix)
other
(defruled msg-fix-when-not-msgp
  (implies (not (msgp msg)) (equal (msg-fix msg) ""))
  :enable msg-fix)
msg-fix-when-not-msgp-cheaptheorem
(defrule msg-fix-when-not-msgp-cheap
  (implies (not (msgp msg)) (equal (msg-fix msg) ""))
  :rule-classes ((:rewrite :backchain-limit-lst (0)))
  :by msg-fix-when-not-msgp)
stringp-of-car-of-msg-fixtheorem
(defrule stringp-of-car-of-msg-fix
  (equal (stringp (car (msg-fix msg)))
    (not (stringp (msg-fix msg))))
  :enable msg-fix)
character-alistp-of-cdr-of-msg-fixtheorem
(defrule character-alistp-of-cdr-of-msg-fix
  (character-alistp (cdr (msg-fix msg)))
  :enable (msg-fix msgp character-alistp))
alistp-of-cdr-of-msg-fixtheorem
(defrule alistp-of-cdr-of-msg-fix
  (alistp (cdr (msg-fix msg)))
  :enable (msg-fix msgp alistp))
other
(define msg$0
  ((str stringp))
  (mbe :logic (if (stringp str)
      str
      "")
    :exec str)
  :inline t)
other
(define msg$1
  ((str stringp) arg0)
  (msg (mbe :logic (if (stringp str)
        str
        "")
      :exec str)
    arg0)
  :inline t)
other
(define msg$2
  ((str stringp) arg0 arg1)
  (msg (mbe :logic (if (stringp str)
        str
        "")
      :exec str)
    arg0
    arg1)
  :inline t)
other
(define msg$3
  ((str stringp) arg0 arg1 arg2)
  (msg (mbe :logic (if (stringp str)
        str
        "")
      :exec str)
    arg0
    arg1
    arg2)
  :inline t)
other
(define msg$4
  ((str stringp) arg0 arg1 arg2 arg3)
  (msg (mbe :logic (if (stringp str)
        str
        "")
      :exec str)
    arg0
    arg1
    arg2
    arg3)
  :inline t)
other
(define msg$5
  ((str stringp) arg0 arg1 arg2 arg3 arg4)
  (msg (mbe :logic (if (stringp str)
        str
        "")
      :exec str)
    arg0
    arg1
    arg2
    arg3
    arg4)
  :inline t)
other
(define msg$6
  ((str stringp) arg0 arg1 arg2 arg3 arg4 arg5)
  (msg (mbe :logic (if (stringp str)
        str
        "")
      :exec str)
    arg0
    arg1
    arg2
    arg3
    arg4
    arg5)
  :inline t)
other
(define msg$7
  ((str stringp) arg0 arg1 arg2 arg3 arg4 arg5 arg6)
  (msg (mbe :logic (if (stringp str)
        str
        "")
      :exec str)
    arg0
    arg1
    arg2
    arg3
    arg4
    arg5
    arg6)
  :inline t)
other
(define msg$8
  ((str stringp) arg0 arg1 arg2 arg3 arg4 arg5 arg6 arg7)
  (msg (mbe :logic (if (stringp str)
        str
        "")
      :exec str)
    arg0
    arg1
    arg2
    arg3
    arg4
    arg5
    arg6
    arg7)
  :inline t)
other
(define msg$9
  ((str stringp) arg0 arg1 arg2 arg3 arg4 arg5 arg6 arg7 arg8)
  (msg (mbe :logic (if (stringp str)
        str
        "")
      :exec str)
    arg0
    arg1
    arg2
    arg3
    arg4
    arg5
    arg6
    arg7
    arg8)
  :inline t)
other
(define msg$10
  ((str stringp) arg0
    arg1
    arg2
    arg3
    arg4
    arg5
    arg6
    arg7
    arg8
    arg9)
  (msg (mbe :logic (if (stringp str)
        str
        "")
      :exec str)
    arg0
    arg1
    arg2
    arg3
    arg4
    arg5
    arg6
    arg7
    arg8
    arg9)
  :inline t)
other
(define msg$-logic
  (str args)
  (declare (xargs :type-prescription (or (stringp (msg$-logic str args))
        (and (consp (msg$-logic str args))
          (true-listp (msg$-logic str args))))
      :guard (hide (comment "msg$-logic is not intended to be used in code. Use msg$ instead."
          (true-listp args)))
      :guard-hints (("Goal" :expand ((:free (x) (hide x)))))))
  :returns (msg msgp :hints (("Goal" :in-theory (enable msgp))))
  (if (consp args)
    (cons (if (stringp str)
        str
        "")
      (if (<= (len args) 10)
        (pairlis$ (take (len args) *base-10-chars*) args)
        nil))
    (if (stringp str)
      str
      ""))
  :prepwork ((defrulel character-alistp-of-pairlis$
     (implies (and (character-listp x) (equal (len x) (len y)))
       (character-alistp (pairlis$ x y)))
     :induct t
     :enable (pairlis$ character-alistp character-listp len))))
msg$0-becomes-msg$-logictheorem
(defrule msg$0-becomes-msg$-logic
  (equal (msg$0 str) (msg$-logic str nil))
  :enable (msg$0 msg$-logic))
msg$1-becomes-msg$-logictheorem
(defrule msg$1-becomes-msg$-logic
  (equal (msg$1 str arg0) (msg$-logic str (list arg0)))
  :enable (msg$1 msg$-logic len pairlis$))
msg$2-becomes-msg$-logictheorem
(defrule msg$2-becomes-msg$-logic
  (equal (msg$2 str arg0 arg1)
    (msg$-logic str (list arg0 arg1)))
  :enable (msg$2 msg$-logic len pairlis$))
msg$3-becomes-msg$-logictheorem
(defrule msg$3-becomes-msg$-logic
  (equal (msg$3 str arg0 arg1 arg2)
    (msg$-logic str (list arg0 arg1 arg2)))
  :enable (msg$3 msg$-logic len pairlis$))
msg$4-becomes-msg$-logictheorem
(defrule msg$4-becomes-msg$-logic
  (equal (msg$4 str arg0 arg1 arg2 arg3)
    (msg$-logic str (list arg0 arg1 arg2 arg3)))
  :enable (msg$4 msg$-logic len pairlis$))
msg$5-becomes-msg$-logictheorem
(defrule msg$5-becomes-msg$-logic
  (equal (msg$5 str arg0 arg1 arg2 arg3 arg4)
    (msg$-logic str (list arg0 arg1 arg2 arg3 arg4)))
  :enable (msg$5 msg$-logic len pairlis$))
msg$6-becomes-msg$-logictheorem
(defrule msg$6-becomes-msg$-logic
  (equal (msg$6 str arg0 arg1 arg2 arg3 arg4 arg5)
    (msg$-logic str (list arg0 arg1 arg2 arg3 arg4 arg5)))
  :enable (msg$6 msg$-logic len pairlis$))
msg$7-becomes-msg$-logictheorem
(defrule msg$7-becomes-msg$-logic
  (equal (msg$7 str arg0 arg1 arg2 arg3 arg4 arg5 arg6)
    (msg$-logic str (list arg0 arg1 arg2 arg3 arg4 arg5 arg6)))
  :enable (msg$7 msg$-logic len pairlis$))
msg$8-becomes-msg$-logictheorem
(defrule msg$8-becomes-msg$-logic
  (equal (msg$8 str arg0 arg1 arg2 arg3 arg4 arg5 arg6 arg7)
    (msg$-logic str
      (list arg0 arg1 arg2 arg3 arg4 arg5 arg6 arg7)))
  :enable (msg$8 msg$-logic len pairlis$))
msg$9-becomes-msg$-logictheorem
(defrule msg$9-becomes-msg$-logic
  (equal (msg$9 str arg0 arg1 arg2 arg3 arg4 arg5 arg6 arg7 arg8)
    (msg$-logic str
      (list arg0 arg1 arg2 arg3 arg4 arg5 arg6 arg7 arg8)))
  :enable (msg$9 msg$-logic len pairlis$))
msg$10-becomes-msg$-logictheorem
(defrule msg$10-becomes-msg$-logic
  (equal (msg$10 str
      arg0
      arg1
      arg2
      arg3
      arg4
      arg5
      arg6
      arg7
      arg8
      arg9)
    (msg$-logic str
      (list arg0 arg1 arg2 arg3 arg4 arg5 arg6 arg7 arg8 arg9)))
  :enable (msg$10 msg$-logic len pairlis$))
msg$macro
(defmacro msg$
  (str &rest args)
  (declare (xargs :guard (<= (len args) 10)))
  (case (len args)
    (0 (list 'msg$0 str))
    (1 (list 'msg$1 str (first args)))
    (2 (list 'msg$2 str (first args) (second args)))
    (3 (list 'msg$3 str (first args) (second args) (third args)))
    (4 (list 'msg$4
        str
        (first args)
        (second args)
        (third args)
        (fourth args)))
    (5 (list 'msg$5
        str
        (first args)
        (second args)
        (third args)
        (fourth args)
        (fifth args)))
    (6 (list 'msg$6
        str
        (first args)
        (second args)
        (third args)
        (fourth args)
        (fifth args)
        (sixth args)))
    (7 (list 'msg$7
        str
        (first args)
        (second args)
        (third args)
        (fourth args)
        (fifth args)
        (sixth args)
        (seventh args)))
    (8 (list 'msg$8
        str
        (first args)
        (second args)
        (third args)
        (fourth args)
        (fifth args)
        (sixth args)
        (seventh args)
        (eighth args)))
    (9 (list 'msg$9
        str
        (first args)
        (second args)
        (third args)
        (fourth args)
        (fifth args)
        (sixth args)
        (seventh args)
        (eighth args)
        (ninth args)))
    (10 (list 'msg$10
        str
        (first args)
        (second args)
        (third args)
        (fourth args)
        (fifth args)
        (sixth args)
        (seventh args)
        (eighth args)
        (ninth args)
        (tenth args)))
    (otherwise nil)))
retmsg$macro
(defmacro retmsg$
  (str &rest args)
  (declare (xargs :guard (<= (len args) 10)))
  `(reterr (msg$ ,STR ,@ARGS)))
other
(define msg-downcase-first
  ((msg msgp))
  :returns (new-msg msgp
    :hints (("Goal" :induct t :in-theory (enable character-alistp))))
  :parents (message-utilities)
  :short "Convert the first character
          of a <see topic='@(url msg)'>structured message</see>
          to lower case."
  :long "<p>
   If the message is a string,
   we use @(tsee str::downcase-first) on the string.
   </p>
   <p>
   Otherwise, if the format string of the message
   does not start with a tilde-directive (see @(tsee fmt)),
   we use @(tsee str::downcase-first) on the format string.
   </p>
   <p>
   Otherwise, we need to look at the tilde-directive
   that starts the format string of the message,
   and possibly modify the tilde-directive
   and the corresponding value in the alist,
   in order to suitably convert the first character
   of the resulting formatted string to lower case.
   This is done as follows:
   </p>
   <ul>
     <li>
     If the command character of the tilde-directive is
     @('x'), @('y'), @('X'), @('Y'), @('f'), or @('F'),
     we leave the message unchanged because
     these directives prints all the ACL2 values in a way that
     capitalization does not really apply:
     numbers are not words,
     symbols are in all caps or start with @('|'),
     characters start with @('#'),
     strings start with @('"'),
     and @(tsee cons) pairs start with @('(').
     </li>
     <li>
     If the command character of the tilde-directive is
     @('t'), @('c'), space, @('_'), newline, @('%'), @('|'), @('~'), or @('-'),
     we leave the message unchanged because
     these directives do not print words.
     </li>
     <li>
     If the command character of the tilde-directive is @('n'),
     we leave the message unchanged because that directive
     already prints words that start with lower case characters.
     </li>
     <li>
     If the command character of the tilde-directive is @('N'),
     we replace it with @('n').
     </li>
     <li>
     If the command character of the tilde-directive is @('@'),
     we find the corresponding message in the alist
     and we recursively process it with this function.
     </li>
     <li>
     If the command character of the tilde-directive is @('s') or @('S'),
     we find the corresponding string or symbol in the alist,
     and if it is a string we use @(tsee str::downcase-first) on it.
     If instead it is a symbol, we leave the message unchanged
     because symbols are in all caps or start with @('|')
     (as in the case of the @('x') and other command characters above).
     </li>
     <li>
     If the command character of the tilde-directive is
     @('#'), @('*'), @('&'), or @('v'),
     we stop with an error:
     these directives are currently not supported by the implementation.
     </li>
   </ul>
   <p>
   Since @(tsee msgp) is a weak recognizer for messages,
   there is no guarantee that the format string is followed by an alist,
   and that the values in the alist have the appropriate types.
   This function leaves the message unchanged
   if some of these properties do not hold.
   </p>"
  (b* ((msg (msg-fix msg)) ((when (stringp msg)) (downcase-first msg))
      ((cons string alist) msg)
      ((unless (and (> (length string) 0) (eql (char string 0) #\~))) (cons (downcase-first string) alist))
      ((unless (and (>= (length string) 3)
           (member (char string 1)
             (list #\@ #\# #\* #\& #\v #\N #\s #\S)))) msg))
    (case (char string 1)
      (#\@ (b* (((unless (alistp alist)) msg) (value (cdr (assoc (char string 2) alist)))
            ((unless (msgp value)) msg)
            (new-alist (acons (char string 2) (msg-downcase-first value) alist)))
          (cons string new-alist)))
      (#\N (b* ((new-string (concatenate 'string "~n" (subseq string 2 nil))))
          (cons new-string alist)))
      ((#\s #\S) (b* (((unless (alistp alist)) msg) (value (cdr (assoc (char string 2) alist)))
            ((unless (stringp value)) msg)
            (new-alist (acons (char string 2) (downcase-first value) alist)))
          (cons string new-alist)))
      (otherwise (prog2$ (raise "Message not supported: ~x0" msg) msg))))
  :no-function nil
  :measure (acl2-count (msg-fix msg)))
other
(define msg-upcase-first
  ((msg msgp))
  :returns (new-msg msgp
    :hints (("Goal" :induct t :in-theory (enable character-alistp))))
  :parents (message-utilities)
  :short "Convert the first character
          of a <see topic='@(url msg)'>structured message</see>
          to upper case."
  :long "<p>
   This is analogous to @(tsee msg-downcase-first),
   but we use @(tsee str::upcase-first) instead of @(tsee str::downcase-first)
   on the strings,
   and the roles of the @('n') and @('N') command characters
   of the tilde-directives are swapped.
   See the documentation of @(tsee msg-downcase-first).
   </p>"
  (b* ((msg (msg-fix msg)) ((when (stringp msg)) (upcase-first msg))
      ((cons string alist) msg)
      ((unless (and (> (length string) 0) (eql (char string 0) #\~))) (cons (upcase-first string) alist))
      ((unless (and (>= (length string) 3)
           (member (char string 1)
             (list #\@ #\# #\* #\& #\v #\n #\s #\S)))) msg))
    (case (char string 1)
      (#\@ (b* (((unless (alistp alist)) msg) (value (cdr (assoc (char string 2) alist)))
            ((unless (msgp value)) msg)
            (new-alist (acons (char string 2) (msg-upcase-first value) alist)))
          (cons string new-alist)))
      (#\n (b* ((new-string (concatenate 'string "~N" (subseq string 2 nil))))
          (cons new-string alist)))
      ((#\s #\S) (b* (((unless (alistp alist)) msg) (value (cdr (assoc (char string 2) alist)))
            ((unless (stringp value)) msg)
            (new-alist (acons (char string 2) (upcase-first value) alist)))
          (cons string new-alist)))
      (otherwise (prog2$ (raise "Message not supported: ~x0" msg) msg))))
  :no-function nil
  :measure (acl2-count (msg-fix msg)))