8043676a984437a2cb55b9f009af5cbb03dac07c
[sbcl.git] / src / code / uncross.lisp
1 ;;;; converting symbols from SB-XC::FOO to COMMON-LISP::FOO when
2 ;;;; cross-compiling (so that we can maintain distinct SB!XC versions
3 ;;;; of fundamental COMMON-LISP things like PROCLAIM and CLASS and
4 ;;;; ARRAY-RANK-LIMIT, so that we don't trash the cross-compilation
5 ;;;; host when defining the cross-compiler, but the distinctions go
6 ;;;; away in the target system)
7
8 ;;;; This software is part of the SBCL system. See the README file for
9 ;;;; more information.
10 ;;;;
11 ;;;; This software is derived from the CMU CL system, which was
12 ;;;; written at Carnegie Mellon University and released into the
13 ;;;; public domain. The software is in the public domain and is
14 ;;;; provided with absolutely no warranty. See the COPYING and CREDITS
15 ;;;; files for more information.
16
17 (in-package "SB!INT")
18
19 ;;; In the target system's compiler, uncrossing is just identity.
20 #-sb-xc-host
21 (progn
22   #!-sb-fluid (declaim (inline uncross))
23   (defun uncross (x) x))
24 ;;; In the cross-compiler, uncrossing is slightly less trivial.
25
26 ;;; This condition is only a STYLE-WARNING because generally it isn't important
27 ;;; in practice to recurse through anything except CONSes anyway.
28 #|
29 #!+sb-show
30 (define-condition uncross-rcr-failure (style-warning)
31   ((form :initarg :form :reader uncross-rcr-failure-form))
32   (:report (lambda (c s)
33              (format s
34                      "UNCROSS couldn't recurse through ~S~%~
35                       (which is OK as long as there are no SB-XC symbols ~
36                       down there)"
37                      (uncross-rcr-failure-form c)))))
38 |#
39
40 ;;; When cross-compiling, EVAL-WHEN :COMPILE-TOPLEVEL code is executed in the
41 ;;; host Common Lisp, not the target. A certain amount of dancing around is
42 ;;; required in order for this to work more or less correctly. (Fortunately,
43 ;;; more or less correctly is good enough -- it only needs to work on the
44 ;;; EVAL-WHEN expressions found in the SBCL sources themselves, and we can
45 ;;; exercise self-control to keep them from including anything which too
46 ;;; strongly resembles a language lawyer's test case.)
47 ;;;
48 ;;; In order to make the dancing happen, we need to make a distinction between
49 ;;; SB!XC and COMMON-LISP when we're executing a form at compile time (i.e.
50 ;;; within EVAL-WHEN :COMPILE-TOPLEVEL) but we need to treat SB!XC as
51 ;;; synonymous with COMMON-LISP otherwise. This can't be done by making SB!XC a
52 ;;; nickname of COMMON-LISP, because the reader processes things before
53 ;;; EVAL-WHEN, so by the time EVAL-WHEN :COMPILE-TOPLEVEL saw a form, the
54 ;;; distinction it needs would be lost. Instead, we read forms preserving this
55 ;;; distinction (treating SB!XC as a separate package), and only when we're
56 ;;; about to process them (for any situation other than
57 ;;; EVAL-WHEN (:COMPILE-TOPLEVEL)) do we call UNCROSS on them to obliterate the
58 ;;; distinction.
59 #+sb-xc-host
60 (defun uncross (form)
61   (let ((;; KLUDGE: We don't currently try to handle circular program
62          ;; structure, but we do at least detect it and complain about it..
63          inside? (make-hash-table)))
64     (labels ((uncross-symbol (symbol)
65                (let ((old-symbol-package (symbol-package symbol)))
66                  (if (and old-symbol-package
67                           (string= (package-name old-symbol-package) "SB-XC"))
68                      (values (intern (symbol-name symbol) "COMMON-LISP"))
69                      symbol)))
70              (rcr (form)
71                (cond ((symbolp form)
72                       (uncross-symbol form))
73                      ((or (numberp form)
74                           (characterp form)
75                           (stringp form))
76                       form)
77                      (t
78                       ;; If we reach here, FORM is something with internal
79                       ;; structure which could include symbols in the SB-XC
80                       ;; package.
81                       (when (gethash form inside?)
82                         (let ((*print-circle* t))
83                           ;; This code could probably be generalized to work on
84                           ;; circular structure, but it seems easier just to
85                           ;; avoid putting any circular structure into the
86                           ;; bootstrap code.
87                           (error "circular structure in ~S" form)))
88                       (setf (gethash form inside?) t)
89                       (unwind-protect
90                           (typecase form
91                             (cons (rcr-cons form))
92                             ;; Note: This function was originally intended to
93                             ;; search through structures other than CONS, but
94                             ;; it got into trouble with LAYOUT-CLASS and
95                             ;; CLASS-LAYOUT circular structure. After some
96                             ;; messing around, it turned out that recursing
97                             ;; through CONS is all that's needed in practice.)
98                             ;; FIXME: This leaves a lot of stale code here
99                             ;; (already commented/NILed out) for us to delete.
100                             #+nil ; only searching through CONS
101                             (simple-vector (rcr-simple-vector form))
102                             #+nil ; only searching through CONS
103                             (structure!object
104                              (rcr-structure!object form))
105                             (t
106                              ;; KLUDGE: I know that UNCROSS is far from
107                              ;; perfect, but it's good enough to cross-compile
108                              ;; the current sources, and getting hundreds of
109                              ;; warnings about individual cases it can't
110                              ;; recurse through, so the warning here has been
111                              ;; turned off. Eventually it would be nice either
112                              ;; to set up a cleaner way of cross-compiling
113                              ;; which didn't have this problem, or to make
114                              ;; an industrial-strength version of UNCROSS
115                              ;; which didn't fail this way. -- WHN 20000201
116                              #+nil (warn 'uncross-rcr-failure :form form)
117                              form))
118                         (remhash form inside?)))))
119              (rcr-cons (form)
120                (declare (type cons form))
121                (let* ((car (car form))
122                       (rcr-car (rcr car))
123                       (cdr (cdr form))
124                       (rcr-cdr (rcr cdr)))
125                  (if (and (eq rcr-car car) (eq rcr-cdr cdr))
126                    form
127                    (cons rcr-car rcr-cdr))))
128              #+nil ; only searching through CONS in this version
129              (rcr-simple-vector (form)
130                (declare (type simple-vector form))
131                (dotimes (i (length form))
132                  (let* ((aref (aref form i))
133                         (rcr-aref (rcr aref)))
134                    (unless (eq rcr-aref aref)
135                      (return (map 'vector #'rcr form))))
136                  form))
137              #+nil ; only searching through CONS in this version
138              (rcr-structure!object (form)
139                (declare (type structure!object form))
140                ;; Note: We skip the zeroth slot because it's used for LAYOUT,
141                ;; which shouldn't require any translation and which is
142                ;; complicated to think about anyway.
143                (do ((i 1 (1+ i)))
144                    ((>= i (%instance-length form)) form)
145                  (let* ((instance-ref (%instance-ref form i))
146                         (rcr-instance-ref (rcr instance-ref)))
147                    (unless (eq rcr-instance-ref instance-ref)
148                      (return (rcr!-structure!object
149                               (copy-structure form)))))))
150              #+nil ; only searching through CONS in this version
151              (rcr!-structure!object (form)
152                (declare (type structure!object form))
153                ;; As in RCR-STRUCTURE!OBJECT, we skip the zeroth slot.
154                (do ((i 1 (1+ i)))
155                    ((>= i (%instance-length form)))
156                  (let* ((instance-ref (%instance-ref form i))
157                         (rcr-instance-ref (rcr instance-ref)))
158                    ;; (By only calling SETF when strictly necessary,
159                    ;; we avoid bombing out unnecessarily when the
160                    ;; I-th slot happens to be read-only.)
161                    (unless (eq rcr-instance-ref instance-ref)
162                      (setf (%instance-ref form i)
163                            rcr-instance-ref))))))
164       (rcr form))))