302 lines
9.5 KiB
Common Lisp
302 lines
9.5 KiB
Common Lisp
|
|
(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))
|