Filtering...

clone

books/std/stobjs/clone
other
(in-package "STOBJS")
other
(include-book "std/util/bstar" :dir :system)
other
(include-book "tools/rulesets" :dir :system)
other
(include-book "tools/templates" :dir :system)
other
(program)
other
(defxdoc defstobj-clone
  :parents (std/stobjs)
  :short "Create a new stobj that is @(':congruent-to') an existing (concrete
or abstract) stobj, and can be given to functions that operate on the old
stobj."
  :long "<p>@('Defstobj-clone') lets you easily introduce a new @(see stobj)
that is @(':congruent-to') an existing stobj.  This allows you to have two (or
more) copies of a stobj that coexist simultaneously.</p>

<h3>Basic Example</h3>

<p>If you want to write an algorithm that operates on two bit arrays, you might
clone the @(see bitarr) to get a second stobj, @('bitarr2').  A minimal way to
do this is:</p>

@({
    (defstobj-clone bitarr2 bitarr :suffix "2")
})

<p>This introduces:</p>

<ul>

<li>A new stobj, @('bitarr2'), which is congruent to @('bitarr'), and</li>

<li>New functions that are basically renamed @('bitarr') operations.  In
particular, whereas @('bitarr') has operations like @('get-bit') and
@('set-bit'), we'll get new functions named @('get-bit2') and
@('set-bit2').</li>

</ul>

<p>Usually you can just <b>ignore</b> these new functions.  They are added only
because of the way that ACL2 stobj definition works and, strictly speaking, are
not really necessary for anything else because you can still use the original
stobj's functions on the new stobj.</p>

<p>Ignoring the new functions is particularly useful when you have already
built up more complex functionality on top of a stobj.  That is, if you've
implemented functions like @('clear-range') and @('invert-range') or similar,
you can just use these on @('bitarr2') without reimplementing them.</p>


<h3>Renaming Accessors</h3>

<p>On the other hand, it may occasionally be useful for code clarity to rename
the new functions in some semantically meaningful way.  For instance, if your
cloned bit array will be used as a seen table, it may be convenient to use
operations like @('set-seen') instead of @('set-bit').</p>

<p>To support using such semantically meaningful names, @('defstobj-clone') has
a variety of options.  Here is a contrived example that uses all of them:</p>

@({
    (defstobj-clone fancy-bitarr bitarr
      :strsubst (("GET" . "FETCH")     ;; Substring replacements to make
                 ("SET" . "INSTALL"))  ;;   (capitalized per symbol names)
      :prefix "MY-"                      ;; Name prefix to add
      :suffix "-FOR-JUSTICE"             ;; Name suffix to add
      :pkg acl2::rewrite                   ;; Package for new symbols
                                           ;;   default: new stobj name
      )
})

<p>The result is to define new analogues of the @('bitarr') functions with the
following names:</p>

@({
      bitarrp       -->  fancy-bitarrp
      create-bitarr -->  create-fancy-bitarr
      bits-length   -->  my-bits-length-for-justice
      get-bit       -->  my-fetch-bit-for-justice
      set-bit       -->  my-install-bit-for-justice
      resize-bits   -->  my-resize-bits-for-justice
})


<h3>Alternate Syntax for Abstract Stobjs</h3>

<p>For an abstract stobj, the accessors/updaters are known as "exports".
Another way to specifying their names in the new stobj is to provide the
@(':exports') argument, which should be a list of symbols corresponding to the
exported functions from the original abstract stobj.  When this is provided,
the other keyword arguments are unused.  For example:</p>

@({
    (defstobj-clone xx-bitarr bitarr
      :exports (xx-size xx-nth !xx-nth xx-resize))
})

<p>Defines a new @('xx-bitarr') stobj with:</p>

@({
    bitarrp       --> xx-bitarrp
    create-bitarr --> create-xx-bitarr
    bits-length   --> xx-size
    get-bit       --> xx-nth
    set-bit       --> !xx-nth
    resize-bits   --> xx-resize
})")
clone-stobj-change-symbolfunction
(defun clone-stobj-change-symbol
  (sym renaming)
  (if renaming
    (b* (((list prefix
          suffix
          strsubst
          pkg) renaming) ((mv sub pkg?) (tmpl-str-sublis strsubst (symbol-name sym))))
      (intern-in-package-of-symbol (concatenate 'string
          prefix
          sub
          suffix)
        (or pkg? pkg)))
    sym))
clone-stobj-process-rename-alistfunction
(defun clone-stobj-process-rename-alist
  (rename-alist renaming)
  (if (atom rename-alist)
    nil
    (cons (list (clone-stobj-change-symbol (caar rename-alist)
          renaming)
        (clone-stobj-change-symbol (cadar rename-alist)
          renaming))
      (clone-stobj-process-rename-alist (cdr rename-alist)
        renaming))))
