remove encoding of versions into the file system (for now?)
[bpt/guile.git] / module / rnrs / records / syntactic.scm
CommitLineData
ce543a9f
JG
1;;; syntactic.scm --- Syntactic support for 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 syntactic (6))
f797da47
JG
21 (export define-record-type
22 record-type-descriptor
23 record-constructor-descriptor)
24 (import (only (guile) *unspecified* and=> gensym unspecified?)
ce543a9f 25 (rnrs base (6))
f797da47
JG
26 (rnrs conditions (6))
27 (rnrs exceptions (6))
28 (rnrs hashtables (6))
ce543a9f
JG
29 (rnrs lists (6))
30 (rnrs records procedural (6))
31 (rnrs syntax-case (6))
32 (only (srfi :1) take))
33
f797da47
JG
34 (define record-type-registry (make-eq-hashtable))
35
36 (define (guess-constructor-name record-name)
37 (string->symbol (string-append "make-" (symbol->string record-name))))
38 (define (guess-predicate-name record-name)
39 (string->symbol (string-append (symbol->string record-name) "?")))
40 (define (register-record-type name rtd rcd)
41 (hashtable-set! record-type-registry name (cons rtd rcd)))
42 (define (lookup-record-type-descriptor name)
43 (and=> (hashtable-ref record-type-registry name #f) car))
44 (define (lookup-record-constructor-descriptor name)
45 (and=> (hashtable-ref record-type-registry name #f) cdr))
46
ce543a9f
JG
47 (define-syntax define-record-type
48 (lambda (stx)
ce543a9f
JG
49 (syntax-case stx ()
50 ((_ (record-name constructor-name predicate-name) record-clause ...)
51 #'(define-record-type0
52 (record-name constructor-name predicate-name)
53 record-clause ...))
54 ((_ record-name record-clause ...)
55 (let* ((record-name-sym (syntax->datum #'record-name))
56 (constructor-name
57 (datum->syntax
58 #'record-name (guess-constructor-name record-name-sym)))
59 (predicate-name
60 (datum->syntax
61 #'record-name (guess-predicate-name record-name-sym))))
62 #`(define-record-type0
63 (record-name #,constructor-name #,predicate-name)
64 record-clause ...))))))
65
f797da47
JG
66 (define (sequence n)
67 (define (seq-inner n) (if (= n 0) '(0) (cons n (seq-inner (- n 1)))))
68 (reverse (seq-inner n)))
69 (define (number-fields fields)
70 (define (number-fields-inner fields counter)
71 (if (null? fields)
72 '()
73 (cons (cons fields counter)
74 (number-fields-inner (cdr fields) (+ counter 1)))))
75 (number-fields-inner fields 0))
76
77 (define (process-fields record-name fields)
78 (define record-name-str (symbol->string record-name))
79 (define (guess-accessor-name field-name)
80 (string->symbol (string-append
81 record-name-str "-" (symbol->string field-name))))
82 (define (guess-mutator-name field-name)
83 (string->symbol
84 (string-append
85 record-name-str "-" (symbol->string field-name) "-set!")))
86
87 (define (f x)
88 (cond ((symbol? x) (list 'immutable x (guess-accessor-name x) #f))
89 ((not (list? x)) (error))
90 ((eq? (car x) 'immutable)
91 (cons 'immutable
92 (case (length x)
93 ((2) (list (cadr x) (guess-accessor-name (cadr x)) #f))
94 ((3) (list (cadr x) (caddr x) #f))
95 (else (error)))))
96 ((eq? (car x) 'mutable)
97 (cons 'mutable
98 (case (length x)
99 ((2) (list (cadr x)
100 (guess-accessor-name (cadr x))
101 (guess-mutator-name (cadr x))))
102 ((4) (cdr x))
103 (else (error)))))
104 (else (error))))
105 (map f fields))
106
ce543a9f 107 (define-syntax define-record-type0
f797da47 108 (lambda (stx)
ce543a9f
JG
109 (syntax-case stx ()
110 ((_ (record-name constructor-name predicate-name) record-clause ...)
111 (let loop ((fields *unspecified*)
112 (parent *unspecified*)
113 (protocol *unspecified*)
114 (sealed *unspecified*)
115 (opaque *unspecified*)
116 (nongenerative *unspecified*)
117 (constructor *unspecified*)
118 (parent-rtd *unspecified*)
119 (record-clauses (syntax->datum #'(record-clause ...))))
120 (if (null? record-clauses)
f797da47
JG
121 (let*
122 ((fields (if (unspecified? fields) '() fields))
123 (field-names
ce543a9f
JG
124 (datum->syntax
125 #'record-name
f797da47 126 (list->vector (map (lambda (x) (take x 2)) fields))))
ce543a9f
JG
127 (field-accessors
128 (fold-left (lambda (x c lst)
129 (cons #`(define #,(datum->syntax
130 #'record-name (caddr x))
131 (record-accessor record-name #,c))
132 lst))
133 '() fields (sequence (length fields))))
134 (field-mutators
135 (fold-left (lambda (x c lst)
136 (if (cadddr x)
137 (cons #`(define #,(datum->syntax
138 #'record-name (cadddr x))
139 (record-mutator record-name #,c))
140 lst)
141 lst))
142 '() fields (sequence (length fields))))
f797da47
JG
143
144 (parent-cd
145 (datum->syntax
146 stx (cond ((not (unspecified? parent))
147 `(record-constructor-descriptor ,parent))
148 ((not (unspecified? parent-rtd)) (cadr parent-rtd))
149 (else #f))))
150 (parent-rtd
151 (datum->syntax
152 stx (cond ((not (unspecified? parent))
153 `(record-type-descriptor ,parent))
154 ((not (unspecified? parent-rtd)) (car parent-rtd))
155 (else #f))))
156
ce543a9f
JG
157 (protocol (datum->syntax
158 #'record-name (if (unspecified? protocol)
159 #f protocol)))
160 (uid (datum->syntax
161 #'record-name (if (unspecified? nongenerative)
162 #f nongenerative)))
163 (sealed? (if (unspecified? sealed) #f sealed))
164 (opaque? (if (unspecified? opaque) #f opaque))
f797da47
JG
165
166 (record-name-sym (datum->syntax
167 stx (list 'quote
168 (syntax->datum #'record-name)))))
ce543a9f
JG
169
170 #`(begin
171 (define record-name
172 (make-record-type-descriptor
f797da47
JG
173 #,record-name-sym
174 #,parent-rtd #,uid #,sealed? #,opaque?
ce543a9f
JG
175 #,field-names))
176 (define constructor-name
177 (record-constructor
178 (make-record-constructor-descriptor
179 record-name #,parent-cd #,protocol)))
f797da47
JG
180 (register-record-type
181 #,record-name-sym
182 record-name (make-record-constructor-descriptor
183 record-name #,parent-cd #,protocol))
ce543a9f
JG
184 (define predicate-name (record-predicate record-name))
185 #,@field-accessors
186 #,@field-mutators))
187 (let ((cr (car record-clauses)))
188 (case (car cr)
189 ((fields)
190 (if (unspecified? fields)
191 (loop (process-fields (syntax->datum #'record-name)
192 (cdr cr))
193 parent protocol sealed opaque nongenerative
194 constructor parent-rtd (cdr record-clauses))
f797da47
JG
195 (raise (make-assertion-violation))))
196 ((parent)
197 (if (not (unspecified? parent-rtd))
198 (raise (make-assertion-violation)))
199 (if (unspecified? parent)
200 (loop fields (cadr cr) protocol sealed opaque
201 nongenerative constructor parent-rtd
202 (cdr record-clauses))
203 (raise (make-assertion-violation))))
204 ((protocol)
205 (if (unspecified? protocol)
206 (loop fields parent (cadr cr) sealed opaque
207 nongenerative constructor parent-rtd
208 (cdr record-clauses))
209 (raise (make-assertion-violation))))
210 ((sealed)
211 (if (unspecified? sealed)
212 (loop fields parent protocol (cadr cr) opaque
213 nongenerative constructor parent-rtd
214 (cdr record-clauses))
215 (raise (make-assertion-violation))))
ce543a9f
JG
216 ((opaque) (if (unspecified? opaque)
217 (loop fields parent protocol sealed (cadr cr)
218 nongenerative constructor parent-rtd
219 (cdr record-clauses))
f797da47
JG
220 (raise (make-assertion-violation))))
221 ((nongenerative)
222 (if (unspecified? nongenerative)
223 (let ((uid (list 'quote
224 (or (and (> (length cr) 1) (cadr cr))
225 (gensym)))))
226 (loop fields parent protocol sealed
227 opaque uid constructor
228 parent-rtd (cdr record-clauses)))
229 (raise (make-assertion-violation))))
230 ((parent-rtd)
231 (if (not (unspecified? parent))
232 (raise (make-assertion-violation)))
233 (if (unspecified? parent-rtd)
234 (loop fields parent protocol sealed opaque
235 nongenerative constructor (cdr cr)
236 (cdr record-clauses))
237 (raise (make-assertion-violation))))
238 (else (raise (make-assertion-violation)))))))))))
239
240 (define-syntax record-type-descriptor
241 (lambda (stx)
242 (syntax-case stx ()
243 ((_ name) #`(lookup-record-type-descriptor
244 #,(datum->syntax
245 stx (list 'quote (syntax->datum #'name))))))))
246
247 (define-syntax record-constructor-descriptor
248 (lambda (stx)
249 (syntax-case stx ()
250 ((_ name) #`(lookup-record-constructor-descriptor
251 #,(datum->syntax
252 stx (list 'quote (syntax->datum #'name))))))))
ce543a9f 253)