mirror of
https://gitlab.com/embeddable-common-lisp/ecl.git
synced 2026-01-27 06:51:44 -08:00
189 lines
7.7 KiB
Common Lisp
189 lines
7.7 KiB
Common Lisp
;;;; -*- Mode: Lisp; Syntax: Common-Lisp; indent-tabs-mode: nil; Package: SYSTEM -*-
|
||
;;;; vim: set filetype=lisp tabstop=8 shiftwidth=2 expandtab:
|
||
|
||
;;;;
|
||
;;;; Copyright (c) 1984, Taiichi Yuasa and Masami Hagiya.
|
||
;;;; Copyright (c) 1990, Giuseppe Attardi.
|
||
;;;; Copyright (c) 2001, Juan Jose Garcia Ripoll.
|
||
;;;;
|
||
;;;; See file 'LICENSE' for the copyright details.
|
||
|
||
;;;; package routines
|
||
|
||
(in-package "SYSTEM")
|
||
|
||
(defun find-all-symbols (string-or-symbol)
|
||
"Args: (string-designator)
|
||
Returns a list of all symbols that have the specified print name.
|
||
STRING-DESIGNATOR may be a symbol, in which case the print name of the symbol
|
||
is used."
|
||
(let ((symbol-name (string string-or-symbol)))
|
||
(mapcan #'(lambda (p)
|
||
(multiple-value-bind (s i)
|
||
(find-symbol symbol-name p)
|
||
(if (or (eq i :internal) (eq i :external))
|
||
(list s)
|
||
nil)))
|
||
(list-all-packages))))
|
||
|
||
(defun packages-iterator (packages options maybe-list)
|
||
(let ((all-symbols nil))
|
||
(when (or (atom packages) (not maybe-list))
|
||
(setq packages (list packages)))
|
||
(dolist (p packages)
|
||
(let ((package (si::coerce-to-package p)))
|
||
(multiple-value-bind (hash-ext hash-int packages-used)
|
||
(si::package-hash-tables package)
|
||
(when (member :external options)
|
||
(push (list package :external hash-ext) all-symbols))
|
||
(when (member :internal options)
|
||
(push (list package :internal hash-int) all-symbols))
|
||
(when (member :inherited options)
|
||
(dolist (p packages-used)
|
||
(push (list package :inherited (si::package-hash-tables p))
|
||
all-symbols))))))
|
||
(unless all-symbols
|
||
(return-from packages-iterator #'(lambda () (values nil nil nil nil))))
|
||
(let* ((current (pop all-symbols))
|
||
(package (first current))
|
||
(type (second current))
|
||
(iterator (si::hash-table-iterator (third current))))
|
||
(flet ((iterate ()
|
||
(tagbody
|
||
AGAIN
|
||
(multiple-value-bind (found key value)
|
||
(funcall iterator)
|
||
(declare (ignore key))
|
||
(cond
|
||
(found
|
||
(when (eq type :inherited)
|
||
(multiple-value-bind (s access)
|
||
(find-symbol (symbol-name value) package)
|
||
(unless (and (eq s value) (eq access type))
|
||
(go AGAIN))))
|
||
(return-from iterate (values t value type package)))
|
||
((null all-symbols)
|
||
(return-from iterate (values nil nil nil nil)))
|
||
(t
|
||
(setq current (pop all-symbols))
|
||
(setq package (first current)
|
||
type (second current)
|
||
iterator (si::hash-table-iterator (third current))
|
||
))))
|
||
(go AGAIN))))
|
||
#'iterate))))
|
||
|
||
(defmacro with-package-iterator ((iterator package-list &rest conditions)
|
||
&rest body)
|
||
(if conditions
|
||
(let ((aux (set-difference conditions '(:external :internal :inherited))))
|
||
(when aux
|
||
(signal-simple-error 'program-error nil "Clauses ~{~S~} are not allowed."
|
||
(list aux))))
|
||
(signal-simple-error 'program-error
|
||
nil
|
||
"Must supply at least one of :inherited, :external or :internal"
|
||
nil))
|
||
`(let ((,iterator (packages-iterator ,package-list ',conditions t)))
|
||
(macrolet ((,iterator () (list 'funcall ',iterator)))
|
||
,@body)))
|
||
|
||
(defun expand-do-symbols (var package result-form body options)
|
||
(declare (si::c-local))
|
||
(let* ((i (gensym))
|
||
(found (gensym))
|
||
declaration doc)
|
||
(multiple-value-setq (declaration body doc)
|
||
(find-declarations body nil))
|
||
`(do* ((,i (packages-iterator ,package ',options t))
|
||
,found ,var)
|
||
(nil)
|
||
,@declaration
|
||
(multiple-value-setq (,found ,var) (funcall ,i))
|
||
(unless ,found (return ,result-form))
|
||
,@body)))
|
||
|
||
(defmacro do-symbols ((var &optional (package '*package*) (result-form nil))
|
||
&rest body)
|
||
"Syntax: (do-symbols (var [package [result]])
|
||
{decl}* {tag | statement}*)
|
||
Executes STATEMENTs once for each symbol in PACKAGE (which defaults to the
|
||
current package), with VAR bound to the symbol. Then evaluates RESULT (which
|
||
defaults to NIL) and returns all values."
|
||
(expand-do-symbols var package result-form body '(:inherited :internal :external)))
|
||
|
||
(defmacro do-external-symbols
|
||
((var &optional (package '*package*) (result-form nil)) &rest body)
|
||
"Syntax: (do-external-symbols (var [package [result]])
|
||
{decl}* {tag | statement}*)
|
||
Establishes a NIL block and executes STATEMENTs once for each external symbol
|
||
in PACKAGE (which defaults to the current package), with VAR bound to the
|
||
variable. Then evaluates RESULT (which defaults to NIL) and returns all
|
||
values."
|
||
(expand-do-symbols var package result-form body '(:external)))
|
||
|
||
(defmacro do-all-symbols ((var &optional (result-form nil)) &rest body)
|
||
"Syntax: (do-all-symbols (var [result]) {decl}* {tag | statement}*)
|
||
Establishes a NIL block and executes STATEMENTs once for each symbol in each
|
||
package, with VAR bound to the symbol. Then evaluates RESULT (which defaults
|
||
to NIL) and returns all values."
|
||
(expand-do-symbols var '(list-all-packages) result-form body '(:internal :external)))
|
||
|
||
(defun print-symbol-apropos (symbol)
|
||
(prin1 symbol)
|
||
(when (fboundp symbol)
|
||
(if (special-operator-p symbol)
|
||
(princ " Special form")
|
||
(if (macro-function symbol)
|
||
(princ " Macro")
|
||
(princ " Function"))))
|
||
(when (boundp symbol)
|
||
(if (constantp symbol)
|
||
(princ " Constant: ")
|
||
(princ " has value: "))
|
||
(prin1 (symbol-value symbol)))
|
||
(terpri))
|
||
|
||
|
||
(defun apropos (string &optional package)
|
||
"Args: (string &optional (package nil))
|
||
Prints those symbols whose print-names contain STRING as substring. If
|
||
PACKAGE is non-NIL, then only the specified PACKAGE is searched."
|
||
(setq string (string string))
|
||
(mapc #'print-symbol-apropos (apropos-list string package))
|
||
(values))
|
||
|
||
(defun apropos-list (string &optional package)
|
||
"Args: (string &optional (package nil))
|
||
Returns a list of all symbols whose print-names contain STRING as substring.
|
||
If PACKAGE is non-NIL, then only the specified PACKAGE is searched."
|
||
(sort (delete-duplicates (apropos-list-inner string package))
|
||
#'(lambda (s1 s2)
|
||
(string-lessp (prin1-to-string s1)
|
||
(prin1-to-string s2)))))
|
||
|
||
(defun apropos-list-inner (string package)
|
||
(declare (si::c-local))
|
||
(let* ((list '())
|
||
(string (string string)))
|
||
(cond (package
|
||
(dolist (p (package-use-list package))
|
||
(setf list (nconc (apropos-list-inner string p) list)))
|
||
(do-symbols (symbol package)
|
||
(when (search string (string symbol) :test #'char-equal)
|
||
(setq list (cons symbol list)))))
|
||
(t
|
||
(do-all-symbols (symbol)
|
||
(when (search string (string symbol) :test #'char-equal)
|
||
(setq list (cons symbol list))))))
|
||
list))
|
||
|
||
|
||
;; Package local nicknames
|
||
(defun add-package-local-nickname (local-nickname nicknamed-package
|
||
&optional (package *package*))
|
||
(si:%add-package-local-nickname local-nickname nicknamed-package package))
|
||
|
||
(defun remove-package-local-nickname (old-nickname
|
||
&optional (package *package*))
|
||
(si:%remove-package-local-nickname old-nickname package))
|