clone-stobj-process-fieldsfunction
(defun clone-stobj-process-fields
  (fields renaming)
  (if (atom fields)
    nil
    (cons (if (consp (car fields))
        (cons (clone-stobj-change-symbol (caar fields)
            renaming)
          (cdar fields))
        (clone-stobj-change-symbol (car fields)
          renaming))
      (clone-stobj-process-fields (cdr fields)
        renaming))))
keep-nonbool-symbolsfunction
(defun keep-nonbool-symbols
  (x)
  (if (atom x)
    nil
    (let* ((k (car x)))
      (if (and k (not (eq k t)) (symbolp k))
        (cons k
          (keep-nonbool-symbols (cdr x)))
        (keep-nonbool-symbols (cdr x))))))
stobj-field-template-fnnamesfunction
(defun stobj-field-template-fnnames
  (field-templates)
  (if (atom field-templates)
    nil
    (cons (caar field-templates)
      (append (keep-nonbool-symbols (cdddar field-templates))
        (stobj-field-template-fnnames (cdr field-templates))))))
stobj-template-fnnamesfunction
(defun stobj-template-fnnames
  (template)
  (list* (car template)
    (cadr template)
    (stobj-field-template-fnnames (caddr template))))
clone-stobj-process-argsfunction
(defun clone-stobj-process-args
  (stobjname args renaming)
  (b* (((mv erp
        field-descriptors
        key-alist) (partition-rest-and-keyword-args args
         *defstobj-keywords*)) ((when erp) (er hard?
          'defstobj-clone
          "The stobj to be cloned had bad keyword args~%"))
      (inline (assoc-eq :inline key-alist))
      (fields (clone-stobj-process-fields field-descriptors
          renaming)))
    (append fields
      (and inline (list :inline (cdr inline)))
      (list :congruent-to stobjname))))
clone-stobj-rewritefunction
(defun clone-stobj-rewrite
  (newfn oldfn formals)
  (let ((thmname (intern-in-package-of-symbol (concatenate 'string
           (symbol-name newfn)
           "-IS-"
           (symbol-name oldfn))
         newfn)))
    `((defthm ,STOBJS::THMNAME
       (equal (,STOBJS::NEWFN . ,STOBJS::FORMALS)
         (,STOBJS::OLDFN . ,STOBJS::FORMALS))
       :hints (("goal" :in-theory '(,STOBJS::NEWFN ,STOBJS::OLDFN)) (and stable-under-simplificationp
           '(:in-theory (e/d** (clone-stobj-tmp-rules))))
         (and stable-under-simplificationp
           '(:in-theory '(,STOBJS::NEWFN ,STOBJS::OLDFN (:induction ,STOBJS::NEWFN)))))) (local (add-to-ruleset! clone-stobj-tmp-rules
          ,STOBJS::THMNAME)))))
clone-stobj-rewritesfunction
(defun clone-stobj-rewrites
  (new old)
  (b* (((when (atom new)) nil) (newfn (caar new))
      (formals (cadar new))
      (oldfn (caar old)))
    (append (clone-stobj-rewrite newfn
        oldfn
        formals)
      (clone-stobj-rewrites (cdr new)
        (cdr old)))))
clone-base-stobj-fnfunction
(defun clone-base-stobj-fn
  (stobjname name
    renaming
    wrld)
  (b* ((ev-wrld (decode-logical-name stobjname wrld)) ((when (null ev-wrld)) (er hard?
          'defstobj-clone
          "Unrecognized stobjname: ~x0~%"
          stobjname))
      (event (access-event-tuple-form (cddar ev-wrld)))
      ((when (not (eq (car event) 'defstobj))) (er hard?
          'defstobj-clone
          "The event named ~x0 is not a defstobj event~%"
          stobjname))
      ((list* & & args) event)
      (name (or name
          (clone-stobj-change-symbol stobjname
            renaming)))
      (new-args (clone-stobj-process-args stobjname
          args
          renaming))
      (old-template (defstobj-template stobjname
          args
          wrld))
      (new-template (defstobj-template name
          new-args
          wrld))
      (old-defs (defstobj-axiomatic-defs stobjname
          old-template
          wrld))
      (new-defs (defstobj-axiomatic-defs name
          new-template
          wrld)))
    (list* 'encapsulate
      nil
      `(defstobj ,STOBJS::NAME . ,STOBJS::NEW-ARGS)
      '(local (def-ruleset! clone-stobj-tmp-rules nil))
      (clone-stobj-rewrites new-defs
        old-defs))))
