records: Allow thunked fields to refer to 'this-record'.
* guix/records.scm (this-record): New syntax parameter. (make-syntactic-constructor)[wrap-field-value]: When F is thunked, return a one-argument lambda instead of a thunk, and parameterize THIS-RECORD. (define-record-type*)[thunked-field-accessor-definition]: Pass X to (real-get X). * tests/records.scm ("define-record-type* & thunked & this-record") ("define-record-type* & thunked & default & this-record") ("define-record-type* & thunked & inherit & this-record"): New tests.
This commit is contained in:
parent
3191b5f6ba
commit
abd4d6b33d
|
@ -25,6 +25,8 @@
|
||||||
#:use-module (ice-9 regex)
|
#:use-module (ice-9 regex)
|
||||||
#:use-module (ice-9 rdelim)
|
#:use-module (ice-9 rdelim)
|
||||||
#:export (define-record-type*
|
#:export (define-record-type*
|
||||||
|
this-record
|
||||||
|
|
||||||
alist->record
|
alist->record
|
||||||
object->fields
|
object->fields
|
||||||
recutils->alist
|
recutils->alist
|
||||||
|
@ -93,6 +95,17 @@ interface\" (ABI) for TYPE is equal to COOKIE."
|
||||||
(()
|
(()
|
||||||
#t)))))))
|
#t)))))))
|
||||||
|
|
||||||
|
(define-syntax-parameter this-record
|
||||||
|
(lambda (s)
|
||||||
|
"Return the record being defined. This macro may only be used in the
|
||||||
|
context of the definition of a thunked field."
|
||||||
|
(syntax-case s ()
|
||||||
|
(id
|
||||||
|
(identifier? #'id)
|
||||||
|
(syntax-violation 'this-record
|
||||||
|
"cannot be used outside of a record instantiation"
|
||||||
|
#'id)))))
|
||||||
|
|
||||||
(define-syntax make-syntactic-constructor
|
(define-syntax make-syntactic-constructor
|
||||||
(syntax-rules ()
|
(syntax-rules ()
|
||||||
"Make the syntactic constructor NAME for TYPE, that calls CTOR, and
|
"Make the syntactic constructor NAME for TYPE, that calls CTOR, and
|
||||||
|
@ -148,7 +161,14 @@ of TYPE matches the expansion-time ABI."
|
||||||
|
|
||||||
(define (wrap-field-value f value)
|
(define (wrap-field-value f value)
|
||||||
(cond ((thunked-field? f)
|
(cond ((thunked-field? f)
|
||||||
#`(lambda () #,value))
|
#`(lambda (x)
|
||||||
|
(syntax-parameterize ((this-record
|
||||||
|
(lambda (s)
|
||||||
|
(syntax-case s ()
|
||||||
|
(id
|
||||||
|
(identifier? #'id)
|
||||||
|
#'x)))))
|
||||||
|
#,value)))
|
||||||
((delayed-field? f)
|
((delayed-field? f)
|
||||||
#`(delay #,value))
|
#`(delay #,value))
|
||||||
(else value)))
|
(else value)))
|
||||||
|
@ -308,7 +328,7 @@ inherited."
|
||||||
(with-syntax ((real-get (wrapped-field-accessor-name field)))
|
(with-syntax ((real-get (wrapped-field-accessor-name field)))
|
||||||
#'(define-inlinable (get x)
|
#'(define-inlinable (get x)
|
||||||
;; The real value of that field is a thunk, so call it.
|
;; The real value of that field is a thunk, so call it.
|
||||||
((real-get x)))))))
|
((real-get x) x))))))
|
||||||
|
|
||||||
(define (delayed-field-accessor-definition field)
|
(define (delayed-field-accessor-definition field)
|
||||||
;; Return the real accessor for FIELD, which is assumed to be a
|
;; Return the real accessor for FIELD, which is assumed to be a
|
||||||
|
|
|
@ -170,6 +170,46 @@
|
||||||
(parameterize ((mark (cons 'a 'b)))
|
(parameterize ((mark (cons 'a 'b)))
|
||||||
(eq? (foo-bar y) (mark)))))))
|
(eq? (foo-bar y) (mark)))))))
|
||||||
|
|
||||||
|
(test-assert "define-record-type* & thunked & this-record"
|
||||||
|
(begin
|
||||||
|
(define-record-type* <foo> foo make-foo
|
||||||
|
foo?
|
||||||
|
(bar foo-bar)
|
||||||
|
(baz foo-baz (thunked)))
|
||||||
|
|
||||||
|
(let ((x (foo (bar 40)
|
||||||
|
(baz (+ (foo-bar this-record) 2)))))
|
||||||
|
(and (= 40 (foo-bar x))
|
||||||
|
(= 42 (foo-baz x))))))
|
||||||
|
|
||||||
|
(test-assert "define-record-type* & thunked & default & this-record"
|
||||||
|
(begin
|
||||||
|
(define-record-type* <foo> foo make-foo
|
||||||
|
foo?
|
||||||
|
(bar foo-bar)
|
||||||
|
(baz foo-baz (thunked)
|
||||||
|
(default (+ (foo-bar this-record) 2))))
|
||||||
|
|
||||||
|
(let ((x (foo (bar 40))))
|
||||||
|
(and (= 40 (foo-bar x))
|
||||||
|
(= 42 (foo-baz x))))))
|
||||||
|
|
||||||
|
(test-assert "define-record-type* & thunked & inherit & this-record"
|
||||||
|
(begin
|
||||||
|
(define-record-type* <foo> foo make-foo
|
||||||
|
foo?
|
||||||
|
(bar foo-bar)
|
||||||
|
(baz foo-baz (thunked)
|
||||||
|
(default (+ (foo-bar this-record) 2))))
|
||||||
|
|
||||||
|
(let* ((x (foo (bar 40)))
|
||||||
|
(y (foo (inherit x) (bar -2)))
|
||||||
|
(z (foo (inherit x) (baz -2))))
|
||||||
|
(and (= -2 (foo-bar y))
|
||||||
|
(= 0 (foo-baz y))
|
||||||
|
(= 40 (foo-bar z))
|
||||||
|
(= -2 (foo-baz z))))))
|
||||||
|
|
||||||
(test-assert "define-record-type* & delayed"
|
(test-assert "define-record-type* & delayed"
|
||||||
(begin
|
(begin
|
||||||
(define-record-type* <foo> foo make-foo
|
(define-record-type* <foo> foo make-foo
|
||||||
|
|
Loading…
Reference in New Issue