;;; -*- Mode:LISP; Package:COMPILER; Readtable:CL; Base:10 -*-

;; ||| New file -- smh 27sep88
;; This is the cross compiler analog of the fleabit new-setf-macros.
;; It contains cross-compiler-compatible setf method definitions.
;; Mostly it layers another layer of fixup on top of the falcon
;; package lossage, because nowhere on the Lambda are there
;; setf method definitions for global-package symbols -- there are only
;; definitions for CONS::CAR, etc.

(defsetf rest            CONS::SET-CDR)
(defsetf first           CONS::SET-CAR)
(defsetf second (x) (v)  `(CONS::SET-CAR (CDR ,x) ,v))
(defsetf third (x) (v)   `(CONS::SET-CAR (CDDR ,x) ,v))
(defsetf fourth (x) (v)  `(CONS::SET-CAR (CDDDR ,x) ,v))
(defsetf fifth (x) (v)   `(CONS::SET-CAR (CDDDDR ,x) ,v))
(defsetf sixth (x) (v)   `(CONS::SET-CAR (NTHCDR 5 ,x) ,v))
(defsetf seventh (x) (v) `(CONS::SET-CAR (NTHCDR 6 ,x) ,v))
(defsetf eighth (x) (v)  `(CONS::SET-CAR (NTHCDR 7 ,x) ,v))
(defsetf ninth (x) (v)   `(CONS::SET-CAR (NTHCDR 8 ,x) ,v))
(defsetf tenth (x) (v)   `(CONS::SET-CAR (NTHCDR 9 ,x) ,v))
(defsetf car             CONS::SET-CAR)
(defsetf cdr             CONS::SET-CDR)
(defsetf caar (x) (v)    `(CONS::SET-CAR (CAR ,x) ,v))
(defsetf cadr (x) (v)    `(CONS::SET-CAR (CDR ,x) ,v))
(defsetf cdar (x) (v)    `(CONS::SET-CAR (CAR ,x) ,v))
(defsetf cddr (x) (v)    `(CONS::SET-CDR (CDR ,x) ,v))
(defsetf caaar (x) (v)   `(CONS::SET-CAR (CAAR ,x) ,v))
(defsetf caadr (x) (v)   `(CONS::SET-CAR (CADR ,x) ,v))
(defsetf cadar (x) (v)   `(CONS::SET-CAR (CDAR ,x) ,v))
(defsetf caddr (x) (v)   `(CONS::SET-CAR (CDDR ,x) ,v))
(defsetf cdaar (x) (v)   `(CONS::SET-CDR (CAAR ,x) ,v))
(defsetf cdadr (x) (v)   `(CONS::SET-CDR (CADR ,x) ,v))
(defsetf cddar (x) (v)   `(CONS::SET-CDR (CDAR ,x) ,v))
(defsetf cdddr (x) (v)   `(CONS::SET-CDR (CDDR ,x) ,v))
(defsetf caaaar (x) (v)  `(CONS::SET-CAR (CAAAR ,x) ,v))
(defsetf caaadr (x) (v)  `(CONS::SET-CAR (CAADR ,x) ,v))
(defsetf caadar (x) (v)  `(CONS::SET-CAR (CADAR ,x) ,v))
(defsetf caaddr (x) (v)  `(CONS::SET-CAR (CADDR ,x) ,v))
(defsetf cadaar (x) (v)  `(CONS::SET-CAR (CDAAR ,x) ,v))
(defsetf cadadr (x) (v)  `(CONS::SET-CAR (CDADR ,x) ,v))
(defsetf caddar (x) (v)  `(CONS::SET-CAR (CDDAR ,x) ,v))
(defsetf cadddr (x) (v)  `(CONS::SET-CAR (CDDDR ,x) ,v))
(defsetf cdaaar (x) (v)  `(CONS::SET-CDR (CAAAR ,x) ,v))
(defsetf cdaadr (x) (v)  `(CONS::SET-CDR (CAADR ,x) ,v))
(defsetf cdadar (x) (v)  `(CONS::SET-CDR (CADAR ,x) ,v))
(defsetf cdaddr (x) (v)  `(CONS::SET-CDR (CADDR ,x) ,v))
(defsetf cddaar (x) (v)  `(CONS::SET-CDR (CDAAR ,x) ,v))
(defsetf cddadr (x) (v)  `(CONS::SET-CDR (CDADR ,x) ,v))
(defsetf cdddar (x) (v)  `(CONS::SET-CDR (CDDAR ,x) ,v))
(defsetf cddddr (x) (v)  `(CONS::SET-CDR (CDDDR ,x) ,v))
(defsetf nth (n x) (v)   `(CONS::SET-CAR (NTHCDR ,n ,x) ,v))


;; +++ These locf methods are not yet really supported in the runtime code.

(defsetf symbol-value    SET)
(deflocf symbol-value    value-cell-location)
(deflocf symeval         value-cell-location)
(defsetf symbol-function symbol::set-symbol-function)
(deflocf symbol-function function-cell-location)
(deflocf fsymeval        function-cell-location)
(defsetf symbol-plist    symbol::set-symbol-plist)
(deflocf symbol-plist    plist-location)
(defsetf symbol-package  symbol::set-symbol-package)
(deflocf symbol-package  package-cell-location)

