;;; -*- Mode: LISP; Syntax: Common-lisp; Package: ZL-USER; Base: 10; Patch-File: T -*-

;=====================================
(SYSTEM-INTERNALS:BEGIN-PATCH-SECTION)
(SYSTEM-INTERNALS:PATCH-SECTION-SOURCE-FILE "SYS:l-COMPILER;OPTIMIZE.LISP.179")
(SYSTEM-INTERNALS:PATCH-SECTION-ATTRIBUTES
  "-*- Mode: Lisp; Package: Compiler; Lowercase: T; Base: 8 -*-")

;;; Does simple constant folding.  This works for everything that doesn't have
;;; side-effects.
;;; ALL operands must be constant.
;;; Note that commutative-constant-folder can hack this case perfectly well
;;; by himself for the functions he handles.
(defun constant-fold-optimizer (form)
  (let ((eval-when-load-p nil))
    (flet ((constant-form-p (x)
	     (when (constant-form-p x)
	       (cond ((and (listp x)
			   (eq (car x) 'quote)
			   (listp (cadr x))
			   (eq (caadr x) eval-at-load-time-marker))
		      (setq eval-when-load-p t)
		      (cdadr x))
		     (t x)))))
      (if (every (cdr form) #'constant-form-p)
	  (if eval-when-load-p
	      (list 'quote
		    (list* eval-at-load-time-marker
			   (car form)
			   (mapcar #'constant-form-p (cdr form))))
	      (condition-case (error-object)
		   (multiple-value-call #'(lambda (&rest values)
					    (if (= (length values) 1)
						`',(first values)
						`(values ,@(mapcar #'(lambda (x) `',x)
								   values))))
					(eval form))
		 (error
		   (phase-1-warning "Constant form left unoptimized: ~S~%because: ~~A~"
				    form error-object)
		   form)))
	  form))))


;=====================================
(SYSTEM-INTERNALS:BEGIN-PATCH-SECTION)
(SYSTEM-INTERNALS:PATCH-SECTION-SOURCE-FILE "SYS:L-COMPILER;COMFILE.LISP.85")
(SYSTEM-INTERNALS:PATCH-SECTION-ATTRIBUTES
  "-*- Mode: Lisp; Package: Compiler; Lowercase: T; Base: 8 -*-")

;;;
;;; The damn compiler doesn't compile random forms that appear at top level.
;;; Its difficult to do because you have to get an associated function spec
;;; to go with those forms.  This handles that by defining a special form,
;;; top-level-form that compiles its body.  It takes a list of eval-when
;;; times just like eval when does.  It also takes a name which it uses
;;; to construct a function spec for the top-level-form function it has
;;; to create.
;;; 
;
;si::
;(defvar *top-level-form-fdefinitions* (cl:make-hash-table :test #'equal))
;
;si::
;(define-function-spec-handler pcl::top-level-form
;			      (operation fspec &optional arg1 arg2)
;  (let ((name (cadr fspec)))
;    (selectq operation
;      (validate-function-spec (and (= (length fspec) 2)
;				   (or (symbolp name)
;				       (listp name))))
;      (fdefine
;       (setf (gethash name *top-level-form-fdefinitions*) arg1))
;      ((fdefinition fdefinedp)
;       (gethash name *top-level-form-fdefinitions*)) 
;      (fdefinition-location 
;       (ferror "It is not possible to get the fdefinition-location of ~s."
;	       fspec))
;      (fundefine (remhash name *top-level-form-fdefinitions*))
;      (otherwise (function-spec-default-handler operation fspec arg1 arg2)))))
;
;;;
;;; This is basically stolen from PROGN (surprised?)
;;; 
;(si:define-special-form pcl::top-level-form (name times
;						  &body body
;						  &environment env)
;  (declare lt:(arg-template . body) (ignore name))
;  (si:check-eval-when-times times)
;  (when (member 'eval times) (si:eval-body body env)))
;
;(defun (:property pcl::top-level-form lt:mapforms) (original-form form usage)
;  (lt::mapforms-list original-form form (cddr form) 'eval usage))

;;; This is the normal function for looking at each form read from the file and calling
;;; *COMPILE-FORM-FUNCTION* on the sub-forms of it.
;;; COMPILE-TIME-TOO means override the normal cases that eval at compile time.  It is
;;; used for recursive calls under (EVAL-WHEN (COMPILE LOAD) ...).
;(DEFUN COMPILE-FROM-STREAM-1 (FORM &OPTIONAL (COMPILE-TIME-TOO NIL))
;  (CATCH-ERROR-RESTART
;     (SYS:ERROR "Skip compiling form ~2,2\COMPILER:SHORT-S-FORMAT\" FORM)
;    (LET ((DEFAULT-CONS-AREA (FUNCALL *COMPILE-FUNCTION* ':CONS-AREA)))
;      (LET ((ERROR-MESSAGE-HOOK
;	      #'(LAMBDA ()
;		  (DECLARE (SYS:DOWNWARD-FUNCTION))
;		  (FORMAT T "~&While processing ~V,V\COMPILER:SHORT-S-FORMAT\"
;			  DBG:*ERROR-MESSAGE-PRINLEVEL*
;			  DBG:*ERROR-MESSAGE-PRINLENGTH*
;			  FORM))))
;	(SETQ FORM (FUNCALL *COMPILE-FUNCTION* ':MACRO-EXPAND FORM)))
;      (WHEN (LISTP FORM)			;Ignore atoms at top-level
;	(LET ((FUNCTION (FIRST FORM)))
;	  (SELECTQ FUNCTION
;	    ((QUOTE))				;and quoted constants e.g. 'COMPILE
;	    ((PROGN)
;	     (DOLIST (FORM (CDR FORM))
;	       (COMPILE-FROM-STREAM-1 FORM COMPILE-TIME-TOO)))
;	    ((EVAL-WHEN)
;	     (SI:CHECK-EVAL-WHEN-TIMES (CADR FORM))
;	     (LET ((COMPILE-P (OR (MEMQ 'COMPILE (CADR FORM))
;				  (AND COMPILE-TIME-TOO (MEMQ 'EVAL (CADR FORM)))))
;		   (LOAD-P (OR (MEMQ 'LOAD (CADR FORM)) (MEMQ 'CL:LOAD (CADR FORM))))
;		   (FORMS (CDDR FORM)))
;	       (COND (LOAD-P
;		      (DOLIST (FORM FORMS)
;			(COMPILE-FROM-STREAM-1 FORM (AND COMPILE-P ':FORCE))))
;		     (COMPILE-P
;		      (DOLIST (FORM FORMS)
;			(FUNCALL *COMPILE-FORM-FUNCTION* FORM ':FORCE NIL))))))
;	    ((DEFUN)
;	     (LET ((TEM (DEFUN-COMPATIBILITY (CDR FORM) :WARN-IF-OBSOLETE T)))
;	       (IF (EQ (CDR TEM) (CDR FORM))
;		   (FUNCALL *COMPILE-FORM-FUNCTION* FORM COMPILE-TIME-TOO T)
;		   (COMPILE-FROM-STREAM-1 TEM COMPILE-TIME-TOO))))
;	    ((MACRO)
;	     (FUNCALL *COMPILE-FORM-FUNCTION* FORM (OR COMPILE-TIME-TOO T) T))
;	    ((DECLARE)
;	     (DOLIST (FORM (CDR FORM))
;	       (FUNCALL *COMPILE-FORM-FUNCTION* FORM (OR COMPILE-TIME-TOO T)
;			;; (DECLARE (SPECIAL ... has load-time action as well.
;			;; All other DECLARE's do not.
;			(MEMQ (CAR FORM) '(SPECIAL ZL:UNSPECIAL)))))
;	    ((COMPILER-LET)
;	     (COMPILER-LET-INTERNAL (CADR FORM) (CDDR FORM)
;				    #'COMPILE-FROM-STREAM-1 COMPILE-TIME-TOO))
;	    ((SI:DEFINE-SPECIAL-FORM)
;	     (FUNCALL *COMPILE-FORM-FUNCTION* FORM COMPILE-TIME-TOO T))
;	    ((MULTIPLE-DEFINITION)
;	     (DESTRUCTURING-BIND (NAME TYPE . BODY) (CDR FORM)
;	       (LET ((NAME-VALID (AND (NOT (NULL NAME))
;				      (OR (SYMBOLP NAME)
;					  (AND (LISTP NAME) (NEQ (CAR NAME) 'QUOTE)))))
;		     (TYPE-VALID (AND (NOT (NULL TYPE)) (SYMBOLP TYPE))))
;		 (UNLESS (AND NAME-VALID TYPE-VALID)
;		   (WARN "(~S ~S ~S ...) is invalid because~@
;			  ~:[~S is not valid as a definition name~;~*~]~
;			  ~:[~&~S is not valid as a definition type~;~*~]"
;			 'MULTIPLE-DEFINITION NAME TYPE NAME-VALID NAME TYPE-VALID TYPE)))
;	       (LET* ((COMPILED-BODY NIL)
;		      (COMPILE-FUNCTION *COMPILE-FUNCTION*)
;		      (*COMPILE-FUNCTION*
;			(LAMBDA (OPERATION &REST ARGS)
;			  (DECLARE (SYS:DOWNWARD-FUNCTION))
;			  (SELECTQ OPERATION
;			    (:DUMP-FORM
;			     (PUSH (FUNCALL COMPILE-FUNCTION :OPTIMIZE-TOP-LEVEL-FORM
;					    (FIRST ARGS))
;				   COMPILED-BODY))
;			    (:INSTALL-DEFINITION
;			     (PUSH (FORM-FOR-DEFINE *COMPILER* (FIRST ARGS) (SECOND ARGS))
;				   COMPILED-BODY))
;			    (OTHERWISE (CL:APPLY COMPILE-FUNCTION OPERATION ARGS)))))
;		      (LOCAL-DECLARATIONS `((FUNCTION-PARENT ,NAME ,TYPE)
;					    ,@LOCAL-DECLARATIONS)))
;		 (DOLIST (FORM BODY)
;		   (COMPILE-FROM-STREAM-1 FORM COMPILE-TIME-TOO))
;		 (FUNCALL COMPILE-FUNCTION :DUMP-FORM
;			  `(LOAD-MULTIPLE-DEFINITION
;			     ',NAME ',TYPE ',(NREVERSE COMPILED-BODY) NIL)))))
;	    ((pcl::top-level-form)
;	     (destructuring-bind (name times . body)
;				 (cdr form)
;	       (si:check-eval-when-times times)
;	       (let ((compile-p (or (memq 'compile times)
;				    (and compile-time-too (memq 'eval times))))
;		     (load-p (or (memq 'load times)
;				 (memq 'cl:load times)))
;		     (fspec `(pcl::top-level-form ,name)))
;		 (cond (load-p
;			(compile-from-stream-1
;			  `(progn (defun ,fspec () . ,body)
;				  (funcall (function ,fspec)))
;			  (and compile-p ':force)))
;		       (compile-p
;			(dolist (b body)
;			  (funcall *compile-form-function* form ':force nil)))))))
;	    (OTHERWISE
;	     (LET ((TEM (AND (SYMBOLP FUNCTION) (GET FUNCTION 'TOP-LEVEL-FORM))))
;	       (IF TEM
;		   (FUNCALL *COMPILE-FORM-FUNCTION* (FUNCALL TEM FORM) COMPILE-TIME-TOO T)
;		   (FUNCALL *COMPILE-FORM-FUNCTION* FORM COMPILE-TIME-TOO T))))))))))
;
;


dw::
(defun symbol-flavor-or-cl-type (symbol)
  (declare (values flavor defstruct-p deftype-fun typep-fun atomic-subtype-parent
		   non-atomic-deftype))
  (multiple-value-bind (result foundp)
      (gethash symbol *flavor-or-cl-type-cache*)
    (let ((frob
	    (if foundp result
	      (setf (gethash symbol *flavor-or-cl-type-cache*)
		    (or (get symbol 'flavor:flavor)
			(not (null (defstruct-type-p symbol)))
			(let* ((deftype (get symbol 'deftype))
			       (descriptor (symbol-presentation-type-descriptor symbol))
			       (typep
				 (unless (and descriptor
					      (presentation-type-explicit-type-function
						descriptor))
				   ;; Don't override the one defined in the presentation-type.
				   (get symbol 'typep)))
			       (atomic-subtype-parent (find-atomic-subtype-parent symbol))
			       (non-atomic-deftype
				 (when (and (not descriptor) deftype)
				   (not (member (first (type-arglist symbol))
						'(&rest &key &optional))))))
			  (if (or typep (not (atom deftype))
				  non-atomic-deftype
				  ;; deftype overrides atomic-subtype-parent.
				  (and (not deftype) atomic-subtype-parent))
			      (list-in-area *handler-dynamic-area*
					    deftype typep atomic-subtype-parent
					    non-atomic-deftype)
			    deftype)))))))
      (locally (declare (inline compiled-function-p))
        (etypecase frob
	  (array (values frob))
	  (null (values nil))
	  ((member t) (values nil t))
	  (compiled-function (values nil nil frob))
	  (lexical-closure (values nil nil frob))
	  (list (destructuring-bind (deftype typep atomic-subtype-parent non-atomic-deftype)
		    frob
		  (values nil nil deftype typep atomic-subtype-parent non-atomic-deftype)))
	  (symbol (values nil nil nil nil frob)))))))

;;;
;;; The variable zwei::*sectionize-line-lookahead* controls how many lines the parser
;;;  is willing to look ahead while trying to parse a definition.  Even 2 lines is enough
;;;  for just about all cases, but there isn't much overhead, and 10 should be enough
;;;  to satisfy pretty much everyone... but feel free to change it.
;;;        - MT 880921
;;;

zwei:
(defvar *sectionize-line-lookahead* 3)

zwei:
(DEFMETHOD (:SECTIONIZE-BUFFER MAJOR-MODE :DEFAULT)
	   (FIRST-BP LAST-BP BUFFER STREAM INT-STREAM ADDED-COMPLETIONS)
  ADDED-COMPLETIONS ;ignored, obsolete
  (WHEN STREAM
    (SEND-IF-HANDLES STREAM :SET-RETURN-DIAGRAMS-AS-LINES T))
  (INCF *SECTIONIZE-BUFFER*)
  (LET ((BUFFER-TICK (OR (SEND-IF-HANDLES BUFFER :SAVE-TICK) *TICK*))
	OLD-CHANGED-SECTIONS)
    (TICK)
    ;; Flush old section nodes.  Also collect the names of those that are modified, they are
    ;; the ones that will be modified again after a revert buffer.
    (DOLIST (NODE (NODE-INFERIORS BUFFER))
      (AND (> (NODE-TICK NODE) BUFFER-TICK)
	   (PUSH (LIST (SECTION-NODE-FUNCTION-SPEC NODE)
		       (SECTION-NODE-DEFINITION-TYPE NODE))
		 OLD-CHANGED-SECTIONS))
      (FLUSH-BP (INTERVAL-FIRST-BP NODE))
      (FLUSH-BP (INTERVAL-LAST-BP NODE)))
    (DO ((LINE (BP-LINE FIRST-BP) (LINE-NEXT INT-LINE))
	 (LIMIT (BP-LINE LAST-BP))
	 (EOFFLG)
	 (ABNORMAL T)
	 (DEFINITION-LIST NIL)
	 (BP (COPY-BP FIRST-BP))
	 (FUNCTION-SPEC)
	 (DEFINITION-TYPE)
	 (STR)
	 (INT-LINE)
	 (first-time t)
	 (future-line)				; we actually read into future line
	 (future-int-line)
	 (PREV-NODE-START-BP FIRST-BP)
	 (PREV-NODE-DEFINITION-LINE NIL)
	 (PREV-NODE-FUNCTION-SPEC NIL)
	 (PREV-NODE-TYPE 'HEADER)
	 (PREVIOUS-NODE NIL)
	 (NODE-LIST NIL)
	 (STATE (SEND SELF :INITIAL-SECTIONIZATION-STATE)))
	(NIL)
      ;; If we have a stream, read another line.
      (when (AND STREAM (NOT EOFFLG))
	(let ((lookahead (if future-line 1 *sectionize-line-lookahead*)))
	  (dotimes (i lookahead)		; startup lookahead
	    (MULTIPLE-VALUE (future-LINE EOFFLG)
	      (LET ((DEFAULT-CONS-AREA *LINE-AREA*))
		(SEND STREAM ':LINE-IN LINE-LEADER-SIZE)))
	    (IF future-LINE (SETQ future-INT-LINE (FUNCALL INT-STREAM ':LINE-OUT future-LINE)))
	    (when first-time
	      (setq first-time nil)
	      (setq line future-line)
	      (setq int-line future-int-line))
	    (when eofflg
	      (return)))))

      (SETQ INT-LINE LINE)

      (when int-line
	(MOVE-BP BP INT-LINE 0))		;Record as potentially start-bp for a section

      ;; See if the line is the start of a defun.
      (WHEN (AND LINE
		 (LET (ERR)
		   (MULTIPLE-VALUE (FUNCTION-SPEC DEFINITION-TYPE STR ERR STATE)
		     (SEND SELF ':SECTION-NAME INT-LINE BP STATE))
		   (NOT ERR)))
	(PUSH (LIST FUNCTION-SPEC DEFINITION-TYPE) DEFINITION-LIST)
	(SECTION-COMPLETION FUNCTION-SPEC STR NIL)
	;; List methods under both names for user ease.
	(LET ((OTHER-COMPLETION (SEND SELF ':OTHER-SECTION-NAME-COMPLETION
				      FUNCTION-SPEC INT-LINE)))
	  (WHEN OTHER-COMPLETION
	    (SECTION-COMPLETION FUNCTION-SPEC OTHER-COMPLETION NIL)))
	(LET ((PREV-NODE-END-BP (BACKWARD-OVER-COMMENT-LINES BP ':FORM-AS-BLANK)))
	  ;; Don't make a section node if it's completely empty.  This avoids making
	  ;; a useless Buffer Header section node. Just set all the PREV variables
	  ;; so that the next definition provokes the *right thing*
	  (UNLESS (BP-= PREV-NODE-END-BP PREV-NODE-START-BP)
	    (SETQ PREVIOUS-NODE
		  (ADD-SECTION-NODE PREV-NODE-START-BP
				    (SETQ PREV-NODE-START-BP PREV-NODE-END-BP)
				    PREV-NODE-FUNCTION-SPEC PREV-NODE-TYPE
				    PREV-NODE-DEFINITION-LINE BUFFER PREVIOUS-NODE
				    (IF (LOOP FOR (FSPEC TYPE) IN OLD-CHANGED-SECTIONS
					      THEREIS (AND (EQ PREV-NODE-FUNCTION-SPEC FSPEC)
							   (EQ PREV-NODE-TYPE TYPE)))
					*TICK* BUFFER-TICK)
				    BUFFER-TICK))
	    (PUSH PREVIOUS-NODE NODE-LIST)))
	(SETQ PREV-NODE-FUNCTION-SPEC FUNCTION-SPEC
	      PREV-NODE-TYPE DEFINITION-TYPE
	      PREV-NODE-DEFINITION-LINE INT-LINE))
      ;; After processing the last line, exit.
      (WHEN (OR #+ignore EOFFLG (null line) (AND (NULL STREAM) (EQ LINE LIMIT)))
	;; If reading a stream, we should not have inserted a CR
	;; after the eof line.
	(WHEN STREAM
	  (DELETE-INTERVAL (FORWARD-CHAR LAST-BP -1 T) LAST-BP T))
	;; The rest of the buffer is part of the last node
	(UNLESS (SEND SELF ':SECTION-NAME-TRIVIAL-P)
	  ;; ---oh dear, what sort of section will this be? A non-empty HEADER
	  ;; ---node.  Well, ok for now.
	  (PUSH (ADD-SECTION-NODE PREV-NODE-START-BP LAST-BP
				  PREV-NODE-FUNCTION-SPEC PREV-NODE-TYPE
				  PREV-NODE-DEFINITION-LINE BUFFER PREVIOUS-NODE
				  (IF (LOOP FOR (FSPEC TYPE) IN OLD-CHANGED-SECTIONS
					    THEREIS (AND (EQ PREV-NODE-FUNCTION-SPEC FSPEC)
							 (EQ PREV-NODE-TYPE TYPE)))
				      *TICK* BUFFER-TICK)
				  BUFFER-TICK)
		NODE-LIST)
	  (SETF (LINE-NODE (BP-LINE LAST-BP)) (CAR NODE-LIST)))
	(SETF (NODE-INFERIORS BUFFER) (NREVERSE NODE-LIST))
	(SETF (NAMED-BUFFER-WITH-SECTIONS-FIRST-SECTION BUFFER) (CAR (NODE-INFERIORS BUFFER)))
	(SETQ ABNORMAL NIL)			;timing windows here
	;; Speed up completion if enabled.
	(WHEN SI:*ENABLE-AARRAY-SORTING-AFTER-LOADS*
	  (SI:SORT-AARRAY *ZMACS-COMPLETION-AARRAY*))
	(SETQ *ZMACS-COMPLETION-AARRAY*
	      (FOLLOW-STRUCTURE-FORWARDING *ZMACS-COMPLETION-AARRAY*))
	(RETURN
	  (VALUES 
	    (CL:SETF (ZMACS-SECTION-LIST BUFFER)
		     (NREVERSE DEFINITION-LIST))
	    ABNORMAL))))))


