? require.diff Index: module.lsp =================================================================== RCS file: /cvsroot/ecls/ecls/src/lsp/module.lsp,v retrieving revision 1.3 diff -u -r1.3 module.lsp --- module.lsp 15 Oct 2001 16:44:04 -0000 1.3 +++ module.lsp 16 Feb 2005 21:07:51 -0000 @@ -10,37 +10,57 @@ ;;;; module routines +;; This is taken from SBCL's code/module.lisp which is in the public +;; domain. + (in-package "SYSTEM") -(defvar *modules* nil - "List of module names that have been loaded into ECL. -See PROVIDE and REQUIRE.") +;;;; exported specials + +(defvar *modules* () + "This is a list of module names that have been loaded into Lisp so far. + It is used by PROVIDE and REQUIRE.") + +(defvar *module-provider-functions* nil + "See function documentation for REQUIRE") + +;;;; PROVIDE and REQUIRE (defun provide (module-name) - "Args: (module-name) -Declares the start of a program module. Usually used at the beginning of a -program file. MODULE-NAME may be a string or a symbol. If it is a string, it -is pushed onto *MODULES*. If it is a symbol, its print name is pushed. See -REQUIRE." - (setq *modules* - (adjoin (string module-name) *modules* :test #'string=))) - - -(defun require (module-name - &optional (pathname (string-downcase (string module-name)))) - "Args: (module-name &optional pathname) -If the specified module name is not found in *MODULES*, then loads the files -specified by PATHNAME. Otherwise, does nothing. MODULE-NAME may be a string -or a symbol. If it is a symbol, the print name of the symbol is used as the -module name. PATHNAME may be a pathname object or it may be a list of -pathname objects. If PATHNAME is not given, then ECL tries to load the file -whose file name is MODULE-NAME and whose filetype is either .FASL, .LSP, or -none. See PROVIDE." - (let ((*default-pathname-defaults* #P"")) - (unless (member (string module-name) - *modules* :test #'string=) - (if (atom pathname) - (load pathname) - (dolist (p pathname) - (load p)))))) + "Adds a new module name to *MODULES* indicating that it has been loaded. + Module-name is a string designator" + (pushnew (string module-name) *modules* :test #'string=) + t) + +(defvar *requiring* nil) + +(defun require-error (control &rest arguments) + (error "Module error: ~?" control arguments)) +(defun require (module-name &optional pathnames) + "Loads a module, unless it already has been loaded. PATHNAMES, if supplied, + is a designator for a list of pathnames to be loaded if the module + needs to be. If PATHNAMES is not supplied, functions from the list + *MODULE-PROVIDER-FUNCTIONS* are called in order with MODULE-NAME + as an argument, until one of them returns non-NIL. User code is + responsible for calling PROVIDE to indicate a successful load of the + module." + (let ((name (string module-name))) + (when (member name *requiring* :test #'string=) + (require-error "~@" 'require module-name)) + (let ((saved-modules (copy-list *modules*)) + (*requiring* (cons name *requiring*))) + (unless (member name *modules* :test #'string=) + (cond (pathnames + (unless (listp pathnames) (setf pathnames (list pathnames))) + ;; ambiguity in standard: should we try all pathnames in the + ;; list, or should we stop as soon as one of them calls PROVIDE? + (dolist (ele pathnames t) + (load ele))) + (t + (unless (some (lambda (p) (funcall p module-name)) + *module-provider-functions*) + (require-error "Don't know how to ~S ~A." + 'require module-name))))) + (set-difference *modules* saved-modules))))