(deflocf %INSTANCE-REF   instance-variable-location)

(defsetf svref           array::svset)
;; One of the next two is probably wrong.
(deflocf aref            array::aloc)		;presently unimplemented
(deflocf zl:aref         array::aloc)		;presently unimplemented

;;;(defsetf elt             (SI::SETELT x v))
;;;(defsetf documentation   (SI::SET-DOCUMENTATION x v))
;;;(defsetf macro-function  (SI::SET-MACRO-FUNCTION x v))

;;; Other required CL SETF methods.
;;;
;;; Note- none of the defsetf'd methods except subseq expand into Common Lisp
;;;       gethash might need to be redone with DEFINE-SETF-METHOD.

;; This needs to be checked for sanity. --smh 28sep88

(define-setf-method apply (#|*** &environment environment***|# function &rest args)
  (unless (and (consp function)
	       (member (car function) '(function quote))
	       (= (length function) 2)
	       (symbolp (cadr function)))
    (error					;'sys:unknown-setf-reference
      "In SETF of APPLY, the function applied must be a constant."))
  (multiple-value-bind (tempvars tempargs storevars storeform refform)
      (get-setf-method (cons (cadr function) args) #|*** environment ***|#)
;    (if (memq (cadr function) '(zl:aref cl:aref))	;why special-cased???
;	(setq storeform
;	      `(aset ,(car (last storeform)) . ,(butlast (cdr storeform)))))
    (if (not (eq (car (last storeform)) (car (last tempvars))))
	(error "~S not acceptable within ~S within SETF." function)
      (values tempvars tempargs storevars
	      `(APPLY #',(car storeform) . ,(cdr storeform))
	      `(APPLY #',(car refform) . ,(cdr refform))))))

(defsetf aref (array &rest subscripts) (x)
  (case (length subscripts)
    (1 `(array::aset-1 ,x ,array ,@subscripts))
    (2 `(array::aset-2 ,x ,array ,@subscripts))
    (t `(array::ASET ,x ,array ,@subscripts))))

(defsetf bit (bit-array &rest subscripts) (x)
  (case (length subscripts)
    (1 `(array::aset-1 (the bit ,x) ,bit-array ,@subscripts))
    (2 `(array::aset-2 (the bit ,x) ,bit-array ,@subscripts))
    (t `(array::ASET (the bit ,x) ,bit-array ,@subscripts))))

(defsetf sbit (simple-bit-array &rest subscripts) (x)
  (case (length subscripts)
    (1 `(array::aset-1 (the bit ,x) ,simple-bit-array ,@subscripts))
    (2 `(array::aset-2 (the bit ,x) ,simple-bit-array ,@subscripts))
    (t `(array::ASET (the bit ,x) ,simple-bit-array ,@subscripts))))

(defsetf char (string index) (x)
  `(array::ASET-1 (THE STRING-CHAR ,x) ,string ,index))

(defsetf schar (string index) (x)
  `(array::ASET-1 (THE STRING-CHAR ,x) ,string ,index))

(defsetf fill-pointer array::SET-fill-pointer)

;(defsetf li::get (symbol property-name &optional default) (x)
;  `(SETF (GETF (SYMBOL-PLIST ,symbol) ,property-name ,default) ,x))

;(define-setf-method li::getf (place indicator &optional default)
;  (multiple-value-bind (temps vals stores store-form access-form)
;      (get-setf-method place)
;    (let ((itemp (gensym))
;	  (dtemp (gensym))
;	  (store (gensym))
;	  (stemp (first stores)))
;      (values (list* itemp dtemp temps)
;	      (list* indicator default vals)
;	      (list store)
;	      (let ((old-plist-temp (gensym)))
;		`(LET ((,old-plist-temp ,access-form))
;		   ,dtemp ;; Ignore default
;		   (IF ,old-plist-temp
;		       ;; If there is an old plist, destructively modify or extend it.
;		       (LABELS ((FOO (PLIST)
;				  (COND ((NULL PLIST)
;					 (RPLACD (LAST ,old-plist-temp)
;						 (LIST ,itemp ,store)))
;					((EQ (CAR PLIST) ,itemp)
;					 (RPLACA (CDR PLIST) ,store))
;					(T
;					 (FOO (CDDR PLIST))))))
;			 (FOO ,old-plist-temp))
;		       ;; If there isn't an old plist, make one.
;		       (LET ((,stemp (LIST ,itemp ,store)))
;			 ,store-form))
;		   ,store))
;	      `(GETF ,access-form ,itemp ,dtemp)))))

(define-setf-method getf (place indicator &optional default)
  (multiple-value-bind (temps vals stores store-form access-form)
      (get-setf-method place)
    (let ((itemp (gensym 'ind))
	  (dtemp (gensym 'def))
	  (store (gensym 'stor))
	  (stemp (first stores)))
      (values (list* itemp dtemp temps)
	      (list* indicator default vals)
	      (list store)
	      `(LET ((,stemp (SYMBOL::%PUTF ,access-form ,itemp ,store))) 
		 ,store-form
		 ,store)
	      `(GETF ,access-form ,itemp ,dtemp)))))

(defsetf get (object property &optional (default nil defaultp)) (value)
  (let ((tem (if defaultp `(prog1 ,property ,default) property)))
    `(symbol::%put ,object ,tem ,value)))

;; It remains to be proven that this gethash method works with complete
;; generality for embedded forms.
;; There is also the language-definition question whether the default form
;; is supposed to be evaluated, even though it is not used.

(defsetf gethash (hashtable key &optional default) (value)
  `(li::%sethash ,hashtable ,key ,value))

(define-setf-method ldb (bytespec int)
  (multiple-value-bind (temps vals stores store-form access-form)
      (get-setf-method int)
    (let ((btemp (gensym))
	  (store (gensym))
	  (stemp (first stores)))
      (values (cons btemp temps)
	      (cons bytespec vals)
	      (list store)
	      `(let ((,stemp (dpb ,store ,btemp ,access-form)))
		 ,store-form
		 ,store)
	      `(ldb ,btemp ,access-form)
	      ))))



(define-setf-method progn (&environment environment &rest forms)
  (multiple-value-bind (tempvars tempargs storevars storeform refform)
      (get-setf-method-multiple-value (car (last forms)) environment)
    (values tempvars tempargs storevars
	    `(progn ,@(butlast forms) ,storeform)
	    `(progn ,@(butlast forms) ,refform))))

(define-setf-method locally (&environment environment &rest forms)
  (multiple-value-bind (tempvars tempargs storevars storeform refform)
      (get-setf-method-multiple-value (car (last forms)) environment)
    (values tempvars tempargs storevars
	    `(locally ,@(butlast forms) ,storeform)
	    `(locally ,@(butlast forms) ,refform))))

(deflocf locally (&rest forms)
  (let ((new-body (copy-list forms)))
    (rplaca (last new-body)
	    `(locf ,(car (last new-body))))
    `(locally . ,new-body)))

(define-setf-method let (&environment environment boundvars &rest forms)
  (multiple-value-bind (tempvars tempargs storevars storeform refform)
      (get-setf-method-multiple-value (car (last forms)) environment)
    (values tempvars tempargs storevars
	    `(let ,boundvars ,@(butlast forms) ,storeform)
	    `(let ,boundvars ,@(butlast forms) ,refform))))

(deflocf progn (&rest forms)
  (let ((new-body (copy-list forms)))
    (rplaca (last new-body)
	    `(locf ,(car (last new-body))))
    `(progn . ,new-body)))

(deflocf let (boundvars &rest forms)
  (let ((new-body (copy-list forms)))
    (rplaca (last new-body)
	    `(locf ,(car (last new-body))))
    `(let ,boundvars . ,new-body)))

(deflocf setq (a b)
  (let ((at (gensym)))
    `(let ((,at (locf ,b)))
       (setq ,a (car ,at))
       ,at)))



;(defsetf li::subseq (sequence start &optional end) (new-seq)
;  `(PROGN (REPLACE ,sequence (THE SEQUENCE ,new-seq) :START-1 ,start :START-2 ,end)
;	  ,new-seq))

(defmacro push (item place)
  "Add ITEM to the front of the list at PLACE."
  (multiple-value-bind (temps values storevars storeform accessform)
      (get-setf-method place)
    (let ((item-temp (gensym)))
      `(LET (,@(mapcar #'list temps values)
	     (,item-temp ,item))
	 (LET ((,(car storevars) (CONS ,item-temp ,accessform)))
	   ,storeform)))))

(defmacro pop (place)
  "Remove the first element from the list at PLACE, and return that element."
  (multiple-value-bind (temps values storevars storeform accessform)
      (get-setf-method place)
    (let ((access-temp (gensym)))
      `(LET* (,@(mapcar #'list temps values)
	      (,access-temp ,accessform)
	      (,(car storevars) (CDR ,access-temp)))
       (PROG1 (CAR ,access-temp)
	      ,storeform)))))

;;; $$$ From "k-sys:warm;array2" <19-Nov-88 wkf>
(defsetf array:array-leader array:set-array-leader)
(defsetf array:aref (array &rest subscripts) (value)
  `(array:aset ,value ,array . ,subscripts))

;;; $$$ From "k-sys:warm;lists" <19-Nov-88 wkf>
(defsetf li:FIRST CONS:SET-CAR)

;;; $$$ "k-sys:warm;hash" <19-Nov-88 wkf>
(defsetf li:%hash-table-size      li:%hash-table-size-set)
(defsetf li:%hash-table-use-count li:%hash-table-use-count-set)
(defsetf li:%hash-table-test      li:%hash-table-test-set)
(defsetf li:%hash-table-rehash-size li:%hash-table-rehash-size-set)
(defsetf li:%hash-table-rehash-threshold li:%hash-table-rehash-threshold-set)
(defsetf li:%hash-table-data-ptr li:%hash-table-data-ptr-set)
(defsetf li:gethash  (key hash-table &optional default) (value)
  `(li:%sethash ,key ,hash-table ,value))