1 ;;; srfi-9.scm --- define-record-type
3 ;; Copyright (C) 2001, 2002, 2006, 2009 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-inlinable
68 ;; Define a macro and a procedure such that direct calls are inlined, via
69 ;; the macro expansion, whereas references in non-call contexts refer to
70 ;; the procedure. Inspired by the `define-integrable' macro by Dybvig et al.
72 (define (make-procedure-name name)
74 (symbol-append '% (syntax->datum name)
78 ((_ (name formals ...) body ...)
80 (with-syntax ((proc-name (make-procedure-name #'name)))
82 (define (proc-name formals ...)
94 (define-syntax define-record-type
96 (define (field-identifiers field-specs)
97 (syntax-case field-specs ()
99 (syntax-case #'field-spec ()
100 ((name accessor) #'(name))
101 ((name accessor modifier) #'(name))))
102 ((field-spec rest ...)
103 (append (field-identifiers #'(field-spec))
104 (field-identifiers #'(rest ...))))))
106 (define (field-indices fields)
107 (fold (lambda (field result)
108 (let ((i (if (null? result)
110 (+ 1 (cdar result)))))
111 (alist-cons field i result)))
115 (define (constructor type-name constructor-spec indices)
116 (syntax-case constructor-spec ()
118 (let ((field-count (length indices))
119 (ctor-args (map (lambda (field)
120 (cons (syntax->datum field) field))
122 #`(define #,constructor-spec
123 (make-struct #,type-name 0
126 (>= field-num field-count))
129 (car (find (lambda (f+i)
130 (= (cdr f+i) field-num))
132 (arg (assq name ctor-args)))
139 (define (accessors type-name field-specs indices)
140 (syntax-case field-specs ()
142 (syntax-case #'field-spec ()
144 (with-syntax ((index (assoc-ref indices (syntax->datum #'name))))
145 #`((define-inlinable (accessor s)
146 (if (eq? (struct-vtable s) #,type-name)
148 (throw 'wrong-type-arg 'accessor
149 "Wrong type argument: ~S" (list s)
151 ((name accessor modifier)
152 (with-syntax ((index (assoc-ref indices (syntax->datum #'name))))
153 #`(#,@(accessors type-name #'((name accessor)) indices)
154 (define-inlinable (modifier s val)
155 (if (eq? (struct-vtable s) #,type-name)
156 (struct-set! s index val)
157 (throw 'wrong-type-arg 'modifier
158 "Wrong type argument: ~S" (list s)
160 ((field-spec rest ...)
161 #`(#,@(accessors type-name #'(field-spec) indices)
162 #,@(accessors type-name #'(rest ...) indices)))))
165 ((_ type-name constructor-spec predicate-name field-spec ...)
166 (let* ((fields (field-identifiers #'(field-spec ...)))
167 (field-count (length fields))
168 (layout (string-concatenate (make-list field-count "pw")))
169 (indices (field-indices (map syntax->datum fields))))
172 (make-vtable #,layout
174 (format port "#<~A" 'type-name)
175 #,@(map (lambda (field)
176 (let* ((f (syntax->datum field))
177 (i (assoc-ref indices f)))
178 #`(format port " ~A: ~S" '#,field
179 (struct-ref obj #,i))))
182 (define-inlinable (predicate-name obj)
184 (eq? (struct-vtable obj) type-name)))
186 #,(constructor #'type-name #'constructor-spec indices)
188 #,@(accessors #'type-name #'(field-spec ...) indices)))))))
190 ;;; srfi-9.scm ends here