remove encoding of versions into the file system (for now?)
[bpt/guile.git] / module / rnrs / records / procedural.scm
CommitLineData
ce543a9f
JG
1;;; procedural.scm --- Procedural interface to R6RS records
2
3;; Copyright (C) 2010 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\f
19
20(library (rnrs records procedural (6))
21 (export make-record-type-descriptor
22 record-type-descriptor?
23 make-record-constructor-descriptor
24
25 record-constructor
26 record-predicate
27 record-accessor
28 record-mutator)
29
30 (import (rnrs base (6))
31 (only (guile) and=>
32 throw
33 display
34 make-struct
35 make-vtable
36 map
37 simple-format
38 string-append
39
40 struct?
41 struct-ref
42 struct-set!
43 struct-vtable
44 vtable-index-layout
45
46 make-hash-table
47 hashq-ref
48 hashq-set!
49
50 vector->list)
51 (ice-9 receive)
55684b5e
JG
52 (only (srfi :1) fold split-at take))
53
54 (define (record-internal? obj)
55 (and (struct? obj)
56 (let* ((vtable (struct-vtable obj))
57 (layout (symbol->string
58 (struct-ref vtable vtable-index-layout))))
59 (and (>= (string-length layout) 4)
60 (let ((rtd (struct-ref obj record-index-rtd)))
61 (and (record-type-descriptor? rtd)))))))
62
63 (define record-index-parent 0)
64 (define record-index-rtd 1)
65
66 (define rtd-index-name 0)
67 (define rtd-index-uid 1)
68 (define rtd-index-parent 2)
69 (define rtd-index-sealed? 3)
70 (define rtd-index-opaque? 4)
71 (define rtd-index-predicate 5)
72 (define rtd-index-field-names 6)
73 (define rtd-index-field-vtable 7)
74 (define rtd-index-field-binder 8)
75
76 (define rctd-index-rtd 0)
77 (define rctd-index-parent 1)
78 (define rctd-index-protocol 2)
ce543a9f
JG
79
80 (define record-type-vtable
81 (make-vtable "prprprprprprprprpr"
82 (lambda (obj port)
55684b5e
JG
83 (simple-format port "#<r6rs:record-type:~A>"
84 (struct-ref obj rtd-index-name)))))
ce543a9f
JG
85
86 (define record-constructor-vtable
87 (make-vtable "prprpr"
88 (lambda (obj port)
55684b5e
JG
89 (simple-format port "#<r6rs:record-constructor:~A>"
90 (struct-ref (struct-ref obj rctd-index-rtd)
91 rtd-index-name)))))
ce543a9f
JG
92
93 (define uid-table (make-hash-table))
94
95 (define (make-record-type-descriptor name parent uid sealed? opaque? fields)
96 (define fields-vtable
55684b5e
JG
97 (make-vtable (fold (lambda (x p)
98 (string-append p (case (car x)
99 ((immutable) "pr")
100 ((mutable) "pw"))))
101 "prpr" (vector->list fields))
ce543a9f 102 (lambda (obj port)
55684b5e
JG
103 (simple-format port "#<r6rs:record:~A>" name))))
104 (define field-names (list->vector (map cadr (vector->list fields))))
ce543a9f
JG
105 (define late-rtd #f)
106 (define (private-record-predicate obj)
55684b5e
JG
107 (and (record-internal? obj)
108 (let ((rtd (struct-ref obj record-index-rtd)))
109 (or (eq? (struct-ref rtd rtd-index-field-vtable) fields-vtable)
110 (and=> (struct-ref obj record-index-parent)
111 private-record-predicate)))))
ce543a9f
JG
112
113 (define (field-binder parent-struct . args)
114 (apply make-struct (append (list fields-vtable 0
115 parent-struct
116 late-rtd)
117 args)))
55684b5e 118 (if (and parent (struct-ref parent rtd-index-sealed?))
ce543a9f
JG
119 (r6rs-raise (make-assertion-violation)))
120
55684b5e
JG
121 (let ((matching-rtd (and uid (hashq-ref uid-table uid)))
122 (opaque? (or opaque? (and parent (struct-ref
123 parent rtd-index-opaque?)))))
ce543a9f
JG
124 (if matching-rtd
125 (if (equal? (list name
126 parent
127 sealed?
128 opaque?
129 field-names
130 (struct-ref fields-vtable vtable-index-layout))
55684b5e
JG
131 (list (struct-ref matching-rtd rtd-index-name)
132 (struct-ref matching-rtd rtd-index-parent)
133 (struct-ref matching-rtd rtd-index-sealed?)
134 (struct-ref matching-rtd rtd-index-opaque?)
135 (struct-ref matching-rtd rtd-index-field-names)
136 (struct-ref (struct-ref matching-rtd
137 rtd-index-field-vtable)
ce543a9f
JG
138 vtable-index-layout)))
139 matching-rtd
140 (r6rs-raise (make-assertion-violation)))
141
142 (let ((rtd (make-struct record-type-vtable 0
143
144 name
145 uid
146 parent
147 sealed?
148 opaque?
149
150 private-record-predicate
151 field-names
152 fields-vtable
153 field-binder)))
154 (set! late-rtd rtd)
155 (if uid (hashq-set! uid-table uid rtd))
156 rtd))))
157
158 (define (record-type-descriptor? obj)
159 (and (struct? obj) (eq? (struct-vtable obj) record-type-vtable)))
160
161 (define (make-record-constructor-descriptor rtd
162 parent-constructor-descriptor
163 protocol)
55684b5e 164 (define rtd-arity (vector-length (struct-ref rtd rtd-index-field-names)))
ce543a9f
JG
165 (define (default-inherited-protocol n)
166 (lambda args
167 (receive
168 (n-args p-args)
169 (split-at args (- (length args) rtd-arity))
170 (let ((p (apply n n-args)))
171 (apply p p-args)))))
172 (define (default-protocol p) p)
173
55684b5e 174 (let* ((prtd (struct-ref rtd rtd-index-parent))
ce543a9f
JG
175 (pcd (or parent-constructor-descriptor
176 (and=> prtd (lambda (d) (make-record-constructor-descriptor
177 prtd #f #f)))))
178 (prot (or protocol (if pcd
179 default-inherited-protocol
180 default-protocol))))
181 (make-struct record-constructor-vtable 0 rtd pcd prot)))
182
183 (define (record-constructor rctd)
55684b5e
JG
184 (let* ((rtd (struct-ref rctd rctd-index-rtd))
185 (parent-rctd (struct-ref rctd rctd-index-parent))
186 (protocol (struct-ref rctd rctd-index-protocol)))
ce543a9f
JG
187 (protocol
188 (if parent-rctd
189 (let ((parent-record-constructor (record-constructor parent-rctd))
55684b5e 190 (parent-rtd (struct-ref parent-rctd rctd-index-rtd)))
ce543a9f
JG
191 (lambda args
192 (let ((struct (apply parent-record-constructor args)))
193 (lambda args
55684b5e 194 (apply (struct-ref rtd rtd-index-field-binder)
ce543a9f 195 (cons struct args))))))
55684b5e
JG
196 (lambda args (apply (struct-ref rtd rtd-index-field-binder)
197 (cons #f args)))))))
ce543a9f 198
55684b5e 199 (define (record-predicate rtd) (struct-ref rtd rtd-index-predicate))
ce543a9f
JG
200
201 (define (record-accessor rtd k)
202 (define (record-accessor-inner obj)
55684b5e
JG
203 (if (not (record-internal? obj))
204 (r6rs-raise (make-assertion-violation)))
205 (if (eq? (struct-ref obj record-index-rtd) rtd)
206 (struct-ref obj (+ k 2))
207 (record-accessor-inner (struct-ref obj record-index-parent))))
ce543a9f
JG
208 (lambda (obj) (record-accessor-inner obj)))
209
210 (define (record-mutator rtd k)
211 (define (record-mutator-inner obj val)
212 (and obj
55684b5e
JG
213 (or (and (eq? (struct-ref obj record-index-rtd) rtd)
214 (struct-set! obj (+ k 2) val))
215 (record-mutator-inner (struct-ref obj record-index-parent)
216 val))))
217 (let* ((rtd-vtable (struct-ref rtd rtd-index-field-vtable))
ce543a9f
JG
218 (field-layout (symbol->string
219 (struct-ref rtd-vtable vtable-index-layout))))
220 (if (not (eqv? (string-ref field-layout (+ (* (+ k 2) 2) 1)) #\w))
221 (r6rs-raise (make-assertion-violation))))
222 (lambda (obj val) (record-mutator-inner obj val)))
223
224 ;; Condition types that are used in the current library. These are defined
225 ;; here and not in (rnrs conditions) to avoid a circular dependency.
226
227 (define &condition (make-record-type-descriptor '&condition #f #f #f #f '#()))
228 (define &condition-constructor-descriptor
229 (make-record-constructor-descriptor &condition #f #f))
230
231 (define &serious (make-record-type-descriptor
232 '&serious &condition #f #f #f '#()))
233 (define &serious-constructor-descriptor
234 (make-record-constructor-descriptor
235 &serious &condition-constructor-descriptor #f))
236
237 (define make-serious-condition
238 (record-constructor &serious-constructor-descriptor))
ce543a9f
JG
239
240 (define &violation (make-record-type-descriptor
241 '&violation &serious #f #f #f '#()))
242 (define &violation-constructor-descriptor
243 (make-record-constructor-descriptor
244 &violation &serious-constructor-descriptor #f))
245 (define make-violation (record-constructor &violation-constructor-descriptor))
ce543a9f
JG
246
247 (define &assertion (make-record-type-descriptor
248 '&assertion &violation #f #f #f '#()))
249 (define make-assertion-violation
250 (record-constructor
251 (make-record-constructor-descriptor
252 &assertion &violation-constructor-descriptor #f)))
ce543a9f
JG
253
254 ;; Exception wrapper type, along with a wrapping `throw' implementation.
255 ;; These are used in the current library, and so they are defined here and not
256 ;; in (rnrs exceptions) to avoid a circular dependency.
257
258 (define &raise-object-wrapper
259 (make-record-type-descriptor '&raise-object-wrapper #f #f #f #f
260 '#((immutable obj) (immutable continuation))))
261 (define make-raise-object-wrapper
262 (record-constructor (make-record-constructor-descriptor
263 &raise-object-wrapper #f #f)))
264 (define raise-object-wrapper? (record-predicate &raise-object-wrapper))
265 (define raise-object-wrapper-obj (record-accessor &raise-object-wrapper 0))
266 (define raise-object-wrapper-continuation
267 (record-accessor &raise-object-wrapper 1))
268
269 (define (r6rs-raise obj)
270 (throw 'r6rs:exception (make-raise-object-wrapper obj #f)))
271 (define (r6rs-raise-continuable obj)
272 (define (r6rs-raise-continuable-internal continuation)
d1c83d38 273 (throw 'r6rs:exception (make-raise-object-wrapper obj continuation)))
ce543a9f
JG
274 (call/cc r6rs-raise-continuable-internal))
275)