(name thunk &key (truename (probe-file name)) location)
"Construct a new module.
- This is the functionality underlying `define-module'."
-
+ This is the functionality underlying `define-module': see that macro for
+ full information."
+
+ ;; Check for an import cycle.
+ (when truename
+ (let ((existing (gethash truename *module-map*)))
+ (cond ((null existing))
+ ((eq (module-state existing) t)
+ (return-from build-module existing))
+ (t
+ (error "Module ~A already being imported at ~A"
+ name (module-state existing))))))
+
+ ;; Construct the new module.
(let ((*module* (make-instance 'module
:name (pathname name)
:state (file-location location))))
(cons 'list constraint))
constraints))))))
+;;;--------------------------------------------------------------------------
+;;; File searching.
+
+(export '*module-dirs*)
+(defparameter *module-dirs* nil
+ "A list of directories (as pathname designators) to search for files.
+
+ Both SOD module files and Lisp extension files are searched for in this
+ list. The search works by merging the requested pathname with each
+ element of this list in turn. The list is prefixed by the pathname of the
+ requesting file, so that it can refer to other files relative to wherever
+ it was found.
+
+ See `find-file' for the grubby details.")
+
+(export 'find-file)
+(defun find-file (scanner name what thunk)
+ "Find a file called NAME on the module search path, and call THUNK on it.
+
+ The file is searched for relative to the SCANNER's current file, and also
+ in the directories mentioned in the `*module-dirs*' list. If the file is
+ found, then THUNK is invoked with two arguments: the name we used to find
+ it (which might be relative to the starting directory) and the truename
+ found by `probe-file'.
+
+ If the file wasn't found, or there was some kind of error, then an error
+ is signalled; WHAT should be a noun phrase describing the kind of thing we
+ were looking for, suitable for inclusion in the error message.
+
+ While `find-file' establishes condition handlers for its own purposes,
+ THUNK is not invoked with any additional handlers defined."
+
+ (handler-case
+ (dolist (dir (cons (pathname (scanner-filename scanner)) *module-dirs*)
+ (values nil nil))
+ (let* ((path (merge-pathnames name dir))
+ (probe (probe-file path)))
+ (when probe
+ (return (values path probe)))))
+ (file-error (error)
+ (error "Error searching for ~A ~S: ~A" what (namestring name) error))
+ (:no-error (path probe)
+ (cond ((null path)
+ (error "Failed to find ~A ~S" what (namestring name)))
+ (t
+ (funcall thunk path probe))))))
+
;;;----- That's all, folks --------------------------------------------------