clone-absstobj-exportsfunction
(defun clone-absstobj-exports
  (absstobj-tuples exports
    renaming
    foundation
    world)
  (b* (((when (atom absstobj-tuples)) nil) ((list* name
         logic
         exec
         updater) (car absstobj-tuples))
      (name-export-lookup (assoc-eq name exports))
      (new-sym (if name-export-lookup
          (cdr name-export-lookup)
          (clone-stobj-change-symbol name
            renaming)))
      (updater (and updater
          (b* ((updater-export-lookup (assoc-eq updater exports)))
            (if updater-export-lookup
              (cdr updater-export-lookup)
              (clone-stobj-change-symbol updater
                renaming)))))
      (protect (unprotected-export-p foundation
          exec
          world)))
    (cons `(,STOBJS::NEW-SYM :logic ,STOBJS::LOGIC
        :exec ,STOBJS::EXEC
        ,@(AND STOBJS::UPDATER `(:UPDATER ,STOBJS::UPDATER))
        :protect ,STOBJS::PROTECT)
      (clone-absstobj-exports (cdr absstobj-tuples)
        exports
        renaming
        foundation
        world))))
clone-absstobj-fnfunction
(defun clone-absstobj-fn
  (stobjname name
    renaming
    user-exports
    world)
  (b* ((abs-info (fgetprop stobjname
         'absstobj-info
         nil
         world)) (stobj-info (fgetprop stobjname
          'stobj
          nil
          world))
      (`(,STOBJS::FOUNDATION (,STOBJS::?!RECOG-NAME ,STOBJS::RECOG-LOGIC
           ,STOBJS::RECOG-EXEC)
         (,STOBJS::?!CREATOR-NAME ,STOBJS::CREATE-LOGIC
           ,STOBJS::CREATE-EXEC) . ,STOBJS::EXPORT-ABSSTOBJ-TUPLES) abs-info)
      (?pred (access stobj-property
          stobj-info
          :recognizer))
      (?create (access stobj-property stobj-info :creator))
      (?exports (access stobj-property stobj-info :names))
      (exports (and user-exports
          (pairlis$ (strip-cars export-absstobj-tuples)
            user-exports)))
      (creator (defstobj-fnname name :creator :top nil))
      (recognizer (defstobj-fnname name :recognizer :top nil)))
    `(defabsstobj ,STOBJS::NAME
      :foundation ,STOBJS::FOUNDATION
      :recognizer (,STOBJS::RECOGNIZER :logic ,STOBJS::RECOG-LOGIC
        :exec ,STOBJS::RECOG-EXEC)
      :creator (,STOBJS::CREATOR :logic ,STOBJS::CREATE-LOGIC
        :exec ,STOBJS::CREATE-EXEC)
      :exports ,(STOBJS::CLONE-ABSSTOBJ-EXPORTS STOBJS::EXPORT-ABSSTOBJ-TUPLES STOBJS::EXPORTS
  STOBJS::RENAMING STOBJS::FOUNDATION STOBJS::WORLD)
      :congruent-to ,STOBJS::STOBJNAME)))
clone-stobj-fnfunction
(defun clone-stobj-fn
  (stobjname name
    prefix
    suffix
    strsubst
    pkg
    exports
    world)
  (declare (xargs :guard (and (stringp prefix)
        (stringp suffix)
        (alistp strsubst)
        (string-listp (strip-cars strsubst))
        (string-listp (strip-cdrs strsubst))
        (symbol-listp exports)
        (symbolp pkg)
        (not (and (equal prefix "")
            (equal suffix "")
            (not strsubst)
            (not exports)
            (not pkg))))))
  (b* ((stobjp (fgetprop stobjname
         'stobj
         nil
         world)) (absstobjp (fgetprop stobjname
          'absstobj-info
          nil
          world))
      (pkg (or pkg name))
      (renaming (and (not exports)
          (list prefix
            suffix
            strsubst
            pkg)))
      ((unless stobjp) (er hard?
          'defstobj-clone
          "~x0 is not a stobj~%"
          stobjname)))
    (if absstobjp
      (clone-absstobj-fn stobjname
        name
        renaming
        exports
        world)
      (if exports
        (er hard?
          'defstobj-clone
          ":Exports is not supported for concrete stobjs")
        (clone-base-stobj-fn stobjname
          name
          renaming
          world)))))
defstobj-clonemacro
(defmacro defstobj-clone
  (newname origname
    &key
    strsubst
    (prefix '"")
    (suffix '"")
    pkg
    exports)
  `(make-event (clone-stobj-fn ',STOBJS::ORIGNAME
      ',STOBJS::NEWNAME
      ',STOBJS::PREFIX
      ',STOBJS::SUFFIX
      ',STOBJS::STRSUBST
      ',STOBJS::PKG
      ',STOBJS::EXPORTS
      (w state))))