Don't convert to specialized-xep with argcount mismatch.
[sbcl.git] / src / code / defpackage.lisp
blobfcd550edf85763cb0832ac52af3151c37e60eedb
1 ;;;; the DEFPACKAGE macro
3 ;;;; This software is part of the SBCL system. See the README file for
4 ;;;; more information.
5 ;;;;
6 ;;;; This software is derived from the CMU CL system, which was
7 ;;;; written at Carnegie Mellon University and released into the
8 ;;;; public domain. The software is in the public domain and is
9 ;;;; provided with absolutely no warranty. See the COPYING and CREDITS
10 ;;;; files for more information.
12 (in-package "SB-IMPL")
14 ;;; ANSI specifies that:
15 ;;; (1) MAKE-PACKAGE and DEFPACKAGE use the same default package-use-list
16 ;;; (2) that it (as an implementation-defined value) should be documented,
17 ;;; which we do in the doc string.
18 ;;; For OAOO reasons we give a name to this value and then use #. readmacro
19 ;;; to splice it in as a constant. Anyone who actually wants a random value
20 ;;; is free to :USE (PACKAGE-USE-LIST :CL-USER) or whatever.
21 (defglobal *!default-package-use-list* nil)
23 (defmacro sanitize-nicknames (name list)
24 `(let ((list ,list))
25 (when list
26 (remove ,name (remove-duplicates (stringify-string-designators list) :test 'string=)
27 :test 'string=))))
29 (defun make-package (name &key
30 (use '#.*!default-package-use-list*)
31 nicknames
32 (internal-symbols 10)
33 (external-symbols 10))
34 #.(format nil
35 "Make a new package having the specified NAME, NICKNAMES, and USE
36 list. :INTERNAL-SYMBOLS and :EXTERNAL-SYMBOLS are estimates for the number of
37 internal and external symbols which will ultimately be present in the package.
38 The default value of USE is implementation-dependent, and in this
39 implementation it is ~S." *!default-package-use-list*)
40 (let* ((name (stringify-string-designator name))
41 (nicks (sanitize-nicknames name nicknames))
42 (package
43 ;; a "resolved" package is not in the global name->package mapping yet,
44 ;; which is why the FIND-PACKAGE / CERROR below does not signal.
45 (or (resolve-deferred-package name)
46 (%make-package (make-symbol-table internal-symbols)
47 (make-symbol-table external-symbols))))
48 (existing-pkg)
49 (namelist (cons name nicks))
50 (conflict))
51 (setf (symtbl-package (package-external-symbols package)) package)
52 (with-package-names (table) ; get exclusive use of name -> package mapping
53 ;; If the loop runs to completion, then insert all names,
54 ;; which also assigns the %NAME and KEYS slots of the package.
55 (dolist (string namelist (package-registry-update package namelist))
56 (when (setq existing-pkg (%get-package string table))
57 (return (setq conflict string)))))
58 (when existing-pkg
59 ;; Of the possible ways to continue from the "package already exists" error,
60 ;; I've seen implementations offer these:
61 ;; - pick a different name for the new package
62 ;; - return the existing package as-is
63 ;; Other ways to proceed might be:
64 ;; - rename the existing package to something different (mostly harmless)
65 ;; - first delete the existing package (potentially nontrivial)
66 ;; SBCL had the weirdest of all solutions: alter the existing name->package mapping
67 ;; while leaving the old package with a name, but not findable by that name.
68 ;; Imho the safe assumption is that the user wants the same package back.
69 ;; All sorts of crazy restarts would in theory be possible, such as if one nickname
70 ;; that you specified (N1) already finds package P1, and another nickname (N2) finds P2
71 ;; and P1 and P2 are distinct. What are we supposed to do? Figure our that you meant
72 ;; to return the existing P1, but give it an additional nickname, and delete P2?
73 ;; Also bear in mind that for most purposes, a package's multiple "names" are
74 ;; equivalent; one is canonical for printing symbols homed in that package.
75 ;; Global nicknames are an absurdly unnecessary part of the language.
76 (signal-package-cerror name "Return the existing package."
77 "A package named ~S already exists" conflict)
78 ;; We don't do the USE in this case.
79 ;; It's OK given the lack of guidance in CLHS about how to "continue".
80 (return-from make-package existing-pkg))
81 (atomic-incf *package-names-cookie*)
82 (when (boundp 'sb-c::*compilation*)
83 (setf (sb-c::package-environment-changed sb-c::*compilation*) t))
84 (use-package use package)
85 package))
87 ;;; Change the name if we can, blast any old nicknames and then
88 ;;; add in any new ones.
89 ;;;
90 ;;; The spec says that NAME is a package designator (not just a string designator)
91 ;;; which is weird, but potentially meaningful if assigning new global nicknames.
92 ;;; If not called for that purpose, then it's largely pointless, because you can't
93 ;;; rename to any package-designator other than itself without causing a conflict.
94 ;;; A survey of some other implementations suggests that we're in the minority
95 ;;; as to the legality of (RENAME-PACKAGE "A" (FIND-PACKAGE "A") '("A-NICK")).
96 ;;;
97 ;;; ABCL:
98 ;;; The value #<PACKAGE A> is not of type (OR STRING SYMBOL CHARACTER).
99 ;;; CCL:
100 ;;; Error: The value #<Package "A"> is not of the expected type (OR STRING SYMBOL CHARACTER).
101 ;;; CMUCL:
102 ;;; #<The A package, 0/9 internal, 0/9 external> cannot be coerced to a string.
103 ;;; ECL:
104 ;;; In function STRING, the value of the first argument is #<"A" package>
105 ;;; which is not of the expected type STRING
107 ;;; CLISP agrees with us that this usage is permitted. If the new "name" is a
108 ;;; different package, it is merely the same error as if any already-existing name
109 ;;; was given. I see no reason to be more strict than the spec would have it be.
110 (defun rename-package (package-designator name &optional (nicknames ()))
111 "Changes the name and nicknames for a package."
112 ;; CLHS says:
113 ;; "The consequences are undefined if new-name or any new-nickname
114 ;; conflicts with any existing package names."
115 ;; Signaling an error is what most implementations do. So shall we now.
116 ;; (There is no portable standard way to proceed)
117 (let* ((package (find-undeleted-package-or-lose package-designator))
118 ;; This potentially allows the "weirdness" alluded to above
119 (name (stringify-package-designator name))
120 (nicknames (sanitize-nicknames name nicknames))
121 (namelist (cons name nicknames))
122 (conflict))
123 (with-single-package-locked-error ()
124 (unless (and (string= name (package-name package))
125 (null (set-difference nicknames (package-%nicknames package)
126 :test #'string=))
127 (null (set-difference (package-%nicknames package) nicknames
128 :test #'string=)))
129 (assert-package-unlocked
130 package "renaming as ~A~@[ with nickname~*~P ~1@*~{~A~^, ~}~]"
131 name nicknames (length nicknames))))
132 (with-package-names (table)
133 ;; get exclusive use of name -> package mapping
134 ;; and also prevent concurrent modification to this package's names.
135 (dolist (string namelist (package-registry-update package namelist))
136 (let ((found (%get-package string table)))
137 (cond ((eq found package))
138 (found (return (setq conflict string)))))))
139 (cond (conflict
140 (signal-package-error
141 ;; avoid saying "another package ... has name X" so the pedants
142 ;; don't complain when X is a "nickname" rather than "name"
143 package "Another package is already accessible via name ~S" conflict))
145 (atomic-incf *package-names-cookie*)
146 (when (boundp 'sb-c::*compilation*)
147 (setf (sb-c::package-environment-changed sb-c::*compilation*) t))
148 package))))
150 (defun delete-package (package-designator)
151 "Delete the package designated by PACKAGE-DESIGNATOR from the package
152 system data structures."
153 (when (and (packagep package-designator)
154 (not (package-%name package-designator))) ; already deleted
155 (return-from delete-package nil))
156 (tagbody :restart
157 (let ((package (find-package package-designator)))
158 (cond ((not package)
159 ;; This continuable error is required by ANSI.
160 (signal-package-cerror
161 package-designator
162 "Ignore."
163 "There is no package named ~S." package-designator)
164 (return-from delete-package nil))
166 (with-single-package-locked-error
167 (:package package "deleting package ~A" package)
168 (let ((use-list (package-used-by-list package)))
169 (when use-list
170 ;; This continuable error is specified by ANSI.
171 (signal-package-cerror
172 package
173 "Remove dependency in other packages."
174 "~@<Package ~S is used by package~P:~2I~_~S~@:>"
175 (package-name package)
176 (length use-list)
177 (mapcar #'package-name use-list))
178 (dolist (p use-list)
179 (unuse-package package p))))
180 (dolist (p (package-implements-list package))
181 (remove-implementation-package package p))
182 (with-package-graph ()
183 ;; Check for races, restart if necessary.
184 (let ((package2 (find-package package-designator)))
185 (when (or (neq package package2) (package-used-by-list package2))
186 (go :restart)))
187 (dolist (used (package-use-list package))
188 (unuse-package used package))
189 (setf (package-%local-nicknames package) nil)
190 (flet ((nullify-home (symbols)
191 (dovector (x (symtbl-cells symbols))
192 (when (and (symbolp x)
193 (eq (symbol-package x) package))
194 (%set-symbol-package x nil)))))
195 (nullify-home (package-internal-symbols package))
196 (nullify-home (package-external-symbols package)))
197 (with-package-names ()
198 (package-registry-update package nil)
199 (awhen (package-id package)
200 (setf (aref *id->package* it) nil (package-id package) nil))
201 (setf (package-%name package) nil
202 ;; Setting PACKAGE-%NAME to NIL is required in order to
203 ;; make PACKAGE-NAME return NIL for a deleted package as
204 ;; ANSI requires. Setting the other slots to NIL
205 ;; and blowing away the SYMBOL-TABLEs is just done
206 ;; for tidiness and to help the GC.
207 (package-keys package) #()))
208 (atomic-incf *package-names-cookie*)
209 (when (boundp 'sb-c::*compilation*)
210 (setf (sb-c::package-environment-changed sb-c::*compilation*) t))
211 (setf (package-tables package) #()
212 (package-%shadowing-symbols package) nil
213 (package-internal-symbols package) (make-symbol-table 0)
214 (package-external-symbols package) (make-symbol-table 0)))
215 (return-from delete-package t)))))))
217 ;;; Possible FIXME:
218 ;;; After doing these 2 things:
219 ;;; (defpackage "P" (:nicknames "PNICK" "PNICK2"))
220 ;;; (defpackage "P" (:nicknames "NN"))
221 ;;; how many nicknames has "P" - 1, 2, 3?
222 ;;; The case for 1 is that DEFPACKAGE says:
223 ;;; "The arguments to :nicknames set the package's nicknames to the supplied names."
224 ;; [ECL interprets the redefinition thusly]
225 ;;; The case for 2 is that it says:
226 ;;; "If defined-package-name already refers to an existing package,
227 ;;; the name-to-package mapping for that name is not changed."
228 ;;; [ABCL interprets the redefinition thusly]
229 ;;; The case for 3 is that nicknames are cumulative.
230 ;;; [SBCL interprets the redefinition thusly]
231 ;;; I suspect that any treatment is fine as long as its documented.
232 ;;; Relatedly, ECL and ABCL take a redefinition with 0 nicknames as follows:
233 ;;; (defpackage "P" (:nicknames))
234 ;;; to imply _no_ _change_ to existing nicknames, while CLISP removes any nicknames.
236 (defmacro defpackage (package &rest options)
237 #.(format nil
238 "Defines a new package called PACKAGE. Each of OPTIONS should be one of the
239 following: ~{~&~4T~A~}
240 All options except ~{~A, ~}and :DOCUMENTATION can be used multiple
241 times."
242 '((:use "{package-name}*")
243 (:export "{symbol-name}*")
244 (:import-from "<package-name> {symbol-name}*")
245 (:shadow "{symbol-name}*")
246 (:shadowing-import-from "<package-name> {symbol-name}*")
247 (:local-nicknames "{(local-nickname actual-package-name)}*")
248 (:lock "boolean")
249 (:implement "{package-name}*")
250 (:documentation "doc-string")
251 (:intern "{symbol-name}*")
252 (:size "<integer>")
253 (:nicknames "{package-name}*"))
254 '(:size :lock))
255 (let ((nicknames nil)
256 (local-nicknames nil)
257 (size nil)
258 (shadows nil)
259 (shadowing-imports nil)
260 (use nil)
261 (use-p nil)
262 (imports nil)
263 (interns nil)
264 (exports nil)
265 (package (stringify-string-designator package))
266 (implement nil)
267 (implement-p nil)
268 (lock nil)
269 (doc nil)
270 (optname nil)
271 (optval nil)
272 (seen nil))
273 (dolist (option options)
274 (unless (consp option)
275 (%program-error "bogus DEFPACKAGE option: ~S" option))
276 (setq optname (car option) optval (cdr option))
277 (case optname
278 ((:documentation :size :lock)
279 (when (memq optname seen)
280 (%program-error "can't specify ~S more than once." optname))
281 (unless (typep optval '(cons t null))
282 (%program-error "~S expects a single argument. Got ~S"
283 (car option) (cdr option)))
284 (push optname seen)
285 (setq optval (car optval))))
286 (case optname
287 (:nicknames
288 (setf nicknames
289 (append nicknames (stringify-string-designators optval))))
290 (:local-nicknames
291 (setf local-nicknames
292 (append local-nicknames
293 (mapcar (lambda (spec)
294 (destructuring-bind (nick name) spec
295 (cons (stringify-package-designator nick)
296 (stringify-package-designator name))))
297 optval))))
298 (:size
299 (if (typep optval 'unsigned-byte)
300 (setf size optval)
301 (%program-error ":SIZE is not a positive integer: ~S" option)))
302 (:shadow
303 (setf shadows (append shadows (stringify-string-designators optval))))
304 (:shadowing-import-from
305 (let ((package-name (stringify-package-designator (car optval)))
306 (names (stringify-string-designators (cdr optval))))
307 (let ((assoc (assoc package-name shadowing-imports :test #'string=)))
308 (if assoc
309 (setf (cdr assoc) (append (cdr assoc) names))
310 (setf shadowing-imports
311 (acons package-name names shadowing-imports))))))
312 (:use
313 (setf use (append use (stringify-package-designators optval))
314 use-p t))
315 (:import-from
316 (let ((package-name (stringify-package-designator (car optval)))
317 (names (stringify-string-designators (cdr optval))))
318 (let ((assoc (assoc package-name imports :test #'string=)))
319 (if assoc
320 (setf (cdr assoc) (append (cdr assoc) names))
321 (setf imports (acons package-name names imports))))))
322 (:intern
323 (setf interns (append interns (stringify-string-designators optval))))
324 (:export
325 (setf exports (append exports (stringify-string-designators optval))))
326 (:implement
327 (setf implement (append implement (stringify-package-designators optval))
328 implement-p t))
329 (:lock
330 (setf lock (coerce optval 'boolean)))
331 (:documentation
332 (setf doc (possibly-base-stringize optval)))
334 (%program-error "bogus DEFPACKAGE option: ~S" option))))
335 (check-disjoint `(:intern ,@interns) `(:export ,@exports))
336 (check-disjoint `(:intern ,@interns)
337 `(:import-from
338 ,@(apply #'append (mapcar #'rest imports)))
339 `(:shadow ,@shadows)
340 `(:shadowing-import-from
341 ,@(apply #'append (mapcar #'rest shadowing-imports))))
342 `(eval-when (:compile-toplevel :load-toplevel :execute)
343 (%defpackage ,package ',nicknames ',size
344 ',shadows ',shadowing-imports ',(if use-p use :default)
345 ',imports ',interns ',exports
346 ;; FIXME: the default singleton list seems unnecessary.
347 ;; PACKAGE-LOCK-VIOLATION-P considers every package to implement
348 ;; itself. Additionally there's an obvious inconsistency:
349 ;; * (package-implements-list (defpackage "A")) => (#<PACKAGE "A">)
350 ;; * (package-implements-list (make-package "B")) => NIL
351 ',(if implement-p implement (list package))
352 ',local-nicknames
353 ',lock (sb-c:source-location)
354 ,@(and doc
355 `(,doc))))))
357 (defun check-disjoint (&rest args)
358 ;; An arg is (:key . set)
359 (do ((list args (cdr list)))
360 ((endp list))
361 (loop
362 with x = (car list)
363 for y in (rest list)
364 for z = (remove-duplicates (intersection (cdr x)(cdr y) :test #'string=))
365 when z do (%program-error "Parameters ~S and ~S must be disjoint ~
366 but have common elements ~% ~S"
367 (car x) (car y) z))))
369 (flet ((designator-to-string (designator type format-control)
370 (possibly-base-stringize
371 (typecase designator
372 (string designator)
373 (symbol (symbol-name designator))
374 (character (string designator))
375 (t (error 'simple-type-error
376 :datum designator
377 :expected-type type
378 :format-control format-control
379 :format-arguments (list designator)))))))
380 (defun stringify-string-designator (string-designator)
381 (designator-to-string string-designator 'string-designator
382 "~S does not designate a string"))
383 (defun stringify-package-designator (package-designator)
384 (if (packagep package-designator)
385 (package-name package-designator) ; already simple, and base-string when possible
386 (designator-to-string package-designator 'package-designator
387 "~S does not designate a package"))))
389 (defun stringify-string-designators (string-designators)
390 (mapcar #'stringify-string-designator string-designators))
392 (defun stringify-package-designators (package-designators)
393 (mapcar #'stringify-package-designator package-designators))
395 (defun import-list-symbols (import-list)
396 (let ((symbols nil))
397 (dolist (import import-list symbols)
398 (destructuring-bind (package-name &rest symbol-names)
399 import
400 (let ((package (find-undeleted-package-or-lose package-name)))
401 (mapcar (lambda (name)
402 (push (find-or-make-symbol name package) symbols))
403 symbol-names))))))
405 (defun use-list-packages (package package-designators)
406 (cond ((listp package-designators)
407 (mapcar #'find-undeleted-package-or-lose package-designators))
408 (package
409 ;; :default for an existing package means preserve the
410 ;; existing use list
411 (package-use-list package))
413 ;; :default for a new package is the *!default-package-use-list*
414 '#.*!default-package-use-list*)))
416 (defun update-package (package nicknames source-location
417 shadows shadowing-imports
419 imports interns
420 exports implement local-nicknames
421 lock doc-string)
422 (rename-package package (package-name package) nicknames)
423 ;; 1. :shadow and :shadowing-import-from
425 ;; shadows is a list of strings, shadowing-imports is a list of symbols.
426 (shadow shadows package)
427 (shadowing-import shadowing-imports package)
428 ;; 2. :use
430 ;; use is a list of package objects.
431 (use-package use package)
432 ;; 3. :import-from and :intern
434 ;; imports is a list of symbols. interns is a list of strings.
435 (import imports package)
436 (dolist (intern interns)
437 (intern intern package))
438 ;; 4. :export
440 ;; exports is a list of strings
441 (export (mapcar (lambda (symbol-name) (intern symbol-name package))
442 exports)
443 package)
444 ;; 5. :local-nicknames
445 ;; FIXME: See bug at PACKAGE-LOCALLY-NICKNAMED-BY-LIST
446 (setf (package-%local-nicknames package) nil) ; throw out the old ones.
447 (loop :for (nickname . nickname-package) :in local-nicknames :do
448 (%add-package-local-nickname nickname nickname-package package))
449 ;; Everything was created: update metadata
450 (when source-location
451 (setf (package-source-location package) source-location))
452 (setf (package-doc-string package) doc-string)
453 ;; Handle packages this is an implementation package of
454 (dolist (p implement)
455 (add-implementation-package package p))
456 ;; Handle lock
457 (setf (package-lock package) lock)
458 ;; Flush cached FIND-PACKAGE values
459 (atomic-incf *package-names-cookie*)
460 package)
462 (declaim (type list *on-package-variance*))
463 (defvar *on-package-variance* '(:warn t)
464 "Specifies behavior when redefining a package using DEFPACKAGE and the
465 definition is in variance with the current state of the package.
467 The value should be of the form:
469 (:WARN [T | packages-names] :ERROR [T | package-names])
471 specifying which packages get which behaviour -- with T signifying the default unless
472 otherwise specified. If default is not specified, :WARN is used.
474 :WARN keeps as much state as possible and causes SBCL to signal a full warning.
476 :ERROR causes SBCL to signal an error when the variant DEFPACKAGE form is executed,
477 with restarts provided for user to specify what action should be taken.
479 Example:
481 (setf *on-package-variance* '(:warn (:swank :swank-backend) :error t))
483 specifies to signal a warning if SWANK package is in variance, and an error otherwise.")
485 (defun note-package-variance (&rest args &key package &allow-other-keys)
486 (let ((pname (package-name package)))
487 (destructuring-bind (&key warn error) *on-package-variance*
488 (let ((what (cond ((and (listp error) (member pname error :test #'string=))
489 :error)
490 ((and (listp warn) (member pname warn :test #'string=))
491 :warn)
492 ((eq t error)
493 :error)
495 :warn))))
496 (ecase what
497 (:error
498 (apply #'error 'package-at-variance-error args))
499 (:warn
500 (apply #'warn 'package-at-variance args)))))))
502 (defun update-package-with-variance (package name nicknames source-location
503 shadows shadowing-imports
505 imports interns
506 exports
507 implement local-nicknames
508 lock doc-string)
509 (unless (string= (the string (package-name package)) name)
510 (error 'simple-package-error
511 :package name
512 :format-control "~A is a nickname for the package ~A"
513 :format-arguments (list name (package-name name))))
514 (let ((no-longer-shadowed
515 (set-difference (package-%shadowing-symbols package)
516 (append shadows shadowing-imports)
517 :test #'string=)))
518 (when no-longer-shadowed
519 (restart-case
520 (let ((*package* (find-package :keyword)))
521 (note-package-variance
522 :format-control "~A also shadows the following symbols:~% ~S"
523 :format-arguments (list name no-longer-shadowed)
524 :package package))
525 (drop-them ()
526 :report "Stop shadowing them by uninterning them."
527 (dolist (sym no-longer-shadowed)
528 (unintern sym package)))
529 (keep-them ()
530 :report "Keep shadowing them."))))
531 (let ((no-longer-used (set-difference (package-use-list package) use)))
532 (when no-longer-used
533 (restart-case
534 (note-package-variance
535 :format-control "~A also uses the following packages:~% ~A"
536 :format-arguments (list name (mapcar #'package-name no-longer-used))
537 :package package)
538 (drop-them ()
539 :report "Stop using them."
540 (unuse-package no-longer-used package))
541 (keep-them ()
542 :report "Keep using them."))))
543 (let (old-exports)
544 (do-external-symbols (s package)
545 (push s old-exports))
546 (let ((no-longer-exported (set-difference old-exports exports :test #'string=)))
547 (when no-longer-exported
548 (restart-case
549 (note-package-variance
550 :format-control "~A also exports the following symbols:~% ~S"
551 :format-arguments (list name no-longer-exported)
552 :package package)
553 (drop-them ()
554 :report "Unexport them."
555 (unexport no-longer-exported package))
556 (keep-them ()
557 :report "Keep exporting them.")))))
558 (let ((old-implements
559 (set-difference (package-implements-list package)
560 (mapcar #'find-undeleted-package-or-lose implement))))
561 (when old-implements
562 (restart-case
563 (note-package-variance
564 :format-control "~A is also an implementation package for:~% ~{~S~^~% ~}"
565 :format-arguments (list name old-implements)
566 :package package)
567 (drop-them ()
568 :report "Stop being an implementation package for them."
569 (dolist (p old-implements)
570 (remove-implementation-package package p)))
571 (keep-them ()
572 :report "Keep exporting them."))))
573 (update-package package nicknames source-location
574 shadows shadowing-imports
575 use imports interns exports
576 implement local-nicknames
577 lock doc-string))
579 (defun %defpackage (name nicknames size shadows shadowing-imports
580 use imports interns exports implement local-nicknames
581 lock source-location &optional doc)
582 (declare (type simple-string name)
583 (type list nicknames shadows shadowing-imports
584 imports interns exports)
585 (type (or list (member :default)) use)
586 (type (or simple-string null) doc))
587 (with-package-graph ()
588 (let* ((existing-package (find-package name))
589 (use (use-list-packages existing-package use))
590 (shadowing-imports (import-list-symbols shadowing-imports))
591 (imports (import-list-symbols imports)))
592 (if existing-package
593 (update-package-with-variance existing-package name
594 nicknames source-location
595 shadows shadowing-imports
596 use imports interns exports
597 implement local-nicknames
598 lock doc)
599 (let ((package (make-package name
600 :use nil
601 :internal-symbols (or size 10)
602 :external-symbols (length exports))))
603 (update-package package
604 nicknames
605 source-location
606 shadows shadowing-imports
607 use imports interns exports
608 implement local-nicknames
609 lock doc))))))
611 (defun find-or-make-symbol (name package)
612 (multiple-value-bind (symbol how) (find-symbol name package)
613 (cond (how
614 symbol)
616 (with-simple-restart (continue "INTERN it.")
617 (error 'simple-package-error
618 :package package
619 :format-control "no symbol named ~S in ~S"
620 :format-arguments (list name (package-name package))))
621 (intern name package)))))
623 ;;;; APROPOS and APROPOS-LIST
625 (defun briefly-describe-symbol (symbol)
626 (fresh-line)
627 (prin1 symbol)
628 (when (boundp symbol)
629 (let ((value (symbol-value symbol)))
630 (if (typep value '(or fixnum symbol hash-table))
631 (format t " = ~S" value)
632 (format t " (bound, ~S)" (type-of value)))))
633 (when (fboundp symbol)
634 (write-string " (fbound)")))
636 (flet ((add-to-bag-if-found (table string length hash result)
637 (with-symbol ((symbol) table string length hash)
638 ;; HASH-TABLE degenerates to a list when used by FIND-ALL-SYMBOLS
639 ;; since homographs have the same SXHASH, so handle either
640 ;; a hash-table or a cons containing a list.
641 (if (hash-table-p result)
642 (setf (gethash symbol result) t)
643 (pushnew symbol (car result))))))
645 (defun find-all-symbols (string-designator)
646 "Return a list of all symbols in the system having the specified name."
647 (let* ((string (truly-the simple-string
648 (stringify-string-designator string-designator)))
649 (length (length string))
650 (hash (calc-symbol-name-hash string length))
651 (result (list nil)))
652 (do-packages (p) ; FIXME: should not acquire package-names lock
653 (add-to-bag-if-found (package-internal-symbols p) string length hash result)
654 (add-to-bag-if-found (package-external-symbols p) string length hash result))
655 (car result)))
657 (defun apropos-list (string-designator
658 &optional
659 package-designator
660 external-only
661 &aux (string (the simple-string
662 (stringify-string-designator string-designator))))
663 "Like APROPOS, except that it returns a list of the symbols found instead
664 of describing them."
665 (if package-designator ; rare to supply this, I suspect
666 ;; This loop is extremely inefficient because both DO-SYMBOLS and FIND-SYMBOL
667 ;; check for inheritance, which we shouldn't if EXTERNAL-ONLY was given.
668 ;; Technically the external-p test could use FIND-EXTERNAL-SYMBOL but portable code
669 ;; can't care. Somebody did, and noticed that it wasn't working, so it got fixed
670 ;; in rev e92a2f8844d9 which is ironic because it came from CMUCL, which implemented
671 ;; APROPOS differently but then removed the nonstandard option in
672 ;; https://gitlab.common-lisp.net/cmucl/cmucl/-/commit/9f652c0515f90b1fc8166d5099a0cee37e76e07c
673 (let ((package (find-undeleted-package-or-lose package-designator))
674 (result nil))
675 (do-symbols (symbol package)
676 (when (and (or (not external-only)
677 (and (eq (symbol-package symbol) package)
678 (eq (nth-value 1 (find-symbol (symbol-name symbol)
679 package))
680 :external)))
681 (search string (symbol-name symbol) :test #'char-equal))
682 (pushnew symbol result)))
683 (return-from apropos-list (sort result #'string-lessp))))
684 ;; Since we're going to scan all packages, there are two admissible optimizations:
685 ;; * only scan directly present symbols, because each symbol returned has to
686 ;; be in some package.
687 ;; * if the table was not modified since core save, as is often the case,
688 ;; then compare by EQ to set of possibly matching strings. This has to be
689 ;; an improvement, because it compares STRING at most once to any symbol-name.
691 ;; Comparison of (TIME (APROPOS-LIST "str")) in a core with over 300,000 symbols:
692 ;; .840 seconds = baseline
693 ;; .140 seconds = inlining WITH-SYMBOL
694 ;; .104 seconds = MODIFIED check then R/O scan or else WITH-SYMBOL
695 (let (candidates)
696 (block done
697 (sb-vm:map-allocated-objects
698 (lambda (obj widetag size)
699 (declare (ignore size))
700 (cond ((or (= widetag sb-vm:simple-base-string-widetag)
701 #+sb-unicode
702 (= widetag sb-vm:simple-character-string-widetag))
703 (when (search string obj :test #'char-equal)
704 (push (cons (calc-symbol-name-hash obj (length obj)) obj) candidates)))
706 (return-from done))))
707 :read-only))
708 (let ((result (make-hash-table :test 'eq))
709 ;; darwin-jit will never take the purified branch. Readonly space exists,
710 ;; but contains no symbol names. TUNE-HASHSET-SIZES-OF-ALL-PACKAGES knows that
711 ;; and will never reset a table's MODIFIED flag. However, for all other platforms,
712 ;; we need to detect if purification happened.
713 (core-purified-p (sap> sb-vm:*read-only-space-free-pointer*
714 (sb-sys:int-sap sb-vm:read-only-space-start))))
715 (flet ((find-all-in-table (table)
716 (if (and core-purified-p (not (symtbl-modified table)))
717 (dolist (candidate candidates)
718 (let* ((hash (the hash-code (car candidate)))
719 (string (the simple-string (cdr candidate)))
720 (length (length string)))
721 (add-to-bag-if-found table string length hash result)))
722 (dovector (entry (symtbl-cells table))
723 ;; I would have guessed that GETHASH is faster than SEARCH, but if
724 ;; interposed between SYMBOLP and SEARCH, it slows down this loop.
725 ;; That's because almost always the symbol is NOT yet in the result,
726 ;; so an extra GETHASH is a strict increase in the number of
727 ;; instructions executed, for no net reduction in time.
728 (when (and (symbolp entry)
729 (search string (symbol-name entry) :test #'char-equal))
730 (setf (gethash entry result) t))))))
731 (do-packages (package) ; FIXME: should not acquire package-names lock
732 (find-all-in-table (package-external-symbols package))
733 (unless external-only
734 (find-all-in-table (package-internal-symbols package)))))
735 (sort (loop for k being each hash-key of result collect k) #'string-lessp))))
736 ) ; end FLET
738 (defun apropos (string-designator &optional package external-only)
739 "Briefly describe all symbols which contain the specified STRING.
740 If PACKAGE is supplied then only describe symbols present in
741 that package. If EXTERNAL-ONLY then only describe
742 external symbols in the specified package."
743 ;; Implementing this in terms of APROPOS-LIST keeps things simple at the cost
744 ;; of some unnecessary consing; and the unnecessary consing shouldn't be an
745 ;; issue, since this function is is only useful interactively anyway, and
746 ;; we can cons and GC a lot faster than the typical user can read..
747 (dolist (symbol (apropos-list string-designator package external-only))
748 (briefly-describe-symbol symbol))
749 (values))
751 ;;; NOTE: the comments below no longer hold. I can't remember what exactly was broken about
752 ;;; perfect hashing on most packages as long as we downgrade to a hashset on demand.
753 ;;; The FIXME below says it isn't thread-safe, but why not?
755 ;;; Reorganize both hashsets of all packages, called by SAVE-LISP-AND-DIE.
756 ;;; With a few exceptions, tables are saved at 100% load factor and a perfect hash.
757 ;;; The danger of attempting to achieve such high load using an open-addressing table
758 ;;; is that despite the robinhood algorithm rearranging elements, there could always
759 ;;; be a tremendously bad probe sequence for some symbol, not to mention that unused
760 ;;; cells must be scattered throughout, to assure probing always terminates.
761 ;;; The relevant benchmark is how quickly we can return that a symbol is NOT found.
762 ;;; Test case:
763 ;;; * (defvar *l* (let (l) (do-all-symbols (s l) (push s l))))
764 ;;; * (defun f (list &aux (n 0))
765 ;;; (dolist (s list n) (if (find-symbol (string s) #.(find-package "CL")) (incf n))))
766 ;;; * (time (f *l*))
768 ;;; Freshly restarted image after save-lisp-and-die without perfect hash:
769 ;;; 0.017 seconds of real time
771 ;;; Freshly restarted image with perfect hash:
772 ;;; 0.012 seconds of real time
774 (defun tune-hashset-sizes-of-all-packages ()
775 (flet ((tune (desired-lf table)
776 (resize-symbol-table table (%symtbl-count table) 'intern desired-lf))
777 (perfect (table &aux (cells (symtbl-%cells table)))
778 (when (functionp (car cells))
779 (return-from perfect)) ; already perfectly hashed
780 (let* ((cells (cdr cells))
781 (hashes (map '(simple-array (unsigned-byte 32) (*))
782 #'symbol-name-hash
783 (remove-if-not #'symbolp cells)))
784 (hash-expr (sb-c:make-perfect-hash-lambda hashes)))
785 (unless hash-expr
786 ;; hmm, this seems like it should be a hard error
787 ;; since it's confined to the CL package.
788 (return-from perfect))
789 (let ((fun (compile nil hash-expr))
790 (new-cells (make-array (length hashes) :initial-element 0)))
791 (dovector (s cells)
792 (when (symbolp s)
793 (let ((hash (funcall fun (symbol-name-hash s))))
794 (aver (eq (svref new-cells hash) 0))
795 (setf (svref new-cells hash) s))))
796 (setf (symtbl-%cells table) (cons fun new-cells)
797 (symtbl-size table) (length hashes)
798 (symtbl-free table) 0
799 (symtbl-deleted table) 0)))))
800 (dolist (package (list-all-packages))
801 ;; Choose load factor based on whether INTERN is expected at runtime
802 ;; FIXME: because changing a package from perfectly hashed back to
803 ;; an open-addressing table is not thread-safe, _only_ the CL package can
804 ;; become perfectly hashed.
805 (let ((lf (cond ((eq (the package package) *keyword-package*) 60/100)
806 ((eq package *cl-package*) 1)
807 (t 8/10)))
808 (internals (package-internal-symbols (truly-the package package)))
809 (externals (package-external-symbols package)))
810 (cond ((= lf 1)
811 ;; Should be no internals of CL, don't even bother tuning them
812 (perfect externals))
814 (tune lf internals)
815 (tune lf externals)))
816 ;; The APROPOS-LIST R/O scan optimization is inadmissible if no R/O space
817 #-darwin-jit
818 (setf (symtbl-modified externals) nil
819 (symtbl-modified internals) nil)))))
821 ;;; This function is mainly of interest to developers, should we remove it
822 ;;; from the image?
823 (export 'show-package-utilization)
824 (defun show-package-utilization (&aux (tot-ncells 0))
825 (flet ((metrics (table &aux (cells (symtbl-%cells table))
826 (reciprocals (car cells))
827 (vec (cdr cells))
828 (nslots (length vec)))
829 (when (functionp reciprocals)
830 (return-from metrics (values 1 1 1))) ; 1 probe max+avg, 100% load
831 (flet ((probe-seq-len (symbol)
832 (let* ((name-hash (symbol-name-hash symbol))
833 (index (symbol-table-hash 1 name-hash nslots))
834 (h2 (symbol-table-hash 2 name-hash nslots))
835 (nprobes 1))
836 (loop (if (eq (svref vec index) symbol) (return nprobes))
837 (setq index (rem (+ index h2) nslots))
838 (incf nprobes)))))
839 (let ((nsymbols 0) (max-nprobes 0) (sum-nprobes 0))
840 (dovector (symbol (symtbl-cells table))
841 (when (symbolp symbol)
842 (incf nsymbols)
843 (let ((n (probe-seq-len symbol)))
844 (setq max-nprobes (max n max-nprobes))
845 (incf sum-nprobes n))))
846 (when (plusp nsymbols)
847 (values max-nprobes
848 (float (/ sum-nprobes nsymbols))
849 (float (/ nsymbols nslots))))))))
850 (dolist (pkg (list-all-packages))
851 (binding* ((ext (package-external-symbols pkg))
852 (int (package-internal-symbols pkg))
853 ((ext-max ext-psl ext-lf) (metrics ext))
854 ((int-max int-psl int-lf) (metrics int))
855 (ncells (+ (length (symtbl-cells int))
856 (length (symtbl-cells ext)))))
857 (incf tot-ncells ncells)
858 (format t "~8d ~:{~:[~2*~18@t~;~:* ~2d ~6,2f ~5,1,2f%~] |~} ~a~%"
859 ncells
860 (list (list ext-max ext-psl ext-lf)
861 (list int-max int-psl int-lf))
862 (package-name pkg))))
863 (format t "~8d~%" tot-ncells)))
865 (let ((package (find-package "SB-SEQUENCE")))
866 (rename-package package package (list "SEQUENCE")))