#|$ACL2s-Preamble$;
(ld ;; Newline to fool dependency scanner
  "hacker-pkg.lsp")

(include-book ;; Newline to fool dependency scanner
   "defcode" :ttags ((defcode)))

(acl2::begin-book t :ttags ((defcode)));$ACL2s-Preamble$|#

(in-package "ACL2")

(program)
(set-state-ok t)

; a helper macro for building other stuff
(defmacro make-raw-definitions (code &key compile fresh
                                save-fns save-macros save-vars)
  (declare (xargs :guard (and (true-listp code)
                              (or (booleanp compile)
                                  (true-listp compile))
                              (or (booleanp fresh)
                                  (symbol-listp fresh))
                              (symbol-listp save-fns)
                              (symbol-listp save-macros)
                              (symbol-listp save-vars))))
  (let* ((all-saves (append save-fns save-macros save-vars))
         (fresh-lst (if (eq fresh 't) all-saves fresh)))
    `(with-output
      :off summary
      (progn
       ,@ (and fresh-lst
               `((assert-unbound . ,fresh-lst)
                 (deflabels . ,fresh-lst)))
       ,@ (and save-fns
               `((ensure-special-raw-definition-flag . ,save-fns)))
       (defcode
         :extend
         (in-raw-mode ,@ (and save-fns
                              `((dolist (f ',save-fns)
                                        (maybe-push-undo-stack 'defun f))))
                      ,@ (and save-macros
                              `((dolist (m ',save-macros)
                                        (maybe-push-undo-stack 'defmacro m))))
                      ,@ (and save-vars
                              `((dolist (v ',save-vars)
                                        (maybe-push-undo-stack 'defconst v))))
                      ,@ code)
         :retract
         ,(and all-saves
               `(in-raw-mode (dolist (s ',all-saves)
                                     (maybe-pop-undo-stack s))))
         :compile
         (progn . ,(if (eq compile 't) code compile)))))))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; some low-level pieces for building high-level abstractions
;
;

(defmacro defun-raw (name ll &rest rst)
  `(make-raw-definitions
    ((defun ,name ,ll . ,rst))
    :compile t
    :fresh t
    :save-fns (,name)))


(defmacro defmacro-raw (name ll &rest rst)
  `(make-raw-definitions
    ((defmacro ,name ,ll . ,rst))
    :compile t
    :fresh t
    :save-macros (,name)))


(defmacro copy-raw-defun (src dst)
  `(make-raw-definitions
    ((setf (symbol-function ',dst)
           (symbol-function ',src)))
    :compile nil
    :fresh t
    :save-fns (,dst)))


(defmacro copy-raw-defmacro (src dst)
  `(make-raw-definitions
    ((setf (macro-function ',dst)
           (macro-function ',src)))
    :compile nil
    :fresh t
    :save-macros (,dst)))


(defmacro defvar-raw (&whole form name &optional initial-val doc)
  (declare (ignore initial-val doc)
           (xargs :guard (symbolp name)))
  `(make-raw-definitions
    ((defvar . ,(cdr form)))
    :compile nil
    :fresh t
    :save-vars (,name)))


(defmacro defparameter-raw (&whole form name initial-val &optional doc)
  (declare (ignore initial-val doc)
           (xargs :guard (symbolp name)))
  `(make-raw-definitions
    ((defparameter . ,(cdr form)))
    :compile nil
    :fresh t
    :save-vars (,name)))


(defmacro defconstant-raw (&whole form name initial-val &optional doc)
  (declare (ignore initial-val doc)
           (xargs :guard (symbolp name)))
  `(make-raw-definitions
    ((defconstant . ,(cdr form)))
    :compile nil
    :fresh t
    :save-vars (,name)))



; include how to figure out what functions a defstruct defines
(include-book "defstruct-parsing")

(defmacro defstruct-raw (&rest args)
  (declare (xargs :guard args))
  (let* ((form (cons 'defstruct args))
         (name-and-fns (acl2-hacker::defstruct-name-and-fns form)))
    (if (consp name-and-fns)
      `(make-raw-definitions
        (,form)
        :compile nil
        :fresh ,name-and-fns
        :save-fns ,(cdr name-and-fns))
      `(er hard 'defstruct-raw
           "Unrecognized defstruct definition form:~%~x0~%"
           ',form))))

#| ; killed because of OpenMCL issues
(defun raw-only-definitions1 (revremforms all-forms compile fresh
                              save-fns save-macros save-vars)
  (if (endp revremforms)
    (let* ((fresh-no-dups (remove-duplicates-eql fresh))
           (main `(make-raw-definitions
                   ,all-forms
                   :compile ,compile 
                   :fresh ,fresh-no-dups
                   :save-fns ,save-fns
                   :save-macros ,save-macros
                   :save-vars ,save-vars)))
      (if (equal fresh-no-dups fresh)
        main
        (let ((dups (duplicates fresh)))
          `(progn (value-triple (cw "Warning: Some names are being defined more than once in raw lisp:~%~x0~%" ',dups))
                  ,main))))
    (let ((form (car revremforms))
          (rst (cdr revremforms)))
      (cond ((and (consp form)
                  (eq 'defun (car form))
                  (>= (len form) 4)
                  (symbolp (cadr form)))
             (raw-only-definitions1
              rst
              all-forms
              (cons form compile)
              (cons (cadr form) fresh)
              (cons (cadr form) save-fns)
              save-macros
              save-vars))
            ((and (consp form)
                  (eq 'defmacro (car form))
                  (>= (len form) 4)
                  (symbolp (cadr form)))
             (raw-only-definitions1
              rst
              all-forms
              (cons form compile)
              (cons (cadr form) fresh)
              save-fns
              (cons (cadr form) save-macros)
              save-vars))
            ((and (consp form)
                  (or (eq 'defvar (car form))
                      (eq 'defparameter (car form)))
                  (>= (len form) 2)
                  (symbolp (cadr form)))
             (raw-only-definitions1
              rst
              all-forms
              compile ; don't compile
              (cons (cadr form) fresh)
              save-fns
              save-macros
              (cons (cadr form) save-vars)))
            ((and (consp form)
                  (eq 'defstruct (car form))
                  (>= (len form) 2))
             (let ((name-and-fns (acl2-hacker::defstruct-name-and-fns form)))
               (if (consp name-and-fns)
                 (raw-only-definitions1
                  rst
                  all-forms
                  compile ; don't compile
                  (append name-and-fns fresh)
                  (append (cdr name-and-fns) save-fns)
                  save-macros
                  save-vars)
                 `(progn! (er soft
                          'raw-only-definitions
                          "Unrecognized defstruct definition form:~%~x0~%"
                          ',form)))))
            (t
             `(progn! (er soft
                          'raw-only-definitions
                          "Unrecognized raw definition form:~%~x0~%"
                          ',form)))))))

(defmacro raw-only-definitions (&rest forms)
  (raw-only-definitions1 (reverse forms) forms nil nil nil nil nil))
|#


(defmacro modify-raw-defun
  (name name-for-old ll &rest decls-and-body)
  (declare (xargs :guard (and (symbolp name)
                              (symbolp name-for-old)
                              (symbol-listp ll)
                              (consp decls-and-body))))
  `(progn (copy-raw-defun ,name ,name-for-old)
          (make-raw-definitions
           ((defun ,name ,ll 
              ,@ (and ll `((declare (ignorable . ,ll))))
              . ,decls-and-body))
           :compile t
           :fresh nil
           :save-fns (,name))))

; tests & stuff:
#|
(include-book
 "defcode" :ttags :all)

(defttag t)

(defstruct-raw foo bar)

(modify-raw-defun foo-bar old-foo-bar (s)
                  (progn (format t "Foobar!~%")
                         (old-foo-bar s)))

(set-raw-mode t)

(foo-bar (make-foo :bar 42))

|#