(DEFINE-FILE-INFO READTABLE "XCL" PACKAGE "XCL" BASE 10)
(il:filecreated " 3-Nov-87 16:27:35" 
"{FireFS:CS:Univ Rochester}<Koomen>LispUsers>Lyric>PORT-CLFILE.;12" 23613  

      il:|changes| il:|to:|  (il:functions export-clfile import-clfile clfile-export-filecom)

      il:|previous| il:|date:| "28-Oct-87 14:24:40" 
"{FireFS:CS:Univ Rochester}<Koomen>LispUsers>Lyric>PORT-CLFILE.;10")


; Copyright (c) 1987 by Johannes Koomen, Larry Masinter.  All rights reserved.

(il:prettycomprint il:port-clfilecoms)

(il:rpaqq il:port-clfilecoms ((il:functions import-clfile export-clfile)
                              (il:p (export '(import-clfile export-clfile) (find-package "XCL"))
                                    (import '(import-clfile export-clfile) (find-package "INTERLISP")
                                           ))
                              (il:functions clfile-export-filecom clfile-parse-form clfile-parse-mode 
                                     clfile-read-semi clfile-set-mode)
                              (il:prop (il:filetype il:makefile-environment)
                                     il:port-clfile)))

(defun import-clfile (filepath) 
                               "Load a standard CommonLisp file FILEPATH, creating COMS for FILEPATH"
   (with-open-file (*standard-input* filepath :direction :input)
          (declare (special *standard-input*))
          (let ((*package* (find-package "USER"))
                (*readtable* (copy-readtable nil))
                (*read-base* 10)
                (comslst nil)
                (eof-value (list :eof))
                (file-id (intern (string-upcase (pathname-name *standard-input*))
                                (find-package "INTERLISP"))))
               (declare (special *package* *readtable* *read-base*))
          
          (il:* il:|;;| "Copy readtable, change ; macro to preserve comments")

               (set-macro-character #\; #'clfile-read-semi nil *readtable*)
               (do ((clform (read nil nil eof-value)
                           (read nil nil eof-value))
                    (firstclformp t)
                    (nextcomsentry nil)
                    (lastcomsentry nil)
                    (nextcomsweirdp nil))
                   ((eq clform eof-value)
                    (if lastcomsentry (push lastcomsentry comslst))
                    (setq comslst (nreverse comslst)))
                   (when firstclformp (setq firstclformp nil)
                         (cond
                            ((and (consp clform)
                                  (eq (car clform)
                                      'il:*)
                                  (do ((cltail (cdr clform)
                                              (cdr cltail)))
                                      ((not (consp cltail))
                                       nil)
                                      (if (stringp (car cltail))
                                          (return (clfile-parse-mode (car cltail)
                                                         file-id)))))
                             (setq clform nil))))
                   (unless (null clform)
                          (eval clform)
                          (setq nextcomsentry (clfile-parse-form clform))
                          (setq nextcomsweirdp (or (eq (car nextcomsentry)
                                                       'il:*)
                                                   (consp (cddr nextcomsentry))))
                          (when (and lastcomsentry (or nextcomsweirdp (not (eq (car nextcomsentry)
                                                                               (car lastcomsentry))))
                                     )
                                (push lastcomsentry comslst)
                                (setq lastcomsentry nil))
                          (cond
                             (nextcomsweirdp (push nextcomsentry comslst))
                             (lastcomsentry (nconc lastcomsentry (cdr nextcomsentry)))
                             (t (setq lastcomsentry nextcomsentry)))))
               (setf (get file-id 'il:filetype)
                     :compile-file)
               (set (il:filecoms file-id)
                    (nconc comslst `((il:prop (il:filetype il:makefile-environment)
                                            ,file-id))))
               (pushnew file-id il:filelst)
               (il:markaschanged file-id 'il:files 'il:defined)
               file-id)))


(defun export-clfile (filepath &optional (linelength 72)) 
                                 "Write a standard CommonLisp file FILEPATH, using COMS for FILEPATH"
   (declare (global il:filelinelength))
   (il:resetvars ((il:filelinelength linelength))
                 (with-open-file (*standard-output* (make-pathname :type "LISP" :version :newest 
                                                           :defaults filepath)
                                        :direction :output)
                        (declare (special *standard-output*))
                        (let ((*package* (find-package "USER"))
                              (*readtable* (il:find-readtable "LISP"))
                              (*print-base* 10)
                              (*print-array* t)
                              (*print-level* nil)
                              (*print-length* nil)
                              (il:fontchangeflg nil)
                              (il:\#rpars nil)
                              (il:**comment**flg nil)
                              (il:*print-semicolon-comments* t)
                              (il:*print-structure* t)
                              (file-id (intern (string-upcase (pathname-name *standard-output*))
                                              (find-package "INTERLISP"))))
                             (declare (special *package* *readtable* *print-base* *print-array* 
                                             *print-level* *print-length* il:fontchangeflg il:\#rpars 
                                             il:**comment**flg il:*print-semicolon-comments* 
                                             il:*print-structure*))
                             (clfile-set-mode (get file-id 'il:makefile-environment))
                             (format t ";;; -*- Package: ~A; Syntax: ~A; Mode: Lisp; Base: ~D -*-"
                                    (string-capitalize (package-name *package*))
                                    (let ((rdtblname (il:readtableprop *readtable* 'il:name)))
                                         (cond
                                            ((or (not (stringp rdtblname))
                                                 (string-equal rdtblname "XCL")
                                                 (string-equal rdtblname "LISP"))
                                             "Common-Lisp")
                                            (t (string-capitalize rdtblname))))
                                    *print-base*)
                             (format t "~2%;;; File converted on ~A from source ~A" (il:date)
                                    file-id)
                             (let ((dates (get file-id 'il:filedates)))
                                  (when dates (format t "~&;;; Original source ~A created ~A"
                                                     (cdar dates)
                                                     (caar dates))))
                             (terpri)
                             (terpri)
                             (il:printcopyright file-id)
                             (mapc #'clfile-export-filecom (il:listp (il:gettopval (il:filecoms
                                                                                    file-id))))
                             (namestring *standard-output*)))))

(export '(import-clfile export-clfile) (find-package "XCL"))
(import '(import-clfile export-clfile) (find-package "INTERLISP"))

(defun clfile-export-filecom (command)
   (flet
    ((save-prop (symbol prop val)
            (case prop ((il:filetype il:makefile-environment)(il:* il:\; "IGNORE")

                        nil)
                  (t (pprint `(setf (get ',symbol ',prop)
                                    ',val))))))
    (case (il:getfilepkgtype (car command)
                 'command)
          (il:fns
           (mapc #'(lambda (fn)
                          (pprint (let ((def (il:getdef fn 'il:fns)))
                                       (ecase (car def)
                                              ((lambda)
                                               `(defun (il:\\\, fn) ,@(cdr def) )
)
                                              ((il:lambda)
                                               `(defun (il:\\\, fn) (&optional ,@(second def))
                                                   ,@(cddr def))
))))) (il:prettycom1 command t t)))
          (il:vars (mapc #'(lambda (var)
                                  (if (listp var)
                                      `(defparameter (first var) (second var) )

                                      `(defparameter (il:\\\, var) ',(il:gettopval var) )
)) (il:prettycom1 command t t)))
          (il:declare\: (let ((context '(load eval))
                              (when-clause t))
                             (do ((tail (il:prettycom1 command t t)
                                        (cdr tail)))
                                 ((null tail))
                                 (case (car tail)
                                       ((il:eval@loadwhen)
                                        (pushnew 'eval context)
                                        (setq when-clause (if (eq when-clause t)
                                                              (cadr tail)
                                                              `(and ,(cadr tail) ,when-clause)))
                                        (setq tail (cdr tail))
                                                             (il:* il:\; 
                                                             " consumes two tokens, one by the DO")

                                        )
                                       ((il:eval@compilewhen)
                                        (pushnew 'compile context)
                                        (setq when-clause (if (eq when-clause t)
                                                              (cadr tail)
                                                              `(and ,(cadr tail) ,when-clause)))
                                        (setq tail (cdr tail)))
                                       ((il:copywhen)
                                        (pushnew 'load context)
                                        (setq when-clause (if (eq when-clause t)
                                                              (cadr tail)
                                                              `(and ,(cadr tail) ,when-clause)))
                                        (setq tail (cdr tail)))
                                       ((il:first il:notfirst)
                                                             (il:* il:\; "IGNORE")

                                        )
                                       ((il:compilervars)
          
          (il:* il:|;;| "throw these out")

                                        (return-from clfile-export-filecom nil))
                                       ((il:copy il:docopy)
                                        (pushnew 'load context))
                                       ((il:doeval@compile il:eval@compile)
                                        (pushnew 'compile context))
                                       ((il:doeval@load il:eval@load)
                                        (pushnew 'eval context))
                                       ((il:dontcopy)
                                        (setq context (remove 'load context)))
                                       ((il:donteval@compile)
                                        (setq context (remove 'compile context)))
                                       ((il:donteval@load)
                                        (setq context (remove 'eval context)))
                                       (t (format t "~&(eval-when &S " context)
                                          (clfile-export-filecom (car tail))
                                          (format t ")"))))))
          ((il:specvars)
           (pprint `(proclaim '(special ,@(il:prettycom1 command t t)))))
          ((il:globalvars)
           (pprint `(proclaim '(global ,@(il:prettycom1 command t t)))))
          ((il:localvars)
           (pprint `(proclaim '(lexical ,@(il:prettycom1 command t t)))))
          ((il:prop il:ifprop)
           (prog ((optional (eq (car command)
                                'il:ifprop))
                  (props (cadr command))
                  (not-found "NOT ON ANY PROPERTY LIST")
                  (symbols (il:prettycom1 (cdr command)
                                  t t)))                     (il:* il:\; 
                                          "IFPROP only dumps those property values that are non-NIL.")

                 (mapc #'(lambda (symbol)
                                (declare (special il:sysprops))
                                (flet ((do-prop (prop)
                                              (unless (and optional (eq not-found
                                                                        (get symbol prop not-found)))
                                                     (save-prop symbol prop (get symbol prop)))))
                                      (cond
                                         ((consp props)
                                          (mapc #'do-prop props))
                                         ((eq props 'il:all)
                                          (do ((tail (symbol-plist symbol)
                                                     (cddr tail)))
                                              ((null tail))
                                              (unless (member (car tail)
                                                             il:sysprops)
                                                     (do-prop (car tail)))))
                                         (t (do-prop props))))) symbols)))
          (il:p (mapc #'(lambda (x)
                               (case (car x)
                                     ((il:putprops)
                                      (do ((tail (cdr x)
                                                 (cdddr tail)))
                                          ((null tail))
                                          (save-prop (first tail)
                                                 (second tail)
                                                 (third tail))))
                                     (t (pprint x)))) (il:prettycom1 command t)))
          (il:initvars (mapc #'(lambda (x)
                                      (declare (special il:commentflg))
                                      (pprint (cond
                                                 ((listp x)
                                                  (if (eq (car x)
                                                          il:commentflg)
                                                      x
                                                      `(defvar (il:\\\,@ x) )
))
                                                 (t (help))))) (il:prettycom1 command t t)))
          (il:coms (mapc #'clfile-export-filecom (il:prettycom1 command t)))
          (                                                  (il:*)
           (cond
              ((eq (cadr command)
                   'il:*)                                    (il:* il:\; 
                 "Form-feed if super-comment indicated.  Use * no matter what current COMMENTFLG is.")

               (write-char #\Page)))
           (pprint command))
          (t (let ((def (cdr (assoc (car command)
                                    il:prettydefmacros))))
                  (if def (mapc #'clfile-export-filecom (il:subpair (car def)
                                                               (il:prettycom1 command t t)
                                                               (cdr def)))
                      (help "CAN'T HANDLE" (car command))))))))


(defun clfile-parse-form (clform) "Given CommonLisp FORM, creates (filepkgtype object)"
   (cond
      ((or (not (consp clform))
           (not (symbolp (car clform))))
       `(il:p ,clform))
      ((eq (car clform)
           'il:*)
       clform)
      ((let ((comstype (get (car clform)
                            'il:definer-for))
             (comsname (cadr clform)))
            (if comstype (list comstype (if (consp comsname) (il:* il:\; "e.g. STRUCTURES")

                                            (car comsname)
                                            comsname)))))
      ((case (car clform)
             (proclaim (let ((declspec (car (il:constantexpressionp (cadr clform)))))
                            (case (car declspec)
                                  (global (cons 'il:globalvars (cdr declspec)))
                                  (special (cons 'il:specvars (cdr declspec)))
                                  (lexical (cons 'il:localvars (cdr declspec))))))
             (eval-when (let (evalflg loadflg compileflg)
                             (do ((context (cadr clform)
                                         (cdr context)))
                                 ((null context))
                                 (case (car context)
                                       (eval (setq evalflg t))
                                       (load (setq loadflg t))
                                       (compile (setq compileflg t))))
                             `(il:declare\: ,(if evalflg 'il:eval@load 'il:donteval@load)
                                     ,(if loadflg 'il:copy 'il:dontcopy)
                                     ,(if compileflg 'il:eval@compile 'il:donteval@compile)
                                     (coms ,@(mapcar #'clfile-parse-form (caddr clform))))))))
      (t `(il:p ,clform))))


(defun clfile-parse-mode (mode-string &optional file-id) 
                         "Setf *PACKAGE*, *READTABLE* and *READ-BASE* according to file mode comment"
   (declare (special *package* *readtable* *read-base*))
   (when (search "-*-" mode-string :end2 3)
         (prog ((modestr (string-upcase mode-string))
                modepos modename object)
               (when (setq modepos (search "PACKAGE: " modestr))
                     (setq modename (string (read-from-string modestr nil nil :start
                                                   (+ modepos (length "PACKAGE: ")))))
                     (setq object (find-package modename))
                     (cond
                        ((packagep object)
                         (setq *package* object))
                        (t (error "~&Non-existent package: ~A~%" modename))))
               (when (setq modepos (search "SYNTAX: " modestr))
                     (setq modename (string (read-from-string modestr nil nil :start
                                                   (+ modepos (length "SYNTAX: ")))))
                     (if (string-equal modename "COMMON-LISP")
                         (setq modename "LISP"))
                     (setq object (il:find-readtable modename))
                     (cond
                        ((readtablep object)
          
          (il:* il:|;;| "Need to continue intercepting comments!")

                         (setq *readtable* (copy-readtable object))
                         (il:readtableprop *readtable* 'il:name (il:readtableprop object 'il:name))
                         (set-macro-character #\; #'clfile-read-semi nil *readtable*))
                        (t (error "~&Non-existent readtable: ~A~%" modename))))
               (when (setq modepos (search "BASE: " modestr))
                     (setq object (read-from-string modestr nil nil :start (+ modepos (length 
                                                                                             "BASE: "
                                                                                             ))))
                     (cond
                        ((and (numberp object)
                              (> object 0))
                         (setq *read-base* (truncate object)))
                        (t (error "~&Bad read base: ~A~%" object))))
               (when file-id (setf (get file-id 'il:makefile-environment)
                                   (list :package (package-name *package*)
                                         :readtable
                                         (let ((rdtblname (il:readtableprop *readtable* 'il:name)))
                                              (cond
                                                 ((or (not (stringp rdtblname))
                                                      (string-equal rdtblname "LISP"))
                                                  "XCL")
                                                 (t rdtblname)))
                                         :base *read-base*)))
               (return t))))


(defun clfile-read-semi (stream rdtbl) "A ; was seen.  Collect more ;'s, then wrap comment in IL:*"
   (declare (ignore rdtbl))
   (do ((ch (read-char stream)
            (read-char stream))
        (lvl 1)
        (comment ""))
       ((or (null ch)
            (not (char= ch #\;)))
        (unread-char ch stream)
        (cond
           ((setq comment (read-line stream))
            (list 'il:* (cond
                           ((> lvl 2)
                            'il:|;;;|)
                           ((= lvl 2)
                            'il:|;;|)
                           (t 'il:\;))
                  (string-trim '(#\Space #\Tab) comment)))))
       (incf lvl 1)))


(defun clfile-set-mode (makefile-environment) 

(il:* il:|;;;| "Using the MAKEFILE-ENVIRONMENT, sets the appropriate free vars (bound above in EXPORT-CLFILE) to the specified package, readtable and print base.")
 (declare (special *package* *readtable* *print-base*))
 (let ((file-package (getf makefile-environment :package))
       (read-table (getf makefile-environment :readtable))
       (print-base (getf makefile-environment :base)))
      (let ((pkg (if (stringp file-package)
                     (find-package file-package)
                     (eval file-package))))
           (when (packagep pkg)
                 (setq *package* pkg)))
      (let ((rdtbl (if (stringp read-table)
                       (il:find-readtable read-table)
                       (eval read-table))))
           (when (readtablep rdtbl)
                 (setq *readtable* rdtbl)))
      (let ((base (if (numberp print-base)
                      print-base
                      (eval print-base))))
           (when (numberp base)
                 (setq *print-base* base)))))


(il:putprops il:port-clfile il:filetype :compile-file)

(il:putprops il:port-clfile il:makefile-environment (:readtable "XCL" :package "XCL" :base 10))
(il:putprops il:port-clfile il:copyright ("Johannes Koomen, Larry Masinter" 1987))
(il:declare\: il:dontcopy
  (il:filemap (nil)))
il:stop