records: Support custom 'this' identifiers.
This lets record users choose an identifier other than 'this-record'. * guix/records.scm (make-syntactic-constructor): Add #:this-identifier. [wrap-field-value]: Honor it. (define-record-type*): Add form with extra THIS-IDENTIFIER and honor it. * tests/records.scm ("define-record-type* & thunked & inherit & custom this"): New test.
This commit is contained in:
parent
ec12e53736
commit
d2be7e3c4b
|
@ -118,6 +118,7 @@ of TYPE matches the expansion-time ABI."
|
||||||
((_ type name ctor (expected ...)
|
((_ type name ctor (expected ...)
|
||||||
#:abi-cookie abi-cookie
|
#:abi-cookie abi-cookie
|
||||||
#:thunked thunked
|
#:thunked thunked
|
||||||
|
#:this-identifier this-identifier
|
||||||
#:delayed delayed
|
#:delayed delayed
|
||||||
#:innate innate
|
#:innate innate
|
||||||
#:defaults defaults)
|
#:defaults defaults)
|
||||||
|
@ -162,7 +163,7 @@ 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 (x)
|
#`(lambda (x)
|
||||||
(syntax-parameterize ((this-record
|
(syntax-parameterize ((#,this-identifier
|
||||||
(lambda (s)
|
(lambda (s)
|
||||||
(syntax-case s ()
|
(syntax-case s ()
|
||||||
(id
|
(id
|
||||||
|
@ -254,6 +255,7 @@ may look like this:
|
||||||
|
|
||||||
(define-record-type* <thing> thing make-thing
|
(define-record-type* <thing> thing make-thing
|
||||||
thing?
|
thing?
|
||||||
|
this-thing
|
||||||
(name thing-name (default \"chbouib\"))
|
(name thing-name (default \"chbouib\"))
|
||||||
(port thing-port
|
(port thing-port
|
||||||
(default (current-output-port)) (thunked))
|
(default (current-output-port)) (thunked))
|
||||||
|
@ -273,7 +275,8 @@ default value specified in the 'define-record-type*' form is used:
|
||||||
|
|
||||||
The 'port' field is \"thunked\", meaning that calls like '(thing-port x)' will
|
The 'port' field is \"thunked\", meaning that calls like '(thing-port x)' will
|
||||||
actually compute the field's value in the current dynamic extent, which is
|
actually compute the field's value in the current dynamic extent, which is
|
||||||
useful when referring to fluids in a field's value.
|
useful when referring to fluids in a field's value. Furthermore, that thunk
|
||||||
|
can access the record it belongs to via the 'this-thing' identifier.
|
||||||
|
|
||||||
A field can also be marked as \"delayed\" instead of \"thunked\", in which
|
A field can also be marked as \"delayed\" instead of \"thunked\", in which
|
||||||
case its value is effectively wrapped in a (delay …) form.
|
case its value is effectively wrapped in a (delay …) form.
|
||||||
|
@ -352,7 +355,9 @@ inherited."
|
||||||
|
|
||||||
(syntax-case s ()
|
(syntax-case s ()
|
||||||
((_ type syntactic-ctor ctor pred
|
((_ type syntactic-ctor ctor pred
|
||||||
|
this-identifier
|
||||||
(field get properties ...) ...)
|
(field get properties ...) ...)
|
||||||
|
(identifier? #'this-identifier)
|
||||||
(let* ((field-spec #'((field get properties ...) ...))
|
(let* ((field-spec #'((field get properties ...) ...))
|
||||||
(thunked (filter-map thunked-field? field-spec))
|
(thunked (filter-map thunked-field? field-spec))
|
||||||
(delayed (filter-map delayed-field? field-spec))
|
(delayed (filter-map delayed-field? field-spec))
|
||||||
|
@ -381,15 +386,36 @@ inherited."
|
||||||
field-spec* ...)
|
field-spec* ...)
|
||||||
(define #,(current-abi-identifier #'type)
|
(define #,(current-abi-identifier #'type)
|
||||||
#,cookie)
|
#,cookie)
|
||||||
|
|
||||||
|
#,@(if (free-identifier=? #'this-identifier #'this-record)
|
||||||
|
#'()
|
||||||
|
#'((define-syntax-parameter this-identifier
|
||||||
|
(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-identifier
|
||||||
|
"cannot be used outside \
|
||||||
|
of a record instantiation"
|
||||||
|
#'id)))))))
|
||||||
thunked-field-accessor ...
|
thunked-field-accessor ...
|
||||||
delayed-field-accessor ...
|
delayed-field-accessor ...
|
||||||
(make-syntactic-constructor type syntactic-ctor ctor
|
(make-syntactic-constructor type syntactic-ctor ctor
|
||||||
(field ...)
|
(field ...)
|
||||||
#:abi-cookie #,cookie
|
#:abi-cookie #,cookie
|
||||||
#:thunked #,thunked
|
#:thunked #,thunked
|
||||||
|
#:this-identifier #'this-identifier
|
||||||
#:delayed #,delayed
|
#:delayed #,delayed
|
||||||
#:innate #,innate
|
#:innate #,innate
|
||||||
#:defaults #,defaults))))))))
|
#:defaults #,defaults)))))
|
||||||
|
((_ type syntactic-ctor ctor pred
|
||||||
|
(field get properties ...) ...)
|
||||||
|
;; When no 'this' identifier was specified, use 'this-record'.
|
||||||
|
#'(define-record-type* type syntactic-ctor ctor pred
|
||||||
|
this-record
|
||||||
|
(field get properties ...) ...)))))
|
||||||
|
|
||||||
(define* (alist->record alist make keys
|
(define* (alist->record alist make keys
|
||||||
#:optional (multiple-value-keys '()))
|
#:optional (multiple-value-keys '()))
|
||||||
|
|
|
@ -210,6 +210,24 @@
|
||||||
(= 40 (foo-bar z))
|
(= 40 (foo-bar z))
|
||||||
(= -2 (foo-baz z))))))
|
(= -2 (foo-baz z))))))
|
||||||
|
|
||||||
|
(test-assert "define-record-type* & thunked & inherit & custom this"
|
||||||
|
(let ()
|
||||||
|
(define-record-type* <foo> foo make-foo
|
||||||
|
foo? this-foo
|
||||||
|
(thing foo-thing (thunked)))
|
||||||
|
(define-record-type* <bar> bar make-bar
|
||||||
|
bar? this-bar
|
||||||
|
(baz bar-baz (thunked)))
|
||||||
|
|
||||||
|
;; Nest records and test the two self references.
|
||||||
|
(let* ((x (foo (thing (bar (baz (list this-bar this-foo))))))
|
||||||
|
(y (foo-thing x)))
|
||||||
|
(match (bar-baz y)
|
||||||
|
((first second)
|
||||||
|
(and (eq? second x)
|
||||||
|
(bar? first)
|
||||||
|
(eq? first y)))))))
|
||||||
|
|
||||||
(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