
;;;  syntax.lisp                               Warren A. Hunt, Jr.

(in-package "ACL2")
(include-book "primitives")

(deflabel syntax-defuns-section)

;;;  A module is the representation of a non-primitive FSM.  It is
;;;  composed of five elements:  name, inputs, outputs, states, and
;;;  occurrences.  Each occurrence is itself composed of four pieces:
;;;  name, outputs, primitive or module reference, and inputs.  The
;;;  following macros are the destructor operations for accessing the
;;;  various pieces of a module.

(deflabel md-accessors-defuns-section)

(defun md-name   (x)
  (declare (xargs :guard (consp-n+1 x 0)))
  (car x))

(defun md-ins    (x)
  (declare (xargs :guard (consp-n+1 x 1)))
  (cadr x))

(defun md-outs   (x)
  (declare (xargs :guard (consp-n+1 x 2)))
  (caddr x))

(defun md-sts    (x)
  (declare (xargs :guard (consp-n+1 x 3)))
  (cadddr x))

(defun md-occs   (x)
  (declare (xargs :guard (consp-n+1 x 4)))
  (car (cddddr x)))

(deftheory md-accessors-defuns
  (set-difference-theories (current-theory :here)
			   (current-theory 'md-accessors-defuns-section)))

(deflabel occ-accessors-defuns-section)

(defun occ-name  (x)
  (declare (xargs :guard (consp-n+1 x 0)))
  (car x))

(defun occ-outs  (x)
  (declare (xargs :guard (consp-n+1 x 1)))
  (cadr x))

(defun occ-fn    (x)
  (declare (xargs :guard (consp-n+1 x 2)))
  (caddr x))

(defun occ-ins   (x)
  (declare (xargs :guard (consp-n+1 x 3)))
  (cadddr x))

(deftheory occ-accessors-defuns
  (set-difference-theories (current-theory :here)
			   (current-theory 'occ-accessors-defuns-section)))

;;;  We define the syntactic restrictions for occurrences and modules.

(defun occ-syntax-okp (occ)
  (declare (xargs :guard t))
  (and (true-listp-at-least-n+1 occ 3)
       (let ((occ-name (occ-name occ))
             (occ-outs (occ-outs occ))
             (occ-fn   (occ-fn   occ))
             (occ-ins  (occ-ins  occ)))
         (and (symbolp           occ-name)
              (symbol-listp      occ-outs)
              (no-duplicatesp-eq occ-outs)
              (symbolp           occ-fn)
              (symbol-listp      occ-ins)))))

;;;  For the lemmas that follow, it is important that the "occ" functions
;;;  are disabled or they will not fire.

(defthm occ-name-info
  (implies (occ-syntax-okp occ)
	   (symbolp (occ-name occ))))

(defthm occ-outs-info
  (implies (occ-syntax-okp occ)
	   (and (symbol-listp      (occ-outs occ))
		(no-duplicatesp-eq (occ-outs occ)))))

(defthm occ-fn-info
  (implies (occ-syntax-okp occ)
	   (symbolp (occ-fn occ))))

(defthm occ-ins-info
  (implies (occ-syntax-okp occ)
	   (symbol-listp  (occ-ins occ))))

(defthm cons-size-occ-lessp-eql
  (and (<= (cons-size (occ-name occ))
	   (cons-size occ))
       (<= (cons-size (occ-outs occ))
	   (cons-size occ))
       (<= (cons-size (occ-fn   occ))
	   (cons-size occ))
       (<= (cons-size (occ-ins  occ))
	   (cons-size occ)))
  :rule-classes (:linear))

(defthm cons-size-occ-lessp
  (implies (consp occ)
	   (and (< (cons-size (occ-name occ))
		   (cons-size occ))
		(< (cons-size (occ-outs occ))
		   (cons-size occ))
		(< (cons-size (occ-fn   occ))
		   (cons-size occ))
		(< (cons-size (occ-ins  occ))
		   (cons-size occ))))
  :rule-classes (:linear))

(in-theory (disable occ-accessors-defuns))
(in-theory (disable occ-syntax-okp))

(defun occs-syntax-okp (occs)
  (declare (xargs :guard t))
  (if (atom occs)
      (eq occs nil)
    (and (occ-syntax-okp (car occs))
         (occs-syntax-okp (cdr occs)))))

(defun module-syntax-okp (module)
  (declare (xargs :guard t))
  (and (true-listp-at-least-n+1 module 4)
       (let ((md-name   (md-name   module))
             (md-ins    (md-ins    module))
             (md-outs   (md-outs   module))
             (md-sts    (md-sts    module))
             (md-occs   (md-occs   module)))
         (and (symbolp           md-name)
              (symbol-listp      md-ins)
              (no-duplicatesp-eq md-ins)
              (symbol-listp      md-outs)
              (no-duplicatesp-eq md-outs)
              (symbol-listp      md-sts)
              (no-duplicatesp-eq md-sts)
              (symbol-alistp     md-occs)
              ;; (consp             md-ins)    ; One input?
              ;; (consp             md-outs)   ; One output?
              (consp             md-occs)   ; One occurrence?
              (occs-syntax-okp md-occs)))))

;;;  For the lemmas that follow, it is important that the "md" functions
;;;  are disabled or they will not fire.

(defthm md-name-info
  (implies (module-syntax-okp module)
	   (symbolp (md-name module))))

(defthm md-ins-info
  (implies (module-syntax-okp module)
	   (and (symbol-listp      (md-ins module))
		(true-listp        (md-outs module))
		(no-duplicatesp-eq (md-ins module)))))

(defthm md-outs-info
  (implies (module-syntax-okp module)
	   (and (symbol-listp      (md-outs module))
		(true-listp        (md-outs module))
		(no-duplicatesp-eq (md-outs module)))))

;;;   :monitor (:rewrite md-outs-info) t

(defthm md-sts-info
  (implies (module-syntax-okp module)
	   (and (symbol-listp      (md-sts module))
		(true-listp        (md-outs module))
		(no-duplicatesp-eq (md-sts module)))))

(defthm md-occs-info
  (implies (module-syntax-okp module)
	   (and (symbol-alistp    (md-occs module))
		(true-listp        (md-outs module))
		(occs-syntax-okp  (md-occs module)))))

(defthm cons-size-md-lessp-eql
  (and (<= (cons-size (md-name module))
	   (cons-size module))
       (<= (cons-size (md-ins  module))
	   (cons-size module))
       (<= (cons-size (md-outs module))
	   (cons-size module))
       (<= (cons-size (md-sts  module))
	   (cons-size module))
       (<= (cons-size (md-occs module))
	   (cons-size module)))
  :rule-classes (:linear))

(defthm cons-size-md-lessp
  (implies (consp module)
	   (and (<= (cons-size (md-name module))
		    (cons-size module))
		(<= (cons-size (md-ins  module))
		    (cons-size module))
		(<= (cons-size (md-outs module))
		    (cons-size module))
		(<= (cons-size (md-sts  module))
		    (cons-size module))
		(<= (cons-size (md-occs module))
		    (cons-size module))))
  :rule-classes (:linear))

(in-theory (disable md-accessors-defuns))
(in-theory (disable module-syntax-okp))

(defun net-syntax-okp (netlist)
  (declare (xargs :guard t))
  (if (atom netlist)
      (eq netlist nil)
    (and (module-syntax-okp (car netlist))
         (net-syntax-okp (cdr netlist)))))

;;;  Here are a couple of forward chaining rules.  Do I really need them
;;;  after proving everything above?

(defthm occ-syntax-okp-forward
  (implies (occ-syntax-okp occ)
           (and (true-listp-at-least-n+1 occ 3)
                (let ((occ-name (occ-name occ))
                      (occ-outs (occ-outs occ))
                      (occ-fn   (occ-fn   occ))
                      (occ-ins  (occ-ins  occ)))
                  (and (symbolp           occ-name)
                       (symbol-listp      occ-outs)
                       (no-duplicatesp-eq occ-outs)
                       (symbolp           occ-fn)
                       (symbol-listp      occ-ins)))))
  :rule-classes :forward-chaining
  :hints (("Goal" :in-theory (enable occ-syntax-okp))))

(defthm alistp-symbol-listp-symbol-alistp-are-true-list
  (implies (or (alistp        lst)
	       (symbol-listp  lst)
	       (symbol-alistp lst))
	   (true-listp lst)))

(defthm module-syntax-okp-forward
  (implies (module-syntax-okp module)
           (and (true-listp-at-least-n+1 module 4)
                (let ((md-name   (md-name   module))
                      (md-ins    (md-ins    module))
                      (md-outs   (md-outs   module))
                      (md-sts    (md-sts    module))
                      (md-occs   (md-occs   module)))
                  (and (symbolp           md-name)
                       (symbol-listp      md-ins)
                       (no-duplicatesp-eq md-ins)
                       (symbol-listp      md-outs)
                       (no-duplicatesp-eq md-outs)
                       (symbol-listp      md-sts)
                       (no-duplicatesp-eq md-sts)
                       (symbol-alistp     md-occs)
                       ;; (consp             md-ins) ; One input?
                       ;; (consp             md-outs) ; One output?
                       (consp             md-occs) ; One occurrence?
                       (occs-syntax-okp   md-occs)))))
  :rule-classes :forward-chaining
  :hints (("Goal" :in-theory (enable module-syntax-okp))))


(defthm net-syntax-okp-forward-to-symbol-alistp
  (implies (net-syntax-okp x)
           (symbol-alistp x))
  :rule-classes :forward-chaining
  :hints (("Goal"
	   :in-theory (enable module-syntax-okp net-syntax-okp md-name))))

(defthm net-syntax-okp-forward-to-alistp
  (implies (net-syntax-okp x)
           (alistp x))
  :rule-classes :forward-chaining)

(defthm net-syntax-okp-delete-eq-module-netlist
  (implies (net-syntax-okp netlist)
           (net-syntax-okp (delete-eq-module fn netlist))))

(defthm assoc-eq-of-non-fn-netlist
  (implies (and (net-syntax-okp netlist)
		(atom (assoc-eq fn netlist)))
           (equal (assoc-eq fn netlist) nil)))

(defthm true-listp-assoc-eq-fn-netlist
  (implies (net-syntax-okp netlist)
	   (true-listp (assoc-eq fn netlist))))

(defthm assoc-eq-fn-of-empty-netlist-is-nil
  (implies (atom netlist)
	   (equal (assoc-eq fn netlist) nil)))

(defthm assoc-eq-of-netlist-is-module-okp
  (implies (and (symbolp fn)
		(assoc-eq fn netlist)
		(net-syntax-okp netlist))
           (module-syntax-okp (assoc-eq fn netlist)))
  :hints (("Goal"
	   :in-theory (disable module-syntax-okp))))

(defthm net-syntax-okp-forward-to-something
  (implies (and (net-syntax-okp netlist)
		(symbolp fn)
		(not (primp fn))
		(consp (assoc-eq fn netlist)))
	   (module-syntax-okp (assoc-eq fn netlist)))
  :rule-classes :forward-chaining)

;;;  Facts that would be expensive to have around because of the
;;;  function symbols involved on the left-hand side, so we globaly
;;;  disable them and enable them when appropriate.

(deflabel some-netlist-lookup-facts-section)

(defthm assoc-eq-fn-of-non-empty-netlist-is-consp
  (implies (and (net-syntax-okp netlist)
		(not (atom (assoc-eq fn netlist))))
	   (and (consp (assoc-eq fn netlist))
		(consp (cdr (assoc-eq fn netlist)))
		(consp (cddr (assoc-eq fn netlist)))
		(consp (cdddr (assoc-eq fn netlist)))
		(consp (cddddr (assoc-eq fn netlist))))))
  
(defthm not-cdr-assoc-eq-fn-netlist-implies-no-module
  (implies (and (net-syntax-okp netlist)
                (atom (cdr (assoc-eq fn netlist))))
           (not (cdr (assoc-eq fn netlist)))))

(defthm not-cddr-assoc-eq-fn-netlist-implies-no-module
  (implies (and (net-syntax-okp netlist)
                (atom (cddr (assoc-eq fn netlist))))
           (not (cddr (assoc-eq fn netlist)))))

(defthm not-cdddr-assoc-eq-fn-netlist-implies-no-module
  (implies (and (net-syntax-okp netlist)
                (atom (cdddr (assoc-eq fn netlist))))
           (not (cdddr (assoc-eq fn netlist)))))

(defthm not-cddddr-assoc-eq-fn-netlist-implies-no-module
  (implies (and (net-syntax-okp netlist)
                (atom (cddddr (assoc-eq fn netlist))))
           (not (cddddr (assoc-eq fn netlist)))))

(deftheory some-netlist-lookup-facts
  (set-difference-theories (current-theory :here)
			   (current-theory 'some-netlist-lookup-facts-section)))

(in-theory (disable some-netlist-lookup-facts))


;;;  Identify a set of symbols for this book.

(deftheory syntax-section
  (set-difference-theories (current-theory :here)
			   (current-theory 'syntax-defuns-section)))

