chiark / gitweb /
Added :in-out style to define-foreign
[clg] / glib / gforeign.lisp
1 ;; Common Lisp bindings for GTK+ v2.0
2 ;; Copyright (C) 1999-2000 Espen S. Johnsen <espejohn@online.no>
3 ;;
4 ;; This library is free software; you can redistribute it and/or
5 ;; modify it under the terms of the GNU Lesser General Public
6 ;; License as published by the Free Software Foundation; either
7 ;; version 2 of the License, or (at your option) any later version.
8 ;;
9 ;; This library is distributed in the hope that it will be useful,
10 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
11 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12 ;; Lesser General Public License for more details.
13 ;;
14 ;; You should have received a copy of the GNU Lesser General Public
15 ;; License along with this library; if not, write to the Free Software
16 ;; Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
17
18 ;; $Id: gforeign.lisp,v 1.2 2000-08-16 18:25:30 espen Exp $
19
20 (in-package "GLIB")
21
22 ;;;; Type methods
23
24 (defvar *type-methods* (make-hash-table))
25
26 (defun ensure-type-method-fun (fname)
27   (unless (fboundp fname)
28     (setf
29      (symbol-function fname)
30      #'(lambda (type-spec &rest args)
31          (apply
32           (find-applicable-type-method type-spec fname) type-spec args)))))
33
34 (defmacro define-type-method-fun (fname lambda-list)
35   (declare (ignore lambda-list))
36   `(defun ,fname (type-spec &rest args)
37      (apply
38       (find-applicable-type-method type-spec ',fname) type-spec args)))
39
40
41 (defun ensure-type-name (type)
42   (etypecase type
43     (symbol type)
44     (pcl::class (class-name type))))
45
46 (defun add-type-method (type fname function)
47   (push
48    (cons fname function)
49    (gethash (ensure-type-name type) *type-methods*)))
50
51 (defun find-type-method (type fname)
52   (cdr (assoc fname (gethash (ensure-type-name type) *type-methods*))))
53
54 (defun find-applicable-type-method (type-spec fname &optional (error t))
55   (flet ((find-superclass-method (class)
56            (when class
57              (dolist (super (cdr (pcl::class-precedence-list class)))
58                (return-if (find-type-method super fname)))))
59          (find-expanded-type-method (type-spec)
60            (multiple-value-bind (expanded-type-spec expanded-p)
61                (type-expand-1 type-spec)
62              (cond
63               (expanded-p 
64                (find-applicable-type-method expanded-type-spec fname nil))
65               ((neq type-spec t)
66                (find-applicable-type-method t fname nil))))))
67
68     (or
69      (typecase type-spec
70        (pcl::class
71         (or
72          (find-type-method type-spec fname)
73          (find-superclass-method type-spec)))
74        (symbol
75         (or
76          (find-type-method type-spec fname)
77          (find-expanded-type-method type-spec)
78          (find-superclass-method (find-class type-spec nil))))
79        (cons
80         (or
81          (find-type-method (first type-spec) fname)
82          (find-expanded-type-method type-spec)))
83        (t
84         (error "Invalid type specifier ~A" type-spec)))
85      (and
86       error
87       (error
88        "No applicable method for ~A when called with type specifier ~A"
89        fname type-spec)))))
90
91 (defmacro deftype-method (fname type lambda-list &body body)
92   `(progn
93      (ensure-type-method-fun ',fname)
94      (add-type-method ',type ',fname #'(lambda ,lambda-list ,@body))
95      ',fname))
96   
97 (defmacro deftype (name parameters &body body)
98   (destructuring-bind (lisp-name &optional alien-name) (mklist name)
99     `(progn
100        ,(when alien-name
101           `(setf (alien-type-name ',lisp-name) ,alien-name))
102        (lisp:deftype ,lisp-name ,parameters ,@body))))
103
104 ;; To make the compiler shut up
105 (eval-when (:compile-toplevel :load-toplevel :execute)
106   (define-type-method-fun translate-type-spec (type-spec))
107   (define-type-method-fun translate-to-alien (type-spec expr &optional copy))
108   (define-type-method-fun translate-from-alien (type-spec expr &optional alloc))
109   (define-type-method-fun cleanup-alien (type-spec expr &optional copied)))
110   
111
112 ;;;; 
113
114 (defvar *type-function-cache* (make-hash-table :test #'equal))
115
116 (defun get-cached-function (type-spec fname)
117   (cdr (assoc fname (gethash type-spec *type-function-cache*))))
118
119 (defun set-cached-function (type-spec fname function)
120   (push (cons fname function) (gethash type-spec *type-function-cache*))
121   function)
122   
123
124 ;; Creates a function to translate an object of the specified type
125 ;; from lisp to alien representation.
126 (defun get-to-alien-function (type-spec)
127   (or
128    (get-cached-function type-spec 'to-alien-function)
129    (set-cached-function type-spec 'to-alien-function
130     (compile
131      nil
132      `(lambda (object)
133         (declare (ignorable object))
134         ,(translate-to-alien type-spec 'object))))))
135
136 ;; and the opposite
137 (defun get-from-alien-function (type-spec)
138   (or
139    (get-cached-function type-spec 'from-alien-function)
140    (set-cached-function type-spec 'from-alien-function
141     (compile
142      nil
143      `(lambda (alien)
144         (declare (ignorable alien))
145         ,(translate-from-alien type-spec 'alien))))))
146
147 ;; and for cleaning up
148 (defun get-cleanup-function (type-spec)
149   (or
150    (get-cached-function type-spec 'cleanup-function)
151    (set-cached-function type-spec 'cleanup-function
152     (compile
153      nil
154      `(lambda (alien)
155         (declare (ignorable alien))
156         ,(cleanup-alien type-spec 'alien))))))
157
158
159
160 ;; Creates a function to write an object of the specified type
161 ;; to the given memory location
162 (defun get-writer-function (type-spec)
163   (or
164    (get-cached-function type-spec 'writer-function)
165    (set-cached-function type-spec 'writer-function
166     (compile
167      nil
168      `(lambda (value sap offset)
169         (declare (ignorable value sap offset))
170         (setf
171          (,(sap-ref-fname type-spec) sap offset)
172          ,(translate-to-alien type-spec 'value :copy)))))))
173
174 ;; Creates a function to read an object of the specified type
175 ;; from the given memory location
176 (defun get-reader-function (type-spec)
177   (or
178    (get-cached-function type-spec 'reader-function)
179    (set-cached-function type-spec 'reader-function
180     (compile
181      nil
182      `(lambda (sap offset)       
183         (declare (ignorable sap offset))
184         ,(translate-from-alien
185           type-spec `(,(sap-ref-fname type-spec) sap offset) :copy))))))
186
187
188 (defun get-destroy-function (type-spec)
189   (or
190    (get-cached-function type-spec 'destroy-function)
191    (set-cached-function type-spec 'destroy-function
192     (compile
193      nil
194      `(lambda (sap offset)       
195         (declare (ignorable sap offset))
196         ,(cleanup-alien
197           type-spec `(,(sap-ref-fname type-spec) sap offset) :copied))))))
198
199
200
201 ;;;;
202
203 (defconstant +size-of-int+ 4)
204 (defconstant +size-of-sap+ 4)
205 (defconstant +size-of-float+ 4)
206 (defconstant +size-of-double+ 8)
207
208 (defun sap-ref-unsigned (sap offset)
209   (sap-ref-32 sap offset))
210
211 (defun sap-ref-signed (sap offset)
212   (signed-sap-ref-32 sap offset))
213
214 (defun sap-ref-fname (type-spec)
215   (let ((alien-type-spec (mklist (translate-type-spec type-spec))))
216     (ecase (first alien-type-spec)
217       (unsigned
218        (ecase (second alien-type-spec)
219          (8 'sap-ref-8)
220          (16 'sap-ref-16)
221          (32 'sap-ref-32)
222          (64 'sap-ref-64)))
223       (signed
224        (ecase (second alien-type-spec)
225          (8 'signed-sap-ref-8)
226          (16 'signed-sap-ref-16)
227          (32 'signed-sap-ref-32)
228          (64 'signed-sap-ref-64)))
229       (system-area-pointer 'sap-ref-sap)
230       (single-float 'sap-ref-single)
231       (double-float 'sap-ref-double))))
232
233
234 (defun signed (size)
235   (if (eq size '*)
236       `(signed ,(* 8 +size-of-int+))
237     `(signed ,size)))
238
239 (defun unsigned (size)
240   (if (eq size '*)
241       `(unsigned ,(* 8 +size-of-int+))
242     `(unsigned ,size)))
243
244 (defun size-of (type-spec)
245   (let ((alien-type-spec (translate-type-spec type-spec)))
246     (ecase (first (mklist alien-type-spec))
247      ((signed unsigned) (/ (second alien-type-spec) 8))
248      ((system-area-pointer single-float) +size-of-sap+)
249      (single-float +size-of-float+)
250      (double-float +size-of-double+))))
251
252
253 ;;;; Foreign function call interface
254
255 (defvar *package-prefix* nil)
256
257 (defun set-package-prefix (prefix &optional (package *package*))
258   (let ((package (find-package package)))
259     (delete-if #'(lambda (assoc) (eq (car assoc) package)) *package-prefix*)
260     (push (cons package prefix) *package-prefix*))
261   prefix)
262
263 (defun package-prefix (&optional (package *package*))
264   (let ((package (find-package package)))
265     (or
266      (cdr (assoc package *package-prefix*))
267      (substitute #\_ #\- (string-downcase (package-name package))))))
268
269 (defmacro use-prefix (prefix &optional (package *package*))
270   `(eval-when (:compile-toplevel :load-toplevel :execute)
271      (set-package-prefix ,prefix ,package)))
272
273
274 (defun default-alien-func-name (lisp-name)
275   (let* ((lisp-name-string
276           (if (char= (char (the simple-string (string lisp-name)) 0) #\%)
277               (subseq (the simple-string (string lisp-name)) 1)
278             (string lisp-name)))
279          (prefix (package-prefix *package*))
280          (name (substitute #\_ #\- (string-downcase lisp-name-string))))
281     (if (or (not prefix) (string= prefix ""))
282         name
283       (format nil "~A_~A" prefix name))))
284
285
286 (defmacro define-foreign (name lambda-list return-type-spec &rest docs/args)
287   (multiple-value-bind (c-name lisp-name)
288       (if (atom name)
289           (values (default-alien-func-name name) name)
290         (values-list name))
291     (let ((supplied-lambda-list lambda-list)
292           (docs nil)
293           (args nil))
294       (dolist (doc/arg docs/args)
295         (if (stringp doc/arg)
296             (push doc/arg docs)
297           (progn
298             (destructuring-bind (expr type &optional (style :in)) doc/arg
299               (unless (member style '(:in :out :in-out))
300                 (error "Bogus argument style ~S in ~S." style doc/arg))
301               (when (and
302                      (not supplied-lambda-list)
303                      (namep expr) (member style '(:in :in-out)))
304                 (push expr lambda-list))
305               (push
306                (list (if (namep expr) expr (gensym)) expr type style) args)))))
307       
308       (%define-foreign
309        c-name lisp-name (or supplied-lambda-list (nreverse lambda-list))
310        return-type-spec (reverse docs) (reverse args)))))
311
312
313 #+cmu
314 (defun %define-foreign (foreign-name lisp-name lambda-list
315                         return-type-spec docs args)
316   (ext:collect ((alien-types) (alien-bindings) (alien-parameters)
317                 (alien-values) (alien-deallocatiors))
318     (dolist (arg args)
319       (destructuring-bind (var expr type-spec style) arg
320         (let ((declaration (translate-type-spec type-spec))
321               (deallocation (cleanup-alien type-spec expr)))
322           (cond
323            ((member style '(:out :in-out))
324             (alien-types `(* ,declaration))
325             (alien-parameters `(addr ,var))
326             (alien-bindings
327              `(,var ,declaration
328                ,@(when (eq style :in-out)
329                    (list (translate-to-alien type-spec expr)))))
330             (alien-values (translate-from-alien type-spec var)))
331           (deallocation
332            (alien-types declaration)
333            (alien-bindings
334             `(,var ,declaration ,(translate-to-alien type-spec expr)))
335            (alien-parameters var)
336            (alien-deallocatiors deallocation))
337           (t
338            (alien-types declaration)
339            (alien-parameters (translate-to-alien type-spec expr)))))))
340
341     (let ((alien-funcall `(alien-funcall ,lisp-name ,@(alien-parameters))))
342       `(defun ,lisp-name ,lambda-list
343          ,@docs
344          (with-alien ((,lisp-name
345                        (function
346                         ,(translate-type-spec return-type-spec)
347                         ,@(alien-types))
348                        :extern ,foreign-name)
349                       ,@(alien-bindings))
350            ,(if return-type-spec
351                 `(let ((result
352                         ,(translate-from-alien return-type-spec alien-funcall)))
353                    ,@(alien-deallocatiors)
354                    (values result ,@(alien-values)))
355               `(progn
356                  ,alien-funcall
357                  ,@(alien-deallocatiors)
358                  (values ,@(alien-values)))))))))
359
360   
361
362
363 ;;;; Translations for fundamental types
364
365 (lisp:deftype long (&optional (min '*) (max '*)) `(integer ,min ,max))
366 (lisp:deftype unsigned-long (&optional (min '*) (max '*)) `(integer ,min ,max))
367 (lisp:deftype int (&optional (min '*) (max '*)) `(long ,min ,max))
368 (lisp:deftype unsigned-int (&optional (min '*) (max '*)) `(unsigned-long ,min ,max))
369 (lisp:deftype short (&optional (min '*) (max '*)) `(int ,min ,max))
370 (lisp:deftype unsigned-short (&optional (min '*) (max '*)) `(unsigned-int ,min ,max))
371 (lisp:deftype signed (&optional (size '*)) `(signed-byte ,size))
372 (lisp:deftype unsigned (&optional (size '*)) `(signed-byte ,size))
373 (lisp:deftype char () 'base-char)
374 (lisp:deftype pointer () 'system-area-pointer)
375 (lisp:deftype boolean (&optional (size '*))
376   (declare (ignore size))
377   `(member t nil))
378 (lisp:deftype static (type) type)
379 (lisp:deftype invalid () nil)
380
381
382 (deftype-method cleanup-alien t (type-spec alien &optional copied)
383   (declare (ignore type-spec alien copied))
384   nil)
385
386
387 (deftype-method translate-to-alien integer (type-spec number &optional copy)
388   (declare (ignore type-spec copy))
389   number)
390
391 (deftype-method translate-from-alien integer (type-spec number &optional alloc)
392   (declare (ignore type-spec alloc))
393   number)
394
395
396 (deftype-method translate-type-spec fixnum (type-spec)
397   (declare (ignore type-spec))
398   (signed '*))
399
400 (deftype-method translate-to-alien fixnum (type-spec number &optional copy)
401   (declare (ignore type-spec copy))
402   number)
403
404 (deftype-method translate-from-alien fixnum (type-spec number &optional alloc)
405   (declare (ignore type-spec alloc))
406   number)
407
408
409 (deftype-method translate-type-spec long (type-spec)
410   (declare (ignore type-spec))
411   (signed '*))
412
413
414 (deftype-method translate-type-spec unsigned-long (type-spec)
415   (declare (ignore type-spec))
416   (unsigned '*))
417
418
419 (deftype-method translate-type-spec short (type-spec)
420   (declare (ignore type-spec))
421   '(signed 16))
422
423
424 (deftype-method translate-type-spec unsigned-short (type-spec)
425   (declare (ignore type-spec))
426   '(unsigned 16))
427
428
429 (deftype-method translate-type-spec signed-byte (type-spec)
430   (destructuring-bind (name &optional (size '*))
431       (type-expand-to 'signed-byte type-spec)
432     (declare (ignore name))
433     (signed size)))
434
435 (deftype-method translate-to-alien signed-byte (type-spec number &optional copy)
436   (declare (ignore type-spec copy))
437   number)
438
439 (deftype-method
440     translate-from-alien signed-byte (type-spec number &optional alloc)
441   (declare (ignore type-spec alloc))
442   number)
443
444
445 (deftype-method translate-type-spec unsigned-byte (type-spec)
446   (destructuring-bind (name &optional (size '*))
447       (type-expand-to 'unsigned-byte type-spec)
448     (declare (ignore name))
449     (unsigned size)))
450
451 (deftype-method
452     translate-to-alien unsigned-byte (type-spec number &optional copy)
453   (declare (ignore type-spec copy))
454   number)
455
456 (deftype-method
457     translate-from-alien unsigned-byte (type-spec number &optional alloc)
458   (declare (ignore type-spec alloc))
459   number)
460
461
462 (deftype-method translate-type-spec single-float (type-spec)
463   (declare (ignore type-spec))
464   'single-float)
465
466 (deftype-method
467     translate-to-alien single-float (type-spec number &optional copy)
468   (declare (ignore type-spec copy))
469   number)
470
471 (deftype-method
472     translate-from-alien single-float (type-spec number &optional alloc)
473   (declare (ignore type-spec alloc))
474   number)
475
476
477 (deftype-method translate-type-spec double-float (type-spec)
478   (declare (ignore type-spec))
479   'double-float)
480
481 (deftype-method
482     translate-to-alien double-float (type-spec number &optional copy)
483   (declare (ignore type-spec copy))
484   number)
485
486 (deftype-method
487     translate-from-alien double-float (type-spec number &optional alloc)
488   (declare (ignore type-spec alloc))
489   number)
490
491
492 (deftype-method translate-type-spec base-char (type-spec)
493   (declare (ignore type-spec))
494   '(unsigned 8))
495
496 (deftype-method translate-to-alien base-char (type-spec char &optional copy)
497   (declare (ignore type-spec copy))
498   `(char-code ,char))
499
500 (deftype-method translate-from-alien base-char (type-spec code &optional alloc)
501   (declare (ignore type-spec alloc))
502   `(code-char ,code))
503
504
505 (deftype-method translate-type-spec string (type-spec)
506   (declare (ignore type-spec))
507   'system-area-pointer)
508
509 (deftype-method translate-to-alien string (type-spec string &optional copy)
510   (declare (ignore type-spec))
511   (if copy
512       `(let ((string ,string))
513          (copy-memory
514           (make-pointer (1+ (kernel:get-lisp-obj-address string)))
515           (1+ (length string))))
516     `(make-pointer (1+ (kernel:get-lisp-obj-address ,string)))))
517
518 (deftype-method
519     translate-from-alien string (type-spec sap &optional (alloc :dynamic))
520   (declare (ignore type-spec))
521   `(let ((sap ,sap))
522      (unless (null-pointer-p sap)
523        (prog1
524            (c-call::%naturalize-c-string sap)
525          ,(when (eq alloc :dynamic) `(deallocate-memory ,sap))))))
526
527 (deftype-method cleanup-alien string (type-spec sap &optional copied)
528   (declare (ignore type-spec))
529   (when copied
530     `(let ((sap ,sap))
531        (unless (null-pointer-p sap)
532          (deallocate-memory sap)))))
533
534
535 (deftype-method translate-type-spec boolean (type-spec)
536   (if (atom type-spec)
537       (unsigned '*)
538     (destructuring-bind (name &optional (size '*))
539         (type-expand-to 'boolean type-spec)
540       (declare (ignore name))
541       (unsigned size))))
542
543 (deftype-method translate-to-alien boolean (type-spec boolean &optional copy)
544   (declare (ignore type-spec copy))
545   `(if ,boolean 1 0))
546
547 (deftype-method translate-from-alien boolean (type-spec int &optional alloc)
548   (declare (ignore type-spec alloc))
549   `(not (zerop ,int)))
550
551
552 (deftype-method translate-type-spec or (union-type-spec)
553   (destructuring-bind (name &rest type-specs)
554       (type-expand-to 'or union-type-spec)
555     (declare (ignore name))
556     (let ((type-spec-translations
557            (map 'list #'translate-type-spec type-specs)))
558       (unless (apply #'all-equal type-spec-translations)
559         (error
560          "No common alien type specifier for union type: ~A" union-type-spec))
561       (first type-spec-translations))))
562
563 (deftype-method translate-to-alien or (union-type-spec expr &optional copy)
564   (destructuring-bind (name &rest type-specs)
565       (type-expand-to 'or union-type-spec)
566     (declare (ignore name))
567     `(let ((value ,expr))
568        (etypecase value
569          ,@(map
570             'list
571             #'(lambda (type-spec)
572                 (list type-spec (translate-to-alien type-spec 'value copy)))
573             type-specs)))))
574
575
576
577 (deftype-method translate-type-spec system-area-pointer (type-spec)
578   (declare (ignore type-spec))
579   'system-area-pointer)
580
581 (deftype-method
582     translate-to-alien system-area-pointer (type-spec sap &optional copy)
583   (declare (ignore type-spec copy))
584   sap)
585
586 (deftype-method
587   translate-from-alien system-area-pointer (type-spec sap &optional alloc)
588   (declare (ignore type-spec alloc))
589   sap)
590
591
592 (deftype-method translate-type-spec null (type-spec)
593   (declare (ignore type-spec))
594   'system-area-pointer)
595
596 (deftype-method translate-to-alien null (type-spec expr &optional copy)
597   (declare (ignore type-spec copy))
598   `(make-pointer 0))
599
600
601 (deftype-method translate-type-spec nil (type-spec)
602   (declare (ignore type-spec))
603   'void)
604
605
606 (deftype-method transalte-type-spec static (type-spec)
607   (translate-type-spec (second type-spec)))
608   
609 (deftype-method translate-to-alien static (type-spec expr &optional copy)
610   (declare (ignore copy))
611   (translate-to-alien (second type-spec) expr nil))
612
613 (deftype-method translate-from-alien static (type-spec alien &optional alloc)
614   (declare (ignore alloc))
615   (translate-from-alien (second type-spec) alien nil))
616
617 (deftype-method cleanup-alien static (type-spec alien &optional copied)
618   (declare (ignore copied))
619   (cleanup-alien type-spec alien nil))
620
621
622
623 ;;;; Enum and flags type
624
625 (defun map-mappings (args op)
626   (let ((current-value 0))
627     (map
628      'list 
629      #'(lambda (mapping)
630          (destructuring-bind (symbol &optional (value current-value))
631              (mklist mapping)
632            (setf current-value (1+ value))
633            (case op
634              (:enum-int (list symbol value))
635              (:flags-int (list symbol (ash 1 value)))
636              (:int-enum (list value symbol))
637              (:int-flags (list (ash 1 value) symbol))
638              (:symbols symbol))))
639      (if (integerp (first args))
640          (rest args)
641        args))))
642
643 (lisp:deftype enum (&rest args)
644   `(member ,@(map-mappings args :symbols)))
645
646 (deftype-method translate-type-spec enum (type-spec)
647   (destructuring-bind (name &rest args) (type-expand-to 'enum type-spec)
648     (declare (ignore name))
649     (if (integerp (first args))
650         `(signed ,(first args))
651       '(signed 32))))
652
653 (deftype-method translate-to-alien enum (type-spec expr &optional copy)
654   (declare (ignore copy))
655   (destructuring-bind (name &rest args) (type-expand-to 'enum type-spec)
656     (declare (ignore name))
657     `(ecase ,expr
658        ,@(map-mappings args :enum-int))))
659
660 (deftype-method translate-from-alien enum (type-spec expr &optional alloc)
661   (declare (ignore alloc))
662   (destructuring-bind (name &rest args) (type-expand-to 'enum type-spec)
663     (declare (ignore name))
664     `(ecase ,expr
665        ,@(map-mappings args :int-enum))))
666
667
668 (lisp:deftype flags (&rest args)
669   `(or
670     null
671     (cons
672      (member ,@(map-mappings args :symbols))
673      list)))
674
675 (deftype-method translate-type-spec flags (type-spec)
676   (destructuring-bind (name &rest args) (type-expand-to 'flags type-spec)
677     (declare (ignore name))
678     (if (integerp (first args))
679         `(signed ,(first args))
680       '(signed 32))))
681
682 (deftype-method translate-to-alien flags (type-spec expr &optional copy)
683   (declare (ignore copy))
684   (destructuring-bind (name &rest args) (type-expand-to 'flags type-spec)
685     (declare (ignore name))
686     (let ((mappings (map-mappings args :flags-int)))
687       `(let ((value 0))
688          (dolist (flag ,expr value)
689            (setq value (logior value (second (assoc flag ',mappings)))))))))
690
691 (deftype-method translate-from-alien flags (type-spec expr &optional alloc)
692   (declare (ignore alloc))
693   (destructuring-bind (name &rest args) (type-expand-to 'flags type-spec)
694     (declare (ignore name))
695     (let ((mappings (map-mappings args :int-flags)))
696       `(let ((result nil))
697          (dolist (mapping ',mappings result)
698            (unless (zerop (logand ,expr (first mapping)))
699              (push (second mapping) result)))))))