Commit | Line | Data |
---|---|---|
a7ee7f7c AW |
1 | ;;; Wrapping foreign objects in Scheme |
2 | ||
3 | ;;; Copyright (C) 2014 Free Software Foundation, Inc. | |
4 | ;;; | |
5 | ;;; This library is free software; you can redistribute it and/or | |
6 | ;;; modify it under the terms of the GNU Lesser General Public | |
7 | ;;; License as published by the Free Software Foundation; either | |
8 | ;;; version 3 of the License, or (at your option) any later version. | |
9 | ;;; | |
10 | ;;; This library is distributed in the hope that it will be useful, | |
11 | ;;; but WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 | ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
13 | ;;; Lesser General Public License for more details. | |
14 | ;;; | |
15 | ;;; You should have received a copy of the GNU Lesser General Public | |
16 | ;;; License along with this library; if not, write to the Free Software | |
17 | ;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
18 | ;;; | |
19 | ||
20 | ;;; Commentary: | |
21 | ;; | |
22 | ;; | |
23 | ;;; Code: | |
24 | ||
25 | (define-module (system foreign-object) | |
26 | #:use-module (oop goops) | |
27 | #:export (make-foreign-object-type | |
28 | define-foreign-object-type)) | |
29 | ||
30 | (eval-when (eval load expand) | |
31 | (load-extension (string-append "libguile-" (effective-version)) | |
32 | "scm_init_foreign_object")) | |
33 | ||
34 | (define-class <finalizer-class> (<class>) | |
35 | (finalizer #:init-keyword #:finalizer #:init-value #f | |
36 | #:getter finalizer)) | |
37 | ||
38 | (define-method (allocate-instance (class <finalizer-class>) initargs) | |
39 | (let ((instance (next-method)) | |
40 | (finalizer (finalizer class))) | |
41 | (when finalizer | |
42 | (%add-finalizer! instance finalizer)) | |
43 | instance)) | |
44 | ||
45 | (define (getter-method class slot-name existing) | |
46 | (let ((getter (ensure-generic existing slot-name)) | |
47 | (slot-def (or (assq slot-name (slot-ref class 'getters-n-setters)) | |
48 | (slot-missing class slot-name)))) | |
49 | (add-method! getter (compute-getter-method class slot-def)) | |
50 | getter)) | |
51 | ||
52 | (define* (make-foreign-object-type name slots #:key finalizer) | |
53 | (unless (symbol? name) | |
54 | (error "type name should be a symbol" name)) | |
55 | (unless (or (not finalizer) (procedure? finalizer)) | |
56 | (error "finalizer should be a procedure" finalizer)) | |
57 | (let ((dslots (map (lambda (slot) | |
58 | (unless (symbol? slot) | |
59 | (error "slot name should be a symbol" slot)) | |
60 | (list slot #:class <foreign-slot> | |
61 | #:init-keyword (symbol->keyword slot) | |
62 | #:init-value 0)) | |
63 | slots))) | |
64 | (if finalizer | |
65 | (make-class '() dslots #:name name | |
66 | #:finalizer finalizer #:metaclass <finalizer-class>) | |
67 | (make-class '() dslots #:name name)))) | |
68 | ||
69 | (define-syntax define-foreign-object-type | |
70 | (lambda (x) | |
71 | (define (kw-apply slots) | |
72 | (syntax-case slots () | |
73 | (() #'()) | |
74 | ((slot . slots) | |
75 | (let ((kw (symbol->keyword (syntax->datum #'slot)))) | |
76 | #`(#,kw slot . #,(kw-apply #'slots)))))) | |
77 | ||
78 | (syntax-case x () | |
79 | ((_ name constructor (slot ...) kwarg ...) | |
80 | #`(begin | |
81 | (define name | |
82 | (make-foreign-object-type 'name '(slot ...) kwarg ...)) | |
83 | (define slot | |
84 | (getter-method name 'slot (and (defined? 'slot) slot))) | |
85 | ... | |
86 | (define constructor | |
87 | (lambda (slot ...) | |
88 | (make name #,@(kw-apply #'(slot ...)))))))))) |