Coverage report: /home/ellis/comp/core/std/defpkg.lisp
Kind | Covered | All | % |
expression | 701 | 1552 | 45.2 |
branch | 62 | 150 | 41.3 |
Key
Not instrumented
Conditionalized out
Executed
Not executed
Both branches taken
One branch taken
Neither branch taken
1
;;; defpkg.lisp --- defpackage extension macro
3
;; DEFPKG is based on UIOP:DEFINE-PACKAGE
10
(defpackage :std/defpkg
14
:find-package* :find-symbol* :symbol-call :intern*
15
:export* :import* :shadowing-import* :shadow*
16
:symbol-shadowing-p :home-package-p :make-symbol* :unintern*
17
:symbol-package-name :standard-common-lisp-symbol-p
18
:reify-package :unreify-package :reify-symbol :unreify-symbol
19
:nuke-symbol-in-package :nuke-symbol :rehome-symbol :ensure-package-unused
20
:delete-package* :package-names :packages-from-names :fresh-package-name
21
:rename-package-away :package-definition-form :parse-defpkg-form :ensure-package
22
:with-package :define-lisp-package
23
:defpackage* :*default-package* :*defpkg-hook* :package-symbols-except))
25
(in-package :std/defpkg)
27
(defvar *default-package* "CL-USER")
29
(defparameter *defpkg-hook* nil)
31
(eval-when (:load-toplevel :compile-toplevel :execute)
32
(defun find-package* (package-designator &optional (error t))
33
"Alternative to FIND-PACKAGE with optional error."
34
(let ((package (find-package package-designator)))
37
(error (error "No package named ~S" (string package-designator)))
39
(defun find-symbol* (name package-designator &optional (error t))
40
"Find a symbol in a package of given string'ified NAME;
41
unlike CL:FIND-SYMBOL, work well with 'modern' case sensitive syntax
42
by letting you supply a symbol or keyword for the name;
43
also works well when the package is not present.
44
If optional ERROR argument is NIL, return NIL instead of an error
45
when the symbol is not found."
47
(let ((package (find-package* package-designator error)))
48
(when package ;; package error handled by find-package* already
49
(multiple-value-bind (symbol status) (find-symbol (string name) package)
51
(status (return (values symbol status)))
52
(error (error "There is no symbol ~S in package ~S" name (package-name package))))))
54
(defun symbol-call (package name &rest args)
55
"Call a function associated with symbol of given name in given package,
56
with given ARGS. Useful when the call is read before the package is loaded,
57
or when loading the package is optional."
58
(apply (find-symbol* name package) args))
59
(defun intern* (name package-designator &optional (error t))
60
"Like INTERN but never create a new package."
61
(intern (string name) (find-package* package-designator error)))
62
(defun export* (name package-designator)
63
"Like EXPORT but return NIL on error."
64
(let* ((package (find-package* package-designator))
65
(symbol (intern* name package)))
66
(export (or symbol (list symbol)) package)))
67
(defun import* (symbol package-designator)
68
"Like IMPORT but return NIL on error."
69
(import (or symbol (list symbol)) (find-package* package-designator)))
70
(defun shadowing-import* (symbol package-designator)
71
"Like SHADOWING-IMPORT but return NIL on error."
72
(shadowing-import (or symbol (list symbol)) (find-package* package-designator)))
73
(defun shadow* (name package-designator)
74
"Like SHADOW but return NIL on error."
75
(shadow (list (string name)) (find-package* package-designator)))
76
(defun make-symbol* (name)
77
"Like MAKE-SYMBOL but when NAME is a symbol and not a string, call COPY-SYMBOL
80
(string (make-symbol name))
81
(symbol (copy-symbol name))))
82
(defun unintern* (name package-designator &optional (error t))
83
"Like UNINTERN but with optional errors."
85
(let ((package (find-package* package-designator error)))
87
(multiple-value-bind (symbol status) (find-symbol* name package error)
89
(status (unintern symbol package)
90
(return (values symbol status)))
91
(error (error "symbol ~A not present in package ~A"
92
(string symbol) (package-name package))))))
94
(defun symbol-shadowing-p (symbol package)
95
"Return T if SYMBOL is a member PACKAGE's shadowing symbols."
96
(and (member symbol (package-shadowing-symbols package)) t))
97
(defun home-package-p (symbol package)
98
"Return T if PACKAGE is the 'home package' of SYMBOL."
99
(and package (let ((sp (symbol-package symbol)))
100
(and sp (let ((pp (find-package* package)))
101
(and pp (eq sp pp))))))))
104
(eval-when (:load-toplevel :compile-toplevel :execute)
105
(defun symbol-package-name (symbol)
106
"Return the name of the package SYMBOL belongs to."
107
(let ((package (symbol-package symbol)))
108
(and package (package-name package))))
109
(defun standard-common-lisp-symbol-p (symbol)
110
"Return T if SYMBOL is a standard COMMON-LISP symbol."
111
(multiple-value-bind (sym status) (find-symbol* symbol :common-lisp nil)
112
(and (eq sym symbol) (eq status :external))))
113
(defun reify-package (package &optional package-context)
114
"Return the appropriate relative value of PACKAGE in optional PACKAGE-CONTEXT."
115
(if (eq package package-context) t
118
((eql (find-package :cl)) :cl)
119
(package (package-name package)))))
120
(defun unreify-package (package &optional package-context)
121
"Return the concrete value of PACKAGE modulo PACKAGE-CONTEXT."
124
((eql t) package-context)
125
((or symbol string) (find-package package))))
126
(defun reify-symbol (symbol &optional package-context)
127
"Return the appropriate relative value of SYMBOL in optional PACKAGE-CONTEXT."
129
((or keyword (satisfies standard-common-lisp-symbol-p)) symbol)
130
(symbol (vector (symbol-name symbol)
131
(reify-package (symbol-package symbol) package-context)))))
132
(defun unreify-symbol (symbol &optional package-context)
133
"Return the concrete value of SYMBOL modulo PACKAGE-CONTEXT."
137
(let* ((symbol-name (svref symbol 0))
138
(package-foo (svref symbol 1))
139
(package (unreify-package package-foo package-context)))
140
(if package (intern* symbol-name package)
141
(make-symbol* symbol-name)))))))
143
(eval-when (:load-toplevel :compile-toplevel :execute)
144
(defvar *all-package-happiness* '())
145
(defvar *all-package-fishiness* (list t))
146
(defun record-fishy (info)
147
;;(format t "~&FISHY: ~S~%" info)
148
(push info *all-package-fishiness*))
149
(defmacro when-package-fishiness (&body body)
150
`(when *all-package-fishiness* ,@body))
151
(defmacro note-package-fishiness (&rest info)
152
`(when-package-fishiness (record-fishy (list ,@info)))))
154
(eval-when (:load-toplevel :compile-toplevel :execute)
155
(defun set-dummy-symbol (symbol reason other-symbol)
156
"Set the DUMMY-SYMBOL prop of SYMBOL to (REASON . OTHER-SYMBOL)."
157
(setf (get symbol 'dummy-symbol) (cons reason other-symbol)))
158
(defun make-dummy-symbol (symbol)
159
"Make a DUMMY-SYMBOL and set the prop value of SYMBOL."
160
(let ((dummy (copy-symbol symbol)))
161
(set-dummy-symbol dummy 'replacing symbol)
162
(set-dummy-symbol symbol 'replaced-by dummy)
164
(defun dummy-symbol (symbol)
165
"Return the DUMMY-SYMBOL prop of SYMBOL."
166
(get symbol 'dummy-symbol))
167
(defun get-dummy-symbol (symbol)
168
"Get the DUMMY-SYMBOL prop of SYMBOL returning values (SYMBOL REASON) if it
169
exists and setting it if not."
170
(let ((existing (dummy-symbol symbol)))
171
(if existing (values (cdr existing) (car existing))
172
(make-dummy-symbol symbol))))
173
(defun nuke-symbol-in-package (symbol package-designator)
174
"Nuke SYMBOL in package PACKAGE-DESIGNATOR."
175
(let ((package (find-package* package-designator))
176
(name (symbol-name symbol)))
177
(multiple-value-bind (sym stat) (find-symbol name package)
178
(when (and (member stat '(:internal :external)) (eq symbol sym))
179
(if (symbol-shadowing-p symbol package)
180
(shadowing-import* (get-dummy-symbol symbol) package)
181
(unintern* symbol package))))))
182
(defun nuke-symbol (symbol &optional (packages (list-all-packages)))
183
"Nuke SYMBOL form PACKAGES."
184
(loop :for p :in packages :do (nuke-symbol-in-package symbol p)))
185
(defun rehome-symbol (symbol package-designator)
186
"Changes the home package of a symbol, also leaving it present in its old home if any"
187
(let* ((name (symbol-name symbol))
188
(package (find-package* package-designator))
189
(old-package (symbol-package symbol))
190
(old-status (and old-package (nth-value 1 (find-symbol name old-package))))
191
(shadowing (and old-package (symbol-shadowing-p symbol old-package) (make-symbol name))))
192
(multiple-value-bind (overwritten-symbol overwritten-symbol-status) (find-symbol name package)
193
(unless (eq package old-package)
194
(let ((overwritten-symbol-shadowing-p
195
(and overwritten-symbol-status
196
(symbol-shadowing-p overwritten-symbol package))))
197
(note-package-fishiness
199
(when old-package (package-name old-package)) old-status (and shadowing t)
200
(package-name package) overwritten-symbol-status overwritten-symbol-shadowing-p)
203
(shadowing-import* shadowing old-package))
204
(unintern* symbol old-package))
206
(overwritten-symbol-shadowing-p
207
(shadowing-import* symbol package))
209
(when overwritten-symbol-status
210
(unintern* overwritten-symbol package))
211
(import* symbol package)))
213
(shadowing-import* symbol old-package)
214
(import* symbol old-package))
215
(when (eq old-status :external)
216
(export* symbol old-package))
217
(when (eq overwritten-symbol-status :external)
218
(export* symbol package))))
219
(values overwritten-symbol overwritten-symbol-status))))
220
(defun ensure-package-unused (package)
221
"Ensure that PACKAGE is unused by any other package."
222
(loop :for p :in (package-used-by-list package) :do
223
(unuse-package package p)))
224
(defun delete-package* (package &key nuke)
225
"Delete package PACKAGE, additionally ensuring it is unused by other packages
226
and optionally nuking all symbols as well."
227
(let ((p (find-package package)))
229
(when nuke (do-symbols (s p) (when (home-package-p s p) (nuke-symbol s))))
230
(ensure-package-unused p)
231
(delete-package package))))
232
(defun package-names (package)
233
"Return a cons of PACKAGE name and nicknames."
234
(cons (package-name package) (package-nicknames package)))
235
(defun packages-from-names (names)
236
"Return packages associated with list NAMES, starting from the end and deleting all duplicates."
237
(remove-duplicates (remove nil (mapcar #'find-package names)) :from-end t))
238
(defun fresh-package-name (&key (prefix :%TO-BE-DELETED)
240
(index (random most-positive-fixnum)))
241
(loop :for i :from index
242
:for n = (format nil "~A~@[~A~D~]" prefix (and (plusp i) (or separator "")) i)
243
:thereis (and (not (find-package n)) n)))
244
(defun rename-package-away (p &rest keys &key prefix &allow-other-keys)
246
(apply 'fresh-package-name
247
:prefix (or prefix (format nil "__~A__" (package-name p))) keys)))
248
(record-fishy (list :rename-away (package-names p) new-name))
249
(rename-package p new-name))))
252
;;; Communicable representation of symbol and package information
253
(eval-when (:load-toplevel :compile-toplevel :execute)
254
(defun package-definition-form (package-designator
255
&key (nicknamesp t) (usep t)
256
(shadowp t) (shadowing-import-p t)
257
(exportp t) (importp t) internp (error t))
258
(let* ((package (or (find-package* package-designator error)
259
(return-from package-definition-form nil)))
260
(name (package-name package))
261
(nicknames (package-nicknames package))
262
(use (mapcar #'package-name (package-use-list package)))
264
(shadowing-import (make-hash-table :test 'equal))
265
(import (make-hash-table :test 'equal))
269
(loop :for sym :being :the :symbols :in package
270
:for status = (nth-value 1 (find-symbol* sym package)) :do
273
((:internal :external)
274
(let* ((name (symbol-name sym))
275
(external (eq status :external))
276
(home (symbol-package sym))
277
(home-name (package-name home))
278
(imported (not (eq home package)))
279
(shadowing (symbol-shadowing-p sym package)))
281
((and shadowing imported)
282
(push name (gethash home-name shadowing-import)))
286
(push name (gethash home-name import))))
291
(t (push name intern)))))))
292
(labels ((sort-names (names)
293
(sort (copy-list names) #'string<))
295
(loop :for k :being :the :hash-keys :of table :collect k))
296
(when-relevant (key value)
297
(when value (list (cons key value))))
298
(import-options (key table)
299
(loop :for i :in (sort-names (table-keys table))
300
:collect `(,key ,i ,@(sort-names (gethash i table))))))
302
,@(when-relevant :nicknames (and nicknamesp (sort-names nicknames)))
303
(:use ,@(and usep (sort-names use)))
304
,@(when-relevant :shadow (and shadowp (sort-names shadow)))
305
,@(import-options :shadowing-import-from (and shadowing-import-p shadowing-import))
306
,@(import-options :import-from (and importp import))
307
,@(when-relevant :export (and exportp (sort-names export)))
308
,@(when-relevant :intern (and internp (sort-names intern)))))))))
310
(eval-when (:load-toplevel :compile-toplevel :execute)
311
(defun ensure-shadowing-import (name to-package from-package shadowed imported)
312
(check-type name string)
313
(check-type to-package package)
314
(check-type from-package package)
315
(check-type shadowed hash-table)
316
(check-type imported hash-table)
317
(let ((import-me (find-symbol* name from-package)))
318
(multiple-value-bind (existing status) (find-symbol name to-package)
320
((gethash name shadowed)
321
(unless (eq import-me existing)
322
(error "Conflicting shadowings for ~A" name)))
324
(setf (gethash name shadowed) t)
325
(setf (gethash name imported) t)
326
(unless (or (null status)
327
(and (member status '(:internal :external))
328
(eq existing import-me)
329
(symbol-shadowing-p existing to-package)))
330
(note-package-fishiness
331
:shadowing-import name
332
(package-name from-package)
333
(or (home-package-p import-me from-package) (symbol-package-name import-me))
334
(package-name to-package) status
335
(and status (or (home-package-p existing to-package) (symbol-package-name existing)))))
336
(shadowing-import* import-me to-package))))))
337
(defun ensure-imported (import-me into-package &optional from-package)
338
(check-type import-me symbol)
339
(check-type into-package package)
340
(check-type from-package (or null package))
341
(let ((name (symbol-name import-me)))
342
(multiple-value-bind (existing status) (find-symbol name into-package)
345
(import* import-me into-package))
346
((eq import-me existing))
348
(let ((shadowing-p (symbol-shadowing-p existing into-package)))
349
(note-package-fishiness
350
:ensure-imported name
351
(and from-package (package-name from-package))
352
(or (home-package-p import-me from-package) (symbol-package-name import-me))
353
(package-name into-package)
355
(and status (or (home-package-p existing into-package) (symbol-package-name existing)))
358
((or shadowing-p (eq status :inherited))
359
(shadowing-import* import-me into-package))
361
(unintern* existing into-package)
362
(import* import-me into-package))))))))
364
(defun ensure-import (name to-package from-package shadowed imported)
365
(check-type name string)
366
(check-type to-package package)
367
(check-type from-package package)
368
(check-type shadowed hash-table)
369
(check-type imported hash-table)
370
(multiple-value-bind (import-me import-status) (find-symbol name from-package)
371
(when (null import-status)
372
(note-package-fishiness
373
:import-uninterned name (package-name from-package) (package-name to-package))
374
(setf import-me (intern* name from-package)))
375
(multiple-value-bind (existing status) (find-symbol name to-package)
377
((and imported (gethash name imported))
378
(unless (and status (eq import-me existing))
379
(error "Can't import ~S from both ~S and ~S"
380
name (package-name (symbol-package existing)) (package-name from-package))))
381
((gethash name shadowed)
382
(error "Can't both shadow ~S and import it from ~S" name (package-name from-package)))
384
(setf (gethash name imported) t))))
385
(ensure-imported import-me to-package from-package)))
386
(defun ensure-inherited (name symbol to-package from-package mixp shadowed imported inherited)
387
(check-type name string)
388
(check-type symbol symbol)
389
(check-type to-package package)
390
(check-type from-package package)
391
(check-type mixp boolean)
392
(check-type shadowed hash-table)
393
(check-type imported hash-table)
394
(check-type inherited hash-table)
395
(multiple-value-bind (existing status) (find-symbol name to-package)
396
(let* ((sp (symbol-package symbol))
397
(in (gethash name inherited))
398
(xp (and status (symbol-package existing))))
400
(note-package-fishiness
401
:import-uninterned name
402
(package-name from-package) (package-name to-package) mixp)
403
(import* symbol from-package)
404
(setf sp (package-name from-package)))
406
((gethash name shadowed))
408
(unless (equal sp (first in))
410
(ensure-shadowing-import name to-package (second in) shadowed imported)
411
(error "Can't inherit ~S from ~S, it is inherited from ~S"
412
name (package-name sp) (package-name (first in))))))
413
((gethash name imported)
414
(unless (eq symbol existing)
415
(error "Can't inherit ~S from ~S, it is imported from ~S"
416
name (package-name sp) (package-name xp))))
418
(setf (gethash name inherited) (list sp from-package))
419
(when (and status (not (eq sp xp)))
420
(let ((shadowing (symbol-shadowing-p existing to-package)))
421
(note-package-fishiness
423
(package-name from-package)
424
(or (home-package-p symbol from-package) (symbol-package-name symbol))
425
(package-name to-package)
426
(or (home-package-p existing to-package) (symbol-package-name existing)))
427
(if shadowing (ensure-shadowing-import name to-package from-package shadowed imported)
428
(unintern* existing to-package)))))))))
429
(defun ensure-mix (name symbol to-package from-package shadowed imported inherited)
430
(check-type name string)
431
(check-type symbol symbol)
432
(check-type to-package package)
433
(check-type from-package package)
434
(check-type shadowed hash-table)
435
(check-type imported hash-table)
436
(check-type inherited hash-table)
437
(unless (gethash name shadowed)
438
(multiple-value-bind (existing status) (find-symbol name to-package)
439
(let* ((sp (symbol-package symbol))
440
(im (gethash name imported))
441
(in (gethash name inherited)))
444
(and status (eq symbol existing))
445
(and in (eq sp (first in))))
446
(ensure-inherited name symbol to-package from-package t shadowed imported inherited))
448
(remhash name inherited)
449
(ensure-shadowing-import name to-package (second in) shadowed imported))
451
(error "Symbol ~S import from ~S~:[~; actually ~:[uninterned~;~:*from ~S~]~] conflicts with existing symbol in ~S~:[~; actually ~:[uninterned~;from ~:*~S~]~]"
452
name (package-name from-package)
453
(home-package-p symbol from-package) (symbol-package-name symbol)
454
(package-name to-package)
455
(home-package-p existing to-package) (symbol-package-name existing)))
457
(ensure-inherited name symbol to-package from-package t shadowed imported inherited)))))))
459
(defun recycle-symbol (name recycle exported)
460
"Takes a symbol NAME (a string), a list of package designators for RECYCLE
461
packages, and a hash-table of names (strings) of symbols scheduled to be
462
EXPORTED from the package being defined. It returns two values, the symbol
463
found (if any, or else NIL), and a boolean flag indicating whether a symbol
464
was found. The caller (DEFPKG) will then do the re-homing of the symbol, etc."
465
(check-type name string)
466
(check-type recycle list)
467
(check-type exported hash-table)
468
(when (gethash name exported) ;; don't bother recycling private symbols
469
(let (recycled foundp)
470
(dolist (r recycle (values recycled foundp))
471
(multiple-value-bind (symbol status) (find-symbol name r)
472
(when (and status (home-package-p symbol r))
475
;; (nuke-symbol symbol)) -- even simple variable names like O or C will do that.
476
(note-package-fishiness :recycled-duplicate name (package-name foundp) (package-name r)))
478
(setf recycled symbol foundp r)))))))))
479
(defun symbol-recycled-p (sym recycle)
480
(check-type sym symbol)
481
(check-type recycle list)
482
(and (member (symbol-package sym) recycle) t))
483
(defun ensure-symbol (name package intern recycle shadowed imported inherited exported)
484
(check-type name string)
485
(check-type package package)
486
(check-type intern boolean)
487
(check-type shadowed hash-table)
488
(check-type imported hash-table)
489
(check-type inherited hash-table)
490
(unless (or (gethash name shadowed)
491
(gethash name imported)
492
(gethash name inherited))
493
(multiple-value-bind (existing status)
494
(find-symbol name package)
495
(multiple-value-bind (recycled previous) (recycle-symbol name recycle exported)
497
((and status (eq existing recycled) (eq previous package)))
499
(rehome-symbol recycled package))
500
((and status (eq package (symbol-package existing))))
503
(note-package-fishiness
505
(reify-package (symbol-package existing) package)
509
(intern* name package))))))))
510
(declaim (ftype (function (t t t &optional t) t) ensure-exported))
511
(defun ensure-exported-to-user (name symbol to-package &optional recycle)
512
(check-type name string)
513
(check-type symbol symbol)
514
(check-type to-package package)
515
(check-type recycle list)
516
(assert (equal name (symbol-name symbol)))
517
(multiple-value-bind (existing status) (find-symbol name to-package)
518
(unless (and status (eq symbol existing))
521
(let ((shadowing (symbol-shadowing-p existing to-package))
522
(recycled (symbol-recycled-p existing recycle)))
523
(unless (and shadowing (not recycled))
524
(note-package-fishiness
525
:ensure-export name (symbol-package-name symbol)
526
(package-name to-package)
527
(or (home-package-p existing to-package) (symbol-package-name existing))
529
(if (or (eq status :inherited) shadowing)
530
(shadowing-import* symbol to-package)
531
(unintern existing to-package))
533
(when (and accessible (eq status :external))
534
(ensure-exported name symbol to-package recycle))))))
535
(defun ensure-exported (name symbol from-package &optional recycle)
536
(dolist (to-package (package-used-by-list from-package))
537
(ensure-exported-to-user name symbol to-package recycle))
538
(unless (eq from-package (symbol-package symbol))
539
(ensure-imported symbol from-package))
540
(export* name from-package))
541
(defun ensure-export (name from-package &optional recycle)
542
(multiple-value-bind (symbol status) (find-symbol* name from-package)
543
(unless (eq status :external)
544
(ensure-exported name symbol from-package recycle))))
546
(defun ensure-package (name &key
547
nicknames documentation use
548
shadow shadowing-import-from
549
import-from export intern
551
unintern package-local-nicknames lock implements)
552
(let* ((package-name (string name))
553
(nicknames (mapcar #'string nicknames))
554
(names (cons package-name nicknames))
555
(previous (packages-from-names names))
556
(discarded (cdr previous))
558
(package (or (first previous) (make-package package-name :nicknames nicknames)))
559
(recycle (packages-from-names recycle))
560
(use (mapcar 'find-package* use))
561
(mix (mapcar 'find-package* mix))
562
(reexport (mapcar 'find-package* reexport))
563
(shadow (mapcar 'string shadow))
564
(export (mapcar 'string export))
565
(intern (mapcar 'string intern))
566
(implements (mapcar 'find-package* implements))
567
(unintern (mapcar 'string unintern))
568
(shadowed (make-hash-table :test 'equal)) ; string to bool
569
(imported (make-hash-table :test 'equal)) ; string to bool
570
(exported (make-hash-table :test 'equal)) ; string to bool
571
;; string to list home package and use package:
572
(inherited (make-hash-table :test 'equal)))
573
(when-package-fishiness (record-fishy package-name))
574
(when documentation (setf (documentation package t) documentation))
575
(when lock (sb-ext:lock-package package))
576
(loop for p in (set-difference implements (sb-ext:package-implements-list package))
577
do (sb-ext:add-implementation-package p package))
578
(loop for p in package-local-nicknames
579
do (sb-ext:add-package-local-nickname (pop p) (pop p) package))
580
(loop :for p :in (set-difference (package-use-list package) (append mix use))
581
:do (note-package-fishiness :over-use name (package-names p))
582
(unuse-package p package))
583
(loop :for p :in discarded
584
:for n = (remove-if #'(lambda (x) (member x names :test 'equal))
586
:do (note-package-fishiness :nickname name (package-names p))
587
(cond (n (rename-package p (first n) (rest n)))
588
(t (rename-package-away p)
589
(push p to-delete))))
590
(rename-package package package-name nicknames)
591
(dolist (name unintern)
592
(multiple-value-bind (existing status) (find-symbol name package)
594
(unless (eq status :inherited)
595
(note-package-fishiness
596
:unintern (package-name package) name (symbol-package-name existing) status)
597
(unintern* name package nil)))))
598
(dolist (name export)
599
(setf (gethash name exported) t))
601
(do-external-symbols (sym p)
602
(setf (gethash (string sym) exported) t)))
603
(do-external-symbols (sym package)
604
(let ((name (symbol-name sym)))
605
(unless (gethash name exported)
606
(note-package-fishiness
607
:over-export (package-name package) name
608
(or (home-package-p sym package) (symbol-package-name sym)))
609
(unexport sym package))))
610
(dolist (name shadow)
611
(setf (gethash name shadowed) t)
612
(multiple-value-bind (existing status) (find-symbol name package)
613
(multiple-value-bind (recycled previous) (recycle-symbol name recycle exported)
614
(let ((shadowing (and status (symbol-shadowing-p existing package))))
616
((eq previous package))
618
(rehome-symbol recycled package))
619
((or (member status '(nil :inherited))
620
(home-package-p existing package)))
622
(let ((dummy (make-symbol name)))
623
(note-package-fishiness
624
:shadow-imported (package-name package) name
625
(symbol-package-name existing) status shadowing)
626
(shadowing-import* dummy package)
627
(import* dummy package)))))))
628
(shadow* name package))
629
(loop :for (p . syms) :in shadowing-import-from
630
:for pp = (find-package* p) :do
631
(dolist (sym syms) (ensure-shadowing-import (string sym) package pp shadowed imported)))
633
:for pp = (find-package* p) :do
634
(do-external-symbols (sym pp) (ensure-mix (symbol-name sym) sym package pp shadowed imported inherited)))
635
(loop :for (p . syms) :in import-from
636
:for pp = (find-package p) :do
637
(dolist (sym syms) (ensure-import (symbol-name sym) package pp shadowed imported)))
638
(dolist (p (append use mix))
639
(do-external-symbols (sym p) (ensure-inherited (string sym) sym package p nil shadowed imported inherited))
640
(use-package p package))
641
(loop :for name :being :the :hash-keys :of exported :do
642
(ensure-symbol name package t recycle shadowed imported inherited exported)
643
(ensure-export name package recycle))
644
(dolist (name intern)
645
(ensure-symbol name package t recycle shadowed imported inherited exported))
646
(do-symbols (sym package)
647
(ensure-symbol (symbol-name sym) package nil recycle shadowed imported inherited exported))
648
(map () 'delete-package* to-delete)
651
(defmacro %defpkg* (pkg args)
652
"Define a new 'prelude' package with NAME (car args) which exports SYMBOLS (cdr
654
(sb-int:once-only ((a args))
655
`(let ((name (car ,a))
657
(eval `(defpackage ,name
658
(:import-from ,,pkg ,@syms)
659
(:export ,@syms))))))
661
(eval-when (:load-toplevel :compile-toplevel :execute)
662
(defun parse-defpkg-form (package clauses)
664
:with use-p = nil :with recycle-p = nil
665
:with documentation = nil
667
:for (kw . args) :in clauses
668
:when (eq kw :nicknames) :append args :into nicknames :else
669
:when (eq kw :documentation)
671
(documentation (error "defpkg: can't define documentation twice"))
672
((or (atom args) (cdr args)) (error "defpkg: bad documentation"))
673
(t (setf documentation (car args))))
675
:when (eq kw :use) :append args :into use :and :do (setf use-p t) :else
676
:when (eq kw :shadow) :append args :into shadow :else
677
:when (eq kw :shadowing-import-from) :collect args :into shadowing-import-from :else
678
:when (eq kw :import-from) :collect args :into import-from :else
679
:when (eq kw :export) :append args :into export :else
680
:when (eq kw :intern) :append args :into intern :else
681
:when (eq kw :recycle) :append args :into recycle :and :do (setf recycle-p t) :else
682
:when (eq kw :mix) :append args :into mix :else
683
:when (eq kw :package-local-nicknames) :collect args :into plns :else
684
:when (eq kw :implements) :append args :into implements :else
685
:when (eq kw :prelude) :collect args :into preludes :else
686
:when (and (eq kw :lock) args) :do (setf lock t) :else
687
:when (eq kw :reexport) :append args :into reexport :else
688
:when (eq kw :use-reexport) :append args :into use :and :append args :into reexport
689
:and :do (setf use-p t) :else
690
:when (eq kw :mix-reexport) :append args :into mix :and :append args :into reexport
691
:and :do (setf use-p t) :else
692
:when (eq kw :unintern) :append args :into unintern :else
693
:do (error "unrecognized defpkg keyword ~S" kw)
698
:nicknames ,nicknames :documentation ,documentation
699
:package-local-nicknames ,plns
700
:implements ,implements
702
:use ,(if use-p use '(:common-lisp))
703
:shadow ,shadow :shadowing-import-from ,shadowing-import-from
704
:import-from ,import-from :export ,export :intern ,intern
705
:recycle ,(if recycle-p recycle (cons package nicknames))
706
:mix ,mix :reexport ,reexport :unintern ,unintern)
709
(defmacro defpkg (package &rest clauses)
710
"Richard's Robust DEFPACKAGE macro. Based on UIOP:DEFINE-PACKAGE ymmv.
712
DEFPKG takes a PACKAGE and a number of CLAUSES, of the form (KEYWORD . ARGS).
714
DEFPKG supports the following standard extensions:
715
USE, SHADOW, SHADOWING-IMPORT-FROM, IMPORT-FROM, EXPORT, INTERN -- as per CL:DEFPACKAGE.
717
As well as the common extensions:
718
RECYCLE, MIX, REEXPORT, UNINTERN -- as per UIOP/PACKAGE:DEFINE-PACKAGE
720
Additionally, DEFPKG supports the following combinators:
722
MIX-REEXPORT -- combination of MIX and REEXPORT
724
USE-REEXPORT -- combination of USE and REEXPORT
726
and the following custom extensions:
728
PRELUDE -- treat the first element as the name of a 'prelude' package which
729
will be defined with the remaining symbols re-exported from PACKAGE and only
732
In addition to defining and returning a package, when *DEFPKG-HOOK* is
733
non-nil, it is called as a function with a single argument - the package being
735
(multiple-value-bind (form preludes) (parse-defpkg-form package clauses)
736
(let ((pkg `(apply 'ensure-package ',form))
737
(prd (mapcar (lambda (x) `(%defpkg* ',(car form) ',x)) preludes)))
738
`(eval-when (:compile-toplevel :load-toplevel :execute)
739
(prog1 (if #1=*defpkg-hook*
742
,@(when prd `(,@prd)))))))
744
(defmacro define-lisp-package (package)
745
"Define a lisp package based on target PACKAGE which transparently exports all
746
COMMON-LISP symbols in addition to those already exported by the target
748
(flet ((externals-of (pkg)
749
(loop for s being each external-symbol in pkg collect s)))
750
(let* ((pkg-externs (externals-of package))
751
(pkg-shadows (intersection (package-shadowing-symbols package)
753
(cl-externs (externals-of "COMMON-LISP")))
754
`(defpackage ,(sb-int:symbolicate package "-LISP")
756
(:shadowing-import-from ,package ,@pkg-shadows)
757
(:import-from ,package ,@(set-difference pkg-externs pkg-shadows))
758
(:export ,@cl-externs)
759
(:export ,@pkg-externs)))))
761
(defmacro with-package (pkg &body body)
762
"Execute BODY within the package PKG."
763
`(let ((*package* (find-package ,pkg)))
766
;; From C-MERA for internal package (syn/gen/c/sym, etc)
767
(defmacro defpackage* (name (&key shadow-symbols export-symbols) &body body)
768
"defpackage with (:shadow ,@<symbols>) and (:export ,@<symbols>)"
769
`(let ((shadow-list (loop for i in (remove-duplicates ,shadow-symbols) collect
770
(intern (format nil "~a" i) :keyword)))
771
(export-list (loop for i in (remove-duplicates ,export-symbols) collect
772
(intern (format nil "~a" i) :keyword)))
774
(eval `(defpackage ,,name
776
(:shadow ,@shadow-list)
777
(:export ,@export-list)))))
779
;; Helper function for blacklisting symbols when tracing whole packages.
780
(defun package-symbols-except (name &rest exceptions)
782
(package (sb-impl::find-undeleted-package-or-lose name)))
783
(do-all-symbols (symbol (find-package name))
784
(when (eql package (symbol-package symbol))
785
(when (and (fboundp symbol)
786
(not (macro-function symbol))
787
(not (special-operator-p symbol)))
788
(push symbol symbols))
789
(let ((setf-name `(setf ,symbol)))
790
(when (fboundp setf-name)
791
(push setf-name symbols)))))
792
(set-difference symbols exceptions
796
(string x))) :test #'string-equal)))