~ chicken-core (chicken-5) 1831914f6d98daec95bcbf138f872061f3545532
commit 1831914f6d98daec95bcbf138f872061f3545532
Author: felix <felix@call-with-current-continuation.org>
AuthorDate: Mon Oct 18 09:01:56 2010 -0400
Commit: felix <felix@call-with-current-continuation.org>
CommitDate: Mon Oct 18 09:01:56 2010 -0400
optional slot-setter for define-record
diff --git a/chicken-syntax.scm b/chicken-syntax.scm
index 4c049424..fe7ff62c 100644
--- a/chicken-syntax.scm
+++ b/chicken-syntax.scm
@@ -57,48 +57,67 @@
'define-record '()
(##sys#er-transformer
(lambda (x r c)
- (##sys#check-syntax 'define-record x '(_ symbol . #(symbol 0)))
+ (##sys#check-syntax 'define-record x '(_ symbol . _))
(let* ((name (cadr x))
(slots (cddr x))
(prefix (symbol->string name))
- (setters (memq #:record-setters ##sys#features))
(%define (r 'define))
- (%getter-with-setter (r 'getter-with-setter)))
+ (%setter (r 'setter))
+ (%getter-with-setter (r 'getter-with-setter))
+ (slotnames
+ (map (lambda (slot)
+ (cond ((symbol? slot) slot)
+ ((and (pair? slot)
+ (c (car slot) %setter)
+ (pair? (cdr slot))
+ (symbol? (cadr slot))
+ (null? (cddr slot)))
+ (cadr slot))
+ (else
+ (syntax-error
+ 'define-record "invalid slot specification" slot))))
+ slots)))
`(##core#begin
- (,%define
- ,(string->symbol (string-append "make-" prefix))
- (##core#lambda ,slots (##sys#make-structure (##core#quote ,name) ,@slots)) )
- (,%define
- ,(string->symbol (string-append prefix "?"))
- (##core#lambda (x) (##sys#structure? x ',name)) )
- ,@(let mapslots ((slots slots) (i 1))
- (if (eq? slots '())
- slots
- (let* ((slotname (symbol->string (##sys#slot slots 0)))
- (setr (string->symbol (string-append prefix "-" slotname "-set!")))
- (getr (string->symbol (string-append prefix "-" slotname)) ) )
- (cons
- `(##core#begin
- (,%define
- ,setr
- (##core#lambda
+ (,%define
+ ,(string->symbol (string-append "make-" prefix))
+ (##core#lambda
+ ,slotnames
+ (##sys#make-structure (##core#quote ,name) ,@slotnames)))
+ (,%define
+ ,(string->symbol (string-append prefix "?"))
+ (##core#lambda (x) (##sys#structure? x ',name)) )
+ ,@(let mapslots ((slots slots) (i 1))
+ (if (eq? slots '())
+ slots
+ (let* ((a (car slots))
+ (has-setter (not (symbol? a)))
+ (slotname (symbol->string (if has-setter (cadr a) a)))
+ (setr (string->symbol (string-append prefix "-" slotname "-set!")))
+ (getr (string->symbol (string-append prefix "-" slotname)))
+ (setrcode
+ `(##core#lambda
(x val)
(##core#check (##sys#check-structure x (##core#quote ,name)))
- (##sys#block-set! x ,i val) ) )
- (,%define
- ,getr
- ,(if setters
- `(,%getter-with-setter
- (##core#lambda
- (x)
- (##core#check (##sys#check-structure x (##core#quote ,name)))
- (##sys#block-ref x ,i) )
- ,setr)
- `(##core#lambda
- (x)
- (##core#check (##sys#check-structure x (##core#quote ,name)))
- (##sys#block-ref x ,i) ) ) ) )
- (mapslots (##sys#slot slots 1) (fx+ i 1)) ) ) ) ) ) ) ) ) )
+ (##sys#block-set! x ,i val) ) ))
+ (cons
+ `(##core#begin
+ ,@(if has-setter
+ '()
+ `((,%define ,setr ,setrcode)))
+ (,%define
+ ,getr
+ ,(if has-setter
+ `(,%getter-with-setter
+ (##core#lambda
+ (x)
+ (##core#check (##sys#check-structure x (##core#quote ,name)))
+ (##sys#block-ref x ,i) )
+ ,setrcode)
+ `(##core#lambda
+ (x)
+ (##core#check (##sys#check-structure x (##core#quote ,name)))
+ (##sys#block-ref x ,i) ) ) ) )
+ (mapslots (##sys#slot slots 1) (fx+ i 1)) ) ) ) ) ) ) ) ) )
(##sys#extend-macro-environment
'receive
diff --git a/manual/Non-standard macros and special forms b/manual/Non-standard macros and special forms
index 1eca9831..4d4e4923 100644
--- a/manual/Non-standard macros and special forms
+++ b/manual/Non-standard macros and special forms
@@ -392,6 +392,14 @@ and updated using {{(NAME-SLOTNAME-set!}} {{STRUCT}} {{VALUE)}}.
(point-y p1) ==> 99
</enscript>
+{{SLOTNAME}} may alternatively also be of the form
+
+ (setter SLOTNAME)
+
+In this case the slot can be read with {{(NAME-SLOTNAME STRUCT)}}
+and written with {{(set! (NAME-SLOTNAME STRUCT) VALUE)}} (the slot-accessor
+has an associated SRFI-17 "setter" procedure).
+
==== define-record-type
<macro>(define-record-type NAME (CONSTRUCTOR TAG ...) PREDICATE (FIELD ACCESSOR [MODIFIER]) ...)</macro>
diff --git a/tests/records-and-setters-test.scm b/tests/records-and-setters-test.scm
index 3840d7e3..a8761229 100644
--- a/tests/records-and-setters-test.scm
+++ b/tests/records-and-setters-test.scm
@@ -21,3 +21,15 @@
(assert (= 100 (get-z f)))
(set! (make-foo f) 1000)
(assert (= 1000 (get-t f))))
+
+(define-record bar
+ a
+ (setter b))
+
+(let ((b (make-bar 1 2)))
+ (assert (bar? b))
+ (bar-a-set! b 3)
+ (assert (= 3 (bar-a b)))
+ (setter bar-b)
+ (set! (bar-b b) 4)
+ (assert (= (bar-b b) 4)))
Trap