;;; -*- Mode:Lisp; Readtable:ZL; Package:USER; Base:8; Patch-File:T -*-
;;; Patch file for System version 126.89
;;; Reason:
;;;  Implement style checker on system functions that expect byte specifier arguments.
;;;  Try to warn about obviously non-portable arguments; the typical situation we want
;;;  to flush out is calling, e.g., LDB with a numeric constant.  Here is an example
;;;  of a function that calls LDB and DPB several ways that are non-portable:
;;;  
;;;    (defun tester-ng (ppss wrd)
;;;      (compiler-let ((compiler:*just-once-for-style-checkers-per-inner-form* nil))
;;;        (ldb #(1 2 3) wrd)
;;;        (ldb nil wrd)
;;;        (ldb t wrd)
;;;        (ldb :keyword wrd)
;;;        (ldb (* ppss 3) wrd)
;;;        (dpb #b1010 261. wrd)
;;;        (dpb #o17 (max 3 5) 77.)
;;;        (ldb (times ppss 3) wrd)))
;;;    
;;;    << While compiling TESTER-NG >>
;;;     LDB called with an invalid BYTE specifier "#(1 2 3)"; this is not portable
;;;     LDB called with a null BYTE specifier; this is not portable
;;;     LDB called with T as a BYTE specifier; this is not portable
;;;     LDB called with the keyword :KEYWORD as a BYTE specifier; this is not portable
;;;     LDB called with a call to * as a BYTE specifier; this may not be portable
;;;     DPB called with the numeric constant 261 as a BYTE specifier; this is not portable
;;;     DPB called with a call to MAX as a BYTE specifier; this may not be portable
;;;     LDB called with a call to TIMES as a BYTE specifier; this may not be portable
;;;  
;;;  Any function, such as BYTE, that is known to return a portable byte
;;;  specifier will not generate a warning if it has a non-NIL
;;;  COMPILER:LEGAL-BYTE-SPECIFIER property.  If anybody has such a need
;;;  frequently, this could be modified to look at a function-internal
;;;  declaration.
;;; Written 23-Sep-88 19:41:11 by keith (Keith Corbett) at site Gigamos Cambridge
;;; while running on Breaking Glass from band 1
;;; with Experimental System 126.88, Experimental ZMail 74.1, Experimental Local-File 76.0, Experimental File-Server 25.0, Experimental Unix-Interface 14.0, Experimental Tape 25.1, Experimental Lambda-Diag 18.0, Experimental ZWEI 126.11, microcode 1762, SDU Boot Tape 3.14, SDU ROM 103.



; From modified file DJ: L.SYS; QCOPT.LISP#184 at 23-Sep-88 19:41:12
#8R COMPILER#: 
(COMPILER-LET ((*PACKAGE* (PKG-FIND-PACKAGE "COMPILER")))
  (PATCH-SOURCE-FILE "SYS: SYS; QCOPT  "


;;;BYTE SPEC callers

(defun check-byte-spec (form &aux flag)
  (let* ((fcn (car form))
	 (argpos (or (get fcn 'check-byte-spec-arg) 0))
	 (barg (nth (1+ argpos) form))
	 (definitely-not-portable t))
    (when
      (setq flag
	    ;;Return to FLAG the warning, if any
	    (macrolet ((middle (prefix)
			       (format nil "~A ~~S as a BYTE specifier" prefix))
		       (at-end (prefix)
			       (format nil "~A BYTE specifier /"~~S/"" prefix))
		       (simple (prefix)
			       (format nil "~A BYTE specifier~~*" prefix)))
	      (typecase barg
		(keyword (middle "the keyword"))	;Keywords will never be right
		((member t nil)				; T, NIL other selv-evaling vars
		 (if barg (simple "T as a")
		   (simple "a null")))
		(symbol nil)				;Variables? We can't be sure.
		(list					;"Random" function calls are not portable.
		 (setq barg (car barg))
		 (cond
		   ((get barg 'legal-byte-specifier) nil)	;The ideal: calls to BYTE
		   (t (setq definitely-not-portable nil)	;Can't be sure
		      (middle "a call to"))))
		(number (middle "the numeric constant"))	;Numbers
		(t (at-end "an invalid")))))
      (warn 'invalid-byte-spec :not-portable
	"~S called with ~A; this ~:[may not be~;is not~] portable"
	fcn
	(format nil flag barg)
	definitely-not-portable))))

;;;Put the LEGAL-BYTE-SPECIFIER property on things like BYTE that return
;;;portable, legally formatted byte specifiers -- i.e., they don't do any
;;;processor-specific arithmetic.
(defprop byte t legal-byte-specifier)

(defmacro check-byte-spec-arg (sym &optional (argpos 0))
  (check-type sym symbol)
  (check-type argpos (integer 0))
  `(eval-when (eval compile load)
     (progn
       (unless (fboundp ',sym)
	 (warn 'function-not-valid :implausible
	   "Establishing byte-spec checker for undefined function ~S" ',sym))
       (let ((prev-check (get ',sym 'style-checker)))
	 (and prev-check (neq prev-check 'check-byte-spec)
	      (warn 'redefining-style-checker :probable-error
		"Redefining style check on ~S from ~S to ~S"
		',sym prev-check 'check-byte-spec)))
       (putprop ',sym 'check-byte-spec 'style-checker)
       (putprop ',sym ,argpos 'check-byte-spec-arg))))

(check-byte-spec-arg byte-position)
(check-byte-spec-arg byte-size)
(check-byte-spec-arg dpb 1)
(check-byte-spec-arg ldb)
(check-byte-spec-arg ldb-test)
(check-byte-spec-arg mask-field)
(check-byte-spec-arg deposit-field 1)
(check-byte-spec-arg %logldb)
(check-byte-spec-arg %logdpb 1)
(check-byte-spec-arg %p-ldb)
(check-byte-spec-arg %p-ldb-offset)
(check-byte-spec-arg %p-mask-field)
(check-byte-spec-arg %p-mask-field-offset)
(check-byte-spec-arg %p-dpb 1)
(check-byte-spec-arg %p-dpb-offset 1)
(check-byte-spec-arg %p-deposit-field 1)
(check-byte-spec-arg %p-deposit-field-offset 1)

))
