X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~mdw/git/clg/blobdiff_plain/2c708568813055419a75f313819c8b3e94f32932..84d58948bc9cf543ac43e17da28d1a832baeff1a:/gffi/interface.lisp diff --git a/gffi/interface.lisp b/gffi/interface.lisp index bcb0cae..6b918d2 100644 --- a/gffi/interface.lisp +++ b/gffi/interface.lisp @@ -20,7 +20,7 @@ ;; TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE ;; SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -;; $Id: interface.lisp,v 1.6 2007-09-07 07:28:42 espen Exp $ +;; $Id: interface.lisp,v 1.10 2008-12-10 02:40:18 espen Exp $ (in-package "GFFI") @@ -72,15 +72,19 @@ (defun default-alien-type-name (type-name) #'string-capitalize (cons prefix (split-string (symbol-name type-name) :delimiter #\-)))))) -(defun default-type-name (alien-name) - (let ((parts - (mapcar - #'string-upcase - (split-string-if alien-name #'upper-case-p)))) - (intern - (concatenate-strings (rest parts) #\-) - (find-prefix-package (first parts))))) +(defun split-alien-name (alien-name) + (let ((parts (split-string-if alien-name #'upper-case-p))) + (do ((prefix (first parts) (concatenate 'string prefix (first rest))) + (rest (rest parts) (cdr rest))) + ((null rest) + (error "Couldn't split alien name '~A' to find a registered prefix" + alien-name)) + (when (find-prefix-package prefix) + (return (values (string-upcase (concatenate-strings rest #\-)) + (find-prefix-package prefix))))))) +(defun default-type-name (alien-name) + (multiple-value-call #'intern (split-alien-name alien-name))) (defun in-arg-p (style) (find style '(:in :in/out :in/return :in-out :return))) @@ -92,6 +96,29 @@ (defun return-arg-p (style) (find style '(:in/return :return))) (defmacro defbinding (name lambda-list return-type &rest args) + "This defines a foreign function call. NAME should either be a symbol or a +list (LISP-SYM STRING). The lisp function will be given the name of the lisp +symbol and the foreign function name is either the string given or automatically +generated using DEFAULT-ALIEN-FNAME. + +If LAMBDA-LIST is nil, the lambda list for the generated lisp function is +automatically computed from the input arguments as described below. If it is +non-nil, it gives the lambda list for the function. To manually specify an empty +lambda list, pass (NIL) which gets recognised as a special value. + +RETURN-TYPE should be a valid type. + +A normal element of ARGS is a list matching + + (EXPR TYPE &OPTIONAL (STYLE :IN) (OUT-TYPE TYPE)) + +however a shorthand form for an input parameter with name the same as its type +is that you can just give the atom TYPE as an argument. The lambda-list for the +function is the list of all input arguments, although if an EXPR is repeated, it +will only appear once. To add a constant argument, define one with STYLE :IN and +EXPR the value it should take. + +To give the binding a docstring, pass a string as the first element of ARGS." (multiple-value-bind (lisp-name c-name) (if (atom name) (values name (default-alien-fname name)) @@ -128,8 +155,15 @@ (defmacro defbinding (name lambda-list return-type &rest args) (list (cond ((and (namep expr) (not (in-arg-p style))) expr) - ((namep expr) (make-symbol (string expr))) - ((gensym))) + ((namep expr) + #-clisp(make-symbol (string expr)) + ;; The above used to work in CLISP, but I'm + ;; not sure exactly at which version it + ;; broke. The following could potentially + ;; cause variable capturing + #+clisp(intern (format nil "~A-~A" (string expr) (gensym)))) + (#-clisp(gensym) + #+clisp(intern (string (gensym))))) (or aux expr) type style out-type)))) args))) @@ -209,7 +243,8 @@ (defun %defbinding (cname lisp-name lambda-list declare-p arg-types aux-bindings when (out-arg-p style) collect (return-type out-type) when (return-arg-p style) - collect (return-type type))))))) + collect (return-type type)))) + ,lisp-name))) (defun ,lisp-name ,lambda-list ,doc (let ,aux-bindings @@ -306,7 +341,10 @@ (defmacro define-callback (name return-type args &body body) (let ((define-callback #+cmu'alien:def-callback #+(and sbcl alien-callbacks)'sb-alien::define-alien-callback - #+(and sbcl (not alien-callbacks))'sb-alien:define-alien-function)) + #+(and sbcl (not alien-callbacks))'sb-alien:define-alien-function) + (args (mapcar #'(lambda (arg) + (if (atom arg) (list arg arg) arg)) + args))) `(progn #+cmu(defparameter ,name nil) (,define-callback ,name @@ -383,8 +421,11 @@ (defun restore-callback-pointers () ;;; translated according to RETTYPE. Obtain a pointer that can be ;;; passed to C code for this callback by calling %CALLBACK. (defmacro define-callback (name return-type args &body body) - (let ((arg-names (mapcar #'first args)) - (arg-types (mapcar #'second args))) + (let* ((args (mapcar #'(lambda (arg) + (if (atom arg) (list arg arg) arg)) + args)) + (arg-names (mapcar #'first args)) + (arg-types (mapcar #'second args))) `(progn (defvar ,name ',name) (register-callback ',name @@ -406,6 +447,12 @@ (deftype callback () 'symbol)) ;;;; Type expansion +;; A hack to make the TYPE-EXPAND code for SBCL work. +#?+(pkg-config:sbcl>= 1 0 35 15) +(sb-ext:without-package-locks + (setf (symbol-function 'sb-kernel::type-expand) + (lambda (form) (typexpand form)))) + (defun type-expand-1 (form) #+(or cmu sbcl) (let ((def (cond ((symbolp form) @@ -431,6 +478,8 @@ (defun type-expand-to (type form) (error "~A can not be expanded to ~A" form type)))))) (expand form))) +(defun type-equal-p (type1 type2) + (and (subtypep type1 type2) (subtypep type2 type1))) ;;;; Type methods