1 ;;; srfi-9.scm --- define-record-type
3 ;; Copyright (C) 2001, 2002, 2006, 2009, 2010, 2011 Free Software Foundation, Inc.
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.
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.
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
21 ;; This module exports the syntactic form `define-record-type', which
22 ;; is the means for creating record types defined in SRFI-9.
24 ;; The syntax of a record type definition is:
26 ;; <record type definition>
27 ;; -> (define-record-type <type name>
28 ;; (<constructor name> <field tag> ...)
32 ;; <field spec> -> (<field tag> <accessor name>)
33 ;; -> (<field tag> <accessor name> <modifier name>)
35 ;; <field tag> -> <identifier>
36 ;; <... name> -> <identifier>
40 ;; guile> (use-modules (srfi srfi-9))
41 ;; guile> (define-record-type :foo (make-foo x) foo?
42 ;; (x get-x) (y get-y set-y!))
43 ;; guile> (define f (make-foo 1))
48 ;; guile> (set-y! f 2)
61 (define-module (srfi srfi-9)
62 #:use-module (srfi srfi-1)
63 #:export (define-record-type))
65 (cond-expand-provide (current-module) '(srfi-9))
67 (define-syntax define-record-type
69 (define (field-identifiers field-specs)
70 (syntax-case field-specs ()
74 (syntax-case #'field-spec ()
75 ((name accessor) #'(name))
76 ((name accessor modifier) #'(name))))
77 ((field-spec rest ...)
78 (append (field-identifiers #'(field-spec))
79 (field-identifiers #'(rest ...))))))
81 (define (field-indices fields)
82 (fold (lambda (field result)
83 (let ((i (if (null? result)
85 (+ 1 (cdar result)))))
86 (alist-cons field i result)))
90 (define (constructor type-name constructor-spec indices)
91 (syntax-case constructor-spec ()
93 (let ((field-count (length indices))
94 (ctor-args (map (lambda (field)
95 (cons (syntax->datum field) field))
97 #`(define-inlinable #,constructor-spec
98 (make-struct #,type-name 0
101 (>= field-num field-count))
104 (car (find (lambda (f+i)
105 (= (cdr f+i) field-num))
107 (arg (assq name ctor-args)))
114 (define (accessors type-name field-specs indices)
115 (syntax-case field-specs ()
119 (syntax-case #'field-spec ()
121 (with-syntax ((index (assoc-ref indices (syntax->datum #'name))))
122 #`((define-inlinable (accessor s)
123 (if (eq? (struct-vtable s) #,type-name)
125 (throw 'wrong-type-arg 'accessor
126 "Wrong type argument: ~S" (list s)
128 ((name accessor modifier)
129 (with-syntax ((index (assoc-ref indices (syntax->datum #'name))))
130 #`(#,@(accessors type-name #'((name accessor)) indices)
131 (define-inlinable (modifier s val)
132 (if (eq? (struct-vtable s) #,type-name)
133 (struct-set! s index val)
134 (throw 'wrong-type-arg 'modifier
135 "Wrong type argument: ~S" (list s)
137 ((field-spec rest ...)
138 #`(#,@(accessors type-name #'(field-spec) indices)
139 #,@(accessors type-name #'(rest ...) indices)))))
142 ((_ type-name constructor-spec predicate-name field-spec ...)
143 (let* ((fields (field-identifiers #'(field-spec ...)))
144 (field-count (length fields))
145 (layout (string-concatenate (make-list field-count "pw")))
146 (indices (field-indices (map syntax->datum fields))))
149 (make-vtable #,layout
151 (format port "#<~A" 'type-name)
152 #,@(map (lambda (field)
153 (let* ((f (syntax->datum field))
154 (i (assoc-ref indices f)))
155 #`(format port " ~A: ~S" '#,field
156 (struct-ref obj #,i))))
159 (define-inlinable (predicate-name obj)
161 (eq? (struct-vtable obj) type-name)))
163 #,(constructor #'type-name #'constructor-spec indices)
165 #,@(accessors #'type-name #'(field-spec ...) indices)))))))
167 ;;; srfi-9.scm ends here