(in-package #:ql-impl) (eval-when (:compile-toplevel :load-toplevel :execute) (defun error-unimplemented (&rest args) (declare (ignore args)) (error "Not implemented"))) (defvar *interfaces* (make-hash-table) "A table of defined interfaces and their documentation.") (defun show-interfaces () "Display information about what interfaces are defined." (maphash (lambda (interface info) (destructuring-bind (arguments docstring) info (let ((*package* (find-package :keyword))) (format t "(~S ~:[()~;~:*~A~]~@[~% ~S~])~%" interface arguments docstring)))) *interfaces*)) (defmacro neuter-package (name) `(eval-when (:compile-toplevel :load-toplevel :execute) (let ((definition (fdefinition 'error-unimplemented))) (do-external-symbols (symbol ,(string name)) (unless (fboundp symbol) (setf (fdefinition symbol) definition)))))) (eval-when (:compile-toplevel :load-toplevel :execute) (defun feature-expression-passes-p (expression) (cond ((keywordp expression) (member expression *features*)) ((consp expression) (case (first expression) (or (some 'feature-expression-passes-p (rest expression))) (and (every 'feature-expression-passes-p (rest expression))))) (t (error "Unrecognized feature expression -- ~S" expression))))) (defmacro define-implementation-package (feature package-name &rest options) (let* ((output-options '((:use) (:export #:lisp))) (prep (cdr (assoc :prep options))) (class-option (cdr (assoc :class options))) (class (first class-option)) (superclasses (rest class-option)) (import-options '()) (effectivep (feature-expression-passes-p feature))) (dolist (option options) (ecase (first option) ((:prep :class)) ((:import-from :import) (push option import-options)) ((:export :shadow :intern :documentation) (push option output-options)) ((:reexport-from) (push (cons :export (cddr option)) output-options) (push (cons :import-from (cdr option)) import-options)))) `(progn ,@(when effectivep `((eval-when (:compile-toplevel :load-toplevel :execute) ,@prep))) (defclass ,class ,superclasses ()) (defpackage ,package-name ,@output-options ,@(when effectivep import-options)) ,@(when effectivep `((setf *implementation* (make-instance ',class)))) ,@(unless effectivep `((neuter-package ,package-name)))))) (defmacro definterface (name lambda-list &body options) (let* ((doc-option (find :documentation options :key #'first)) (doc (second doc-option))) (setf (gethash name *interfaces*) (list lambda-list doc))) (let* ((forbidden (intersection lambda-list lambda-list-keywords)) (gf-options (remove :implementation options :key #'first)) (implementations (set-difference options gf-options)) (implementation-arg (copy-symbol '%implementation))) (when forbidden (error "~S not allowed in definterface lambda list" forbidden)) (flet ((method-option (class body) `(:method ((,implementation-arg ,class) ,@lambda-list) ,@body))) (let ((generic-name (intern (format nil "%~A" name)))) `(progn (defgeneric ,generic-name (lisp ,@lambda-list) ,@gf-options ,@(mapcan (lambda (implementation) (destructuring-bind (class &rest body) (rest implementation) (mapcar (lambda (class) (method-option class body)) (if (consp class) class (list class))))) implementations)) (defun ,name ,lambda-list (,generic-name *implementation* ,@lambda-list))))))) (defmacro defimplementation (name-and-options lambda-list &body body) (destructuring-bind (name &key (for t) qualifier) (if (consp name-and-options) name-and-options (list name-and-options)) (unless for (error "You must specify an implementation name.")) (let ((generic-name (find-symbol (format nil "%~A" name))) (implementation-arg (copy-symbol '%implementation))) (unless generic-name (error "~S does not name an implementation function" name)) `(defmethod ,generic-name ,@(when qualifier (list qualifier)) ,(list* `(,implementation-arg ,for) lambda-list) ,@body)))) ;;; Bootstrap implementations (defvar *implementation* nil) (defclass lisp () ()) ;;; Allegro Common Lisp (define-implementation-package :allegro #:ql-allegro (:documentation "Allegro Common Lisp - http://www.franz.com/products/allegrocl/") (:class allegro) (:reexport-from #:socket #:make-socket) (:reexport-from #:excl #:file-directory-p #:delete-directory #:delete-directory-and-files #:read-vector)) ;;; Armed Bear Common Lisp (define-implementation-package :abcl #:ql-abcl (:documentation "Armed Bear Common Lisp - http://common-lisp.net/project/armedbear/") (:class abcl) (:reexport-from #:ext #:make-socket #:get-socket-stream)) ;;; Clozure CL (define-implementation-package :ccl #:ql-ccl (:documentation "Clozure Common Lisp - http://www.clozure.com/clozurecl.html") (:class ccl) (:reexport-from #:ccl #:delete-directory #:make-socket #:native-translated-namestring)) ;;; CLASP (define-implementation-package :clasp #:ql-clasp (:documentation "CLASP - http://github.com/drmeister/clasp") (:class clasp) (:prep (require 'sockets)) (:intern #:host-network-address) (:reexport-from #:si #:rmdir #:file-kind) (:reexport-from #:sb-bsd-sockets #:get-host-by-name #:host-ent-address #:inet-socket #:socket-connect #:socket-make-stream)) ;;; GNU CLISP (define-implementation-package :clisp #:ql-clisp (:documentation "GNU CLISP - http://clisp.cons.org/") (:class clisp) (:reexport-from #:socket #:socket-connect) (:reexport-from #:ext #:delete-directory #:rename-directory #:probe-directory #:probe-pathname #:read-byte-sequence)) ;;; CMUCL (define-implementation-package :cmu #:ql-cmucl (:documentation "CMU Common Lisp - http://www.cons.org/cmucl/") (:class cmucl) (:reexport-from #:system #:make-fd-stream) (:reexport-from #:unix #:unix-rmdir) (:reexport-from #:extensions #:connect-to-inet-socket #:*gc-verbose*)) (defvar ql-cmucl:*gc-verbose*) ;;; Scieneer CL (define-implementation-package :scl #:ql-scl (:documentation "Scieneer Common Lisp - http://www.scieneer.com/scl/") (:class scl) (:reexport-from #:system #:make-fd-stream) (:reexport-from #:unix #:unix-rmdir) (:reexport-from #:extensions #:connect-to-inet-socket #:unix-namestring)) ;;; LispWorks (define-implementation-package :lispworks #:ql-lispworks (:documentation "LispWorks - http://www.lispworks.com/") (:class lispworks) (:prep (require "comm")) (:reexport-from #:lw #:file-directory-p #:delete-directory) (:reexport-from #:comm #:open-tcp-stream #:get-host-entry)) ;;; ECL (define-implementation-package :ecl #:ql-ecl (:documentation "ECL - http://ecls.sourceforge.net/") (:class ecl) (:prep (require 'sockets)) (:intern #:host-network-address) (:reexport-from #:si #:rmdir #:file-kind) (:reexport-from #:sb-bsd-sockets #:get-host-by-name #:host-ent-address #:inet-socket #:socket-connect #:socket-make-stream)) ;;; MKCL (define-implementation-package :mkcl #:ql-mkcl (:documentation "ManKai Common Lisp - http://common-lisp.net/project/mkcl/") (:class mkcl) (:prep (require 'sockets)) (:intern #:host-network-address) (:reexport-from #:si #:rmdir #:file-kind) (:reexport-from #:sb-bsd-sockets #:get-host-by-name #:host-ent-address #:inet-socket #:socket-connect #:socket-make-stream)) ;;; SBCL (define-implementation-package :sbcl #:ql-sbcl (:class sbcl) (:documentation "Steel Bank Common Lisp - http://www.sbcl.org/") (:prep (require 'sb-posix) (require 'sb-bsd-sockets)) (:intern #:host-network-address) (:reexport-from #:sb-posix #:rmdir) (:reexport-from #:sb-ext #:compiler-note #:native-namestring) (:reexport-from #:sb-bsd-sockets #:get-host-by-name #:inet-socket #:host-ent-address #:socket-connect #:socket-make-stream))