1 ;;; Extensions to SRFI-9
3 ;; Copyright (C) 2010, 2012 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 ;; Extensions to SRFI-9. Fully documented in the Guile Reference Manual.
25 (define-module (srfi srfi-9 gnu)
26 #:use-module (srfi srfi-1)
27 #:use-module (system base ck)
28 #:export (set-record-type-printer!
29 define-immutable-record-type
33 (define (set-record-type-printer! type proc)
34 "Set PROC as the custom printer for TYPE."
35 (struct-set! type vtable-index-printer proc))
37 (define-syntax-rule (define-immutable-record-type name ctor pred fields ...)
38 ((@@ (srfi srfi-9) %define-record-type)
39 #t (define-immutable-record-type name ctor pred fields ...)
40 name ctor pred fields ...))
42 (define-syntax-rule (set-field s (getter ...) expr)
43 (%set-fields #t (set-field s (getter ...) expr) ()
44 s ((getter ...) expr)))
46 (define-syntax-rule (set-fields s . rest)
47 (%set-fields #t (set-fields s . rest) ()
51 ;; collate-set-field-specs is a helper for %set-fields
52 ;; thats combines all specs with the same head together.
56 ;; SPECS: (((a b c) expr1)
61 ;; RESULT: ((a ((b c) expr1)
66 (define (collate-set-field-specs specs)
67 (define (insert head tail expr result)
68 (cond ((find (lambda (tree)
69 (free-identifier=? head (car tree)))
72 `((,head (,tail ,expr)
74 ,@(delq tree result))))
75 (else `((,head (,tail ,expr))
77 (with-syntax (((((head . tail) expr) ...) specs))
78 (fold insert '() #'(head ...) #'(tail ...) #'(expr ...))))
80 (define-syntax unknown-getter
84 (syntax-violation 'set-fields "unknown getter" #'orig-form #'getter)))))
88 (syntax-case x (quote)
92 (define-syntax c-same-type-check
94 (syntax-case x (quote)
95 ((_ s 'orig-form '(path ...)
100 (or (free-identifier=? t #'type0)
105 field paths ~a and ~a require one object to belong to two different record types (~a and ~a)"
106 (syntax->datum #`(path ... #,g))
107 (syntax->datum #'(path ... getter0))
109 (syntax->datum #'type0))
113 #'(ck s 'on-success)))))
115 (define-syntax %set-fields
117 (with-syntax ((getter-type #'(@@ (srfi srfi-9) getter-type))
118 (getter-index #'(@@ (srfi srfi-9) getter-index))
119 (getter-copier #'(@@ (srfi srfi-9) getter-copier)))
121 ((_ check? orig-form (path-so-far ...)
124 ((_ check? orig-form (path-so-far ...)
127 ((_ check? orig-form (path-so-far ...)
128 struct-expr ((head . tail) expr) ...)
129 (let ((collated-specs (collate-set-field-specs
130 #'(((head . tail) expr) ...))))
131 (with-syntax (((getter0 getter ...)
132 (map car collated-specs)))
133 (with-syntax ((err #'(unknown-getter
140 '(getter0 getter ...)
141 (c-list (getter-type 'getter0 'err)
142 (getter-type 'getter 'err) ...)
143 '(let ((s struct-expr))
144 ((ck () (getter-copier 'getter0 'err))
147 #,@(map (lambda (spec)
148 (with-syntax (((head (tail expr) ...) spec))
149 (with-syntax ((err #'(unknown-getter
154 (path-so-far ... head)
155 (struct-ref s (ck () (getter-index
158 collated-specs)))))))))
159 ((_ check? orig-form (path-so-far ...)
160 s (() e) (() e*) ...)
161 (syntax-violation 'set-fields "duplicate field path"
162 #'orig-form #'(path-so-far ...)))
163 ((_ check? orig-form (path-so-far ...)
164 s ((getter ...) expr) ...)
165 (syntax-violation 'set-fields "one field path is a prefix of another"
166 #'orig-form #'(path-so-far ...)))
167 ((_ check? orig-form . rest)
168 (syntax-violation 'set-fields "invalid syntax" #'orig-form))))))