I wrote:
> Meanwhile, I've implemented this with some changes.

So, here's what I've got:

diff -rN -u cffi-old/src/foreign-vars.lisp cffi-new/src/foreign-vars.lisp
--- cffi-old/src/foreign-vars.lisp	2006-01-07 01:54:06.000000000 +0000
+++ cffi-new/src/foreign-vars.lisp	2006-02-12 06:26:46.000000000 +0000
@@ -62,26 +62,20 @@
 returning nil when foreign-name is not found."
   (or (foreign-symbol-pointer foreign-name :data)
       (error "Trying access undefined foreign variable ~S." foreign-name)))
-  
+
 (defmacro defcvar (name type &key read-only)
   "Define a foreign global variable."
   (let* ((lisp-name (lisp-var-name name))
          (foreign-name (foreign-var-name name))
-         (fn (symbolicate '#:%var-accessor- lisp-name))
-         (ptype (parse-type type)))
-    (when (aggregatep ptype) ; we can't really setf an aggregate type
-      (setq read-only t))    ; at least not yet...
+         (fn (symbolicate '#:%var-accessor- lisp-name)))
+    (when (aggregatep (parse-type type)) ; we can't really setf an aggregate
+      (setq read-only t))                ; type, at least not yet...
     `(progn
        ;; Save foreign-name for posterior access by get-var-ptr
        (setf (get ',lisp-name 'foreign-var-name) ,foreign-name)
        ;; Getter
        (defun ,fn ()
-         ,(if (aggregatep ptype)
-              ;; no dereference for aggregate types.
-              `(foreign-symbol-pointer-or-lose ,foreign-name)
-              `(translate-type-from-foreign
-                (mem-ref (foreign-symbol-pointer-or-lose ,foreign-name) ',type)
-                ,ptype)))
+         (mem-ref (foreign-symbol-pointer-or-lose ,foreign-name) ',type)) 
        ;; Setter
        (defun (setf ,fn) (value)
          ,(if read-only '(declare (ignore value)) (values))
@@ -89,7 +83,7 @@
               `(error ,(format nil "Trying to modify read-only foreign var: ~A."
                                lisp-name))
               `(setf (mem-ref (foreign-symbol-pointer-or-lose ,foreign-name)
-                      ',type)
-                (translate-type-to-foreign value ,ptype))))
+                              ',type)
+                     value)))
        ;; Symbol macro
        (define-symbol-macro ,lisp-name (,fn)))))
diff -rN -u cffi-old/src/functions.lisp cffi-new/src/functions.lisp
--- cffi-old/src/functions.lisp	2006-02-10 18:18:03.000000000 +0000
+++ cffi-new/src/functions.lisp	2006-02-12 05:32:52.000000000 +0000
@@ -39,21 +39,15 @@
 ;;; (passed to TRANSLATE-OBJECTS as the CALL argument) instead
 ;;; of CFFI-SYS:%FOREIGN-FUNCALL to call the foreign-function.
 
-(defmacro translate-objects (syms args types rettype call)
-  "Helper macro for FOREIGN-FUNCALL and DEFCFUN."
-  (cond
-    ;; All arguments have been translated, translate
-    ;; the return value and perform the call.
-    ((null args)
-     (let ((parsed-type (parse-type rettype)))
-       (if (translate-p parsed-type)
-           `(translate-type-from-foreign ,call ,parsed-type)
-           `(values ,call))))
-    ;; More than one argument is available---translate the first
-    ;; argument/type pair and recurse.
-    (t `(with-object-translated (,(car syms) ,(car args) ,(car types))
-          (translate-objects
-           ,(rest syms) ,(rest args) ,(rest types) ,rettype ,call)))))
+(defun translate-objects (syms args types rettype call-form)
+  "Helper function for FOREIGN-FUNCALL and DEFCFUN."
+  (if (null args)
+      (expand-type-from-foreign call-form (parse-type rettype))
+      (expand-type-to-foreign-dyn
+       (car args) (car syms)
+       (list (translate-objects (cdr syms) (cdr args)
+                                (cdr types) rettype call-form))
+       (parse-type (car types)))))
 
 (defun parse-args-and-types (args)
   "Returns 4 values. Types, canonicalized types, args and return type."
@@ -70,13 +64,13 @@
   (multiple-value-bind (types ctypes fargs rettype)
       (parse-args-and-types args)
     (let ((syms (make-gensym-list (length fargs))))
-      `(translate-objects
-        ,syms ,fargs ,types ,rettype
-        (,(if (stringp name-or-pointer)
+      (translate-objects
+       syms fargs types rettype
+       `(,(if (stringp name-or-pointer)
               '%foreign-funcall
               '%foreign-funcall-pointer)
-         ,name-or-pointer ,@(mapcan #'list ctypes syms)
-         ,(canonicalize-foreign-type rettype))))))
+          ,name-or-pointer ,@(mapcan #'list ctypes syms)
+          ,(canonicalize-foreign-type rettype))))))
 
 (defun promote-varargs-type (builtin-type)
   "Default argument promotions."
@@ -100,10 +94,10 @@
         (parse-args-and-types varargs)
       (let ((syms (make-gensym-list (+ (length fixed-fargs)
                                        (length varargs-fargs)))))
-        `(translate-objects
-          ,syms ,(append fixed-fargs varargs-fargs)
-          ,(append fixed-types varargs-types) ,rettype
-          (,(if (stringp name-or-pointer)
+        (translate-objects
+         syms (append fixed-fargs varargs-fargs)
+         (append fixed-types varargs-types) rettype
+         `(,(if (stringp name-or-pointer)
                 '%foreign-funcall
                 '%foreign-funcall-pointer)
             ,name-or-pointer
@@ -148,13 +142,13 @@
         (syms (make-gensym-list (length args))))
     (multiple-value-bind (prelude caller)
         (defcfun-helper-forms
-            foreign-name lisp-name (canonicalize-foreign-type return-type)
-            syms (mapcar #'canonicalize-foreign-type arg-types))
+          foreign-name lisp-name (canonicalize-foreign-type return-type)
+          syms (mapcar #'canonicalize-foreign-type arg-types))
       `(progn
          ,prelude
          (defun ,lisp-name ,arg-names
-           (translate-objects
-            ,syms ,arg-names ,arg-types ,return-type ,caller))))))
+           ,(translate-objects
+             syms arg-names arg-types return-type caller))))))
 
 (defun %defcfun-varargs (lisp-name foreign-name return-type args)
   (with-unique-names (varargs)
@@ -181,22 +175,25 @@
 
 ;;;# Defining Callbacks
 
-(defmacro inverse-translate-objects (args types rettype call)
-  "Helper macro for DEFCALLBACK."
-  (cond
-    ((null args)
-     (let ((parsed-type (parse-type rettype)))
-       (if (translate-p parsed-type)
-           `(translate-type-to-foreign ,call ,parsed-type)
-           call)))
-    (t
-     (let ((type (parse-type (car types))))
-       (if (translate-p type)
-           `(let ((,(car args) (translate-type-from-foreign ,(car args) ,type)))
-              (inverse-translate-objects ,(rest args) ,(rest types)
-                                         ,rettype ,call))
-           `(inverse-translate-objects ,(rest args) ,(rest types)
-                                       ,rettype ,call))))))
+(defun inverse-translate-objects (args ignored-args types rettype call)
+  "Helper function for DEFCALLBACK."
+  (labels ((rec (args types)
+             (cond ((null args)
+                    (expand-type-to-foreign call (parse-type rettype)))
+                   ;; Don't apply translations for arguments that were
+                   ;; declared ignored in order to avoid warnings.
+                   ((not (member (car args) ignored-args))
+                    `(let ((,(car args) ,(expand-type-from-foreign
+                                          (car args) (parse-type (car types)))))
+                       ,(rec (cdr args) (cdr types))))
+                   (t (rec (cdr args) (cdr types)))))) 
+    (rec args types)))
+
+(defun collect-ignored-args (declarations)
+  (loop for declaration in declarations
+        append (loop for decl in (cdr declaration)
+                     when (eq (car decl) 'cl:ignore)
+                     append (cdr decl))))
 
 (defmacro defcallback (name return-type args &body body)
   (multiple-value-bind (body docstring declarations)
@@ -208,8 +205,9 @@
          (%defcallback ,name ,(canonicalize-foreign-type return-type)
              ,arg-names ,(mapcar #'canonicalize-foreign-type arg-types)
            ,@declarations
-           (inverse-translate-objects ,arg-names ,arg-types ,return-type
-                                      (block ,name ,@body)))
+           ,(inverse-translate-objects
+             arg-names (collect-ignored-args declarations) arg-types
+             return-type `(block ,name ,@body)))
          ',name))))
 
 (defun get-callback (symbol)
diff -rN -u cffi-old/src/types.lisp cffi-new/src/types.lisp
--- cffi-old/src/types.lisp	2006-02-08 19:22:35.000000000 +0000
+++ cffi-new/src/types.lisp	2006-02-12 06:30:07.000000000 +0000
@@ -96,7 +96,6 @@
   (:method (value name param)
     (declare (ignore value name param))))
 
-
 ;;; Default translator to foreign for typedefs.  We build a list out
 ;;; of the second value returned from each translator so we can pass
 ;;; each parameter to the appropriate free method when freeing the
@@ -123,17 +122,15 @@
 
 ;;;## Macroexpansion Time Translation
 ;;;
-;;; In this new implementation of type translation, this macro should
-;;; only be used when VAR should be translated and bound to VALUE, and
-;;; has dynamic extent during BODY.  There is no need to use this
-;;; macro when converting values from C objects---just call
-;;; TRANSLATE-TYPE-FROM-FOREIGN directly.
+;;; The following expand-* generic functions are similar to their
+;;; translate-* counterparts but are usually called at macroexpansion
+;;; time. They offer a way to optimize the runtime translators.
 ;;;
-;;; If TYPE-SPEC refers to a built-in type, it will not be translated.
+;;; The default methods expand to forms calling the runtime translators
+;;; unless TRANSLATE-P returns NIL for the type.
 
-(defmacro with-object-translated ((var value type-spec) &body body)
-  (let ((type (parse-type type-spec))
-        (param (gensym "PARAM-")))
+(defun %expand-type-to-foreign-dyn (value var body type)
+  (with-unique-names (param)
     (if (translate-p type)
         `(multiple-value-bind (,var ,param)
              (translate-type-to-foreign ,value ,type)
@@ -141,29 +138,113 @@
                 (progn ,@body)
              (free-type-translated-object ,var ,type ,param)))
         `(let ((,var ,value))
-          ,@body))))
+           ,@body))))
+
+(defun %expand-type-to-foreign (value type)
+  (if (translate-p type)
+      `(translate-type-to-foreign ,value ,type)
+      value))
+
+(defun %expand-type-from-foreign (value type)
+  (if (translate-p type)
+      `(translate-type-from-foreign ,value ,type)
+      `(values ,value)))
+
+;;; This special variable is bound by the various :around methods below
+;;; to the respective form generated by the above %EXPAND-* functions.
+;;; This way, an expander can "bail out" by returning it.
+(defvar *runtime-translator-form*)
+
+(defgeneric expand-type-to-foreign-dyn (value var body type)
+  (:method :around (value var body type)
+    (let ((*runtime-translator-form*
+           (%expand-type-to-foreign-dyn value var body type)))
+      (call-next-method)))  
+  (:method (value var body type)
+    ;; If COMPUTE-APPLICABLE-METHODS only finds one method it's
+    ;; the default one meaning that there is no to-foreign expander
+    ;; therefore we return *RUNTIME-TRANSLATOR-FORM* instead.
+    (if (< 1 (length (compute-applicable-methods
+                      #'expand-type-to-foreign (list value type))))
+        `(let ((,var ,(expand-type-to-foreign value type)))
+           ,@body)
+        *runtime-translator-form*)))
+
+(defgeneric expand-type-to-foreign (value type)
+  (:method :around (value type)
+    (let ((*runtime-translator-form* (%expand-type-to-foreign value type)))
+      (call-next-method)))
+  (:method (value type)
+    (declare (ignore value type))
+    *runtime-translator-form*))
+
+(defgeneric expand-type-from-foreign (value type)
+  (:method :around (value type)
+    (let ((*runtime-translator-form* (%expand-type-from-foreign value type)))
+      (call-next-method)))
+  (:method (value type)
+    (declare (ignore value type))
+    *runtime-translator-form*))
+
+(defgeneric expand-to-foreign-dyn (value var body type))
+(defgeneric expand-to-foreign (value type))
+(defgeneric expand-from-foreign (value type))
+
+(defun applicablep (gf &rest args)
+  "Returns true if GF has any applicable methods for ARGS."
+  (not (null (compute-applicable-methods gf args))))
+
+(defmethod expand-type-to-foreign-dyn (value var body (type foreign-typedef))
+  (cond ((applicablep #'expand-to-foreign-dyn value var body (name type))
+         (expand-to-foreign-dyn value var body (name type)))
+        ;; If there is to-foreign _expansion_ we use that.
+        ((applicablep #'expand-to-foreign value (name type))
+         `(let ((,var ,(expand-to-foreign value (name type))))
+            ,@body))
+        ;; Else...
+        (t *runtime-translator-form*)))
+
+(defmethod expand-type-to-foreign (value (type foreign-typedef))
+  (if (applicablep #'expand-to-foreign value (name type))
+      (expand-to-foreign value (name type))
+      *runtime-translator-form*))
+
+(defmethod expand-type-from-foreign (value (type foreign-typedef))
+  (if (applicablep #'expand-from-foreign value (name type))
+      (expand-from-foreign value (name type))
+      *runtime-translator-form*))
 
 ;;;# Dereferencing Foreign Pointers
 
 (defun mem-ref (ptr type &optional (offset 0))
   "Return the value of TYPE at OFFSET bytes from PTR. If TYPE is aggregate,
 we don't return its 'value' but a pointer to it, which is PTR itself."
-  (let ((parsed-type (parse-type type)))
-    (if (aggregatep parsed-type)
+  (let ((ptype (parse-type type)))
+    (if (aggregatep ptype)
         (inc-pointer ptr offset)
-        (%mem-ref ptr (canonicalize parsed-type) offset))))
+        (let ((raw-value (%mem-ref ptr (canonicalize ptype) offset)))
+          (if (translate-p ptype)
+              (translate-type-from-foreign raw-value ptype)
+              raw-value)))))
 
 (define-compiler-macro mem-ref (&whole form ptr type &optional (offset 0))
   "Compiler macro to open-code MEM-REF when TYPE is constant."
   (if (constantp type)
-      (if (aggregatep (parse-type (eval type)))
-          `(inc-pointer ,ptr ,offset)
-          `(%mem-ref ,ptr ,(canonicalize-foreign-type (eval type)) ,offset))
+      (let ((parsed-type (parse-type (eval type))))
+        (if (aggregatep parsed-type)
+            `(inc-pointer ,ptr ,offset)
+            (expand-type-from-foreign
+             `(%mem-ref ,ptr ,(canonicalize parsed-type) ,offset)
+             parsed-type)))
       form))
 
 (defun mem-set (value ptr type &optional (offset 0))
   "Set the value of TYPE at OFFSET bytes from PTR to VALUE."
-  (%mem-set value ptr (canonicalize-foreign-type type) offset))
+  (let ((ptype (parse-type type)))
+    (%mem-set (if (translate-p ptype)
+                  (translate-type-to-foreign value ptype)
+                  value)
+              ptr (canonicalize ptype) offset)))
 
 (define-setf-expander mem-ref (ptr type &optional (offset 0) &environment env)
   "SETF expander for MEM-REF that doesn't rebind TYPE.
@@ -196,7 +277,9 @@
     (&whole form value ptr type &optional (offset 0))
   "Compiler macro to open-code (SETF MEM-REF) when type is constant."
   (if (constantp type)
-      `(%mem-set ,value ,ptr ,(canonicalize-foreign-type (eval type)) ,offset)
+      (let ((parsed-type (parse-type (eval type))))
+        `(%mem-set ,(expand-type-to-foreign value parsed-type) ,ptr
+                   ,(canonicalize parsed-type) ,offset))
       form))
 
 ;;;# Dereferencing Foreign Arrays
@@ -314,36 +397,19 @@
 
 (defmethod foreign-struct-slot-value (ptr (slot simple-struct-slot))
   "Return the value of a simple SLOT from a struct at PTR."
-  (let* ((type (slot-type slot))
-         (parsed-type (parse-type type)))
-    (translate-type-from-foreign
-     (mem-ref ptr type (slot-offset slot)) parsed-type)))
+  (mem-ref ptr (slot-type slot) (slot-offset slot)))
 
 (defmethod foreign-struct-slot-value-form (ptr (slot simple-struct-slot))
   "Return a form to get the value of a slot from PTR."
-  (let* ((type (slot-type slot))
-         (parsed-type (parse-type type)))
-    (if (translate-p parsed-type)
-        `(translate-type-from-foreign
-          (mem-ref ,ptr ',type ,(slot-offset slot))
-          ,parsed-type)
-        `(mem-ref ,ptr ',type ,(slot-offset slot)))))
+  `(mem-ref ,ptr ',(slot-type slot) ,(slot-offset slot)))
 
 (defmethod (setf foreign-struct-slot-value) (value ptr (slot simple-struct-slot))
   "Set the value of a simple SLOT to VALUE in PTR."
-  (let* ((type (slot-type slot))
-         (parsed-type (parse-type type)))
-    (setf (mem-ref ptr type (slot-offset slot))
-          (translate-type-to-foreign value parsed-type))))
+  (setf (mem-ref ptr (slot-type slot) (slot-offset slot)) value))
 
 (defmethod foreign-struct-slot-set-form (value ptr (slot simple-struct-slot))
   "Return a form to set the value of a simple structure slot."
-  (let* ((type (slot-type slot))
-         (parsed-type (parse-type type)))
-    (if (translate-p parsed-type)
-        `(setf (mem-ref ,ptr ',type ,(slot-offset slot))
-               (translate-type-to-foreign ,value ,parsed-type))
-        `(setf (mem-ref ,ptr ',type ,(slot-offset slot)) ,value))))
+  `(setf (mem-ref ,ptr ',(slot-type slot) ,(slot-offset slot)) ,value))
 
 ;;;### Aggregate Slots
 
@@ -727,6 +793,18 @@
 (defmethod translate-from-foreign (value (name (eql :boolean)))
   (not (zerop value)))
 
+(defmethod expand-to-foreign (value (name (eql :boolean)))
+  "Optimization for the :boolean type."
+  (if (constantp value)
+      (if (eval value) 1 0)
+      `(if ,value 1 0)))
+
+(defmethod expand-from-foreign (value (name (eql :boolean)))
+  "Optimization for the :boolean type."
+  (if (constantp value) ; very unlikely, heh
+      (not (zerop (eval value)))
+      `(not (zerop ,value))))
+
 ;;;# Built-In Types
 
 (define-built-in-foreign-type :char)
-- 
Luís Oliveira
luismbo (@) gmail (.) com
Equipa Portuguesa do Translation Project
http://www.iro.umontreal.ca/translation/registry.cgi?team=pt
_______________________________________________
cffi-devel mailing list
cffi-devel@common-lisp.net
http://common-lisp.net/cgi-bin/mailman/listinfo/cffi-devel

Reply via email to