mirror of
https://git.savannah.gnu.org/git/guix.git
synced 2025-01-31 06:46:50 +01:00
Add `define-record-type*'.
* guix/utils.scm (define-record-type*): New macro. * tests/utils.scm ("define-record-type*"): New test.
This commit is contained in:
parent
0d56a551bf
commit
72d869634b
2 changed files with 78 additions and 1 deletions
|
@ -18,6 +18,7 @@
|
||||||
|
|
||||||
(define-module (guix utils)
|
(define-module (guix utils)
|
||||||
#:use-module (srfi srfi-1)
|
#:use-module (srfi srfi-1)
|
||||||
|
#:use-module (srfi srfi-9)
|
||||||
#:use-module (srfi srfi-26)
|
#:use-module (srfi srfi-26)
|
||||||
#:use-module (srfi srfi-39)
|
#:use-module (srfi srfi-39)
|
||||||
#:use-module (srfi srfi-60)
|
#:use-module (srfi srfi-60)
|
||||||
|
@ -27,6 +28,7 @@ (define-module (guix utils)
|
||||||
#:autoload (ice-9 popen) (open-pipe*)
|
#:autoload (ice-9 popen) (open-pipe*)
|
||||||
#:autoload (ice-9 rdelim) (read-line)
|
#:autoload (ice-9 rdelim) (read-line)
|
||||||
#:use-module (ice-9 regex)
|
#:use-module (ice-9 regex)
|
||||||
|
#:use-module (ice-9 match)
|
||||||
#:use-module ((chop hash)
|
#:use-module ((chop hash)
|
||||||
#:select (bytevector-hash
|
#:select (bytevector-hash
|
||||||
hash-method/sha256))
|
hash-method/sha256))
|
||||||
|
@ -42,6 +44,7 @@ (define-module (guix utils)
|
||||||
%nixpkgs-directory
|
%nixpkgs-directory
|
||||||
nixpkgs-derivation
|
nixpkgs-derivation
|
||||||
|
|
||||||
|
define-record-type*
|
||||||
memoize
|
memoize
|
||||||
gnu-triplet->nix-system
|
gnu-triplet->nix-system
|
||||||
%current-system))
|
%current-system))
|
||||||
|
@ -391,6 +394,66 @@ (define (nixpkgs-derivation attribute)
|
||||||
;;; Miscellaneous.
|
;;; Miscellaneous.
|
||||||
;;;
|
;;;
|
||||||
|
|
||||||
|
(define-syntax define-record-type*
|
||||||
|
(lambda (s)
|
||||||
|
"Define the given record type such that an additional \"syntactic
|
||||||
|
constructor\" is defined, which allows instances to be constructed with named
|
||||||
|
field initializers, à la SRFI-35, as well as default values."
|
||||||
|
(define (make-syntactic-constructor name ctor fields defaults)
|
||||||
|
"Make the syntactic constructor NAME that calls CTOR, and expects all
|
||||||
|
of FIELDS to be initialized. DEFAULTS is the list of FIELD/DEFAULT-VALUE
|
||||||
|
tuples."
|
||||||
|
(with-syntax ((name name)
|
||||||
|
(ctor ctor)
|
||||||
|
(expected fields)
|
||||||
|
(defaults defaults))
|
||||||
|
#'(define-syntax name
|
||||||
|
(lambda (s)
|
||||||
|
(syntax-case s expected
|
||||||
|
((_ (field value) (... ...))
|
||||||
|
(let ((fields (map syntax->datum #'(field (... ...))))
|
||||||
|
(inits (map (match-lambda
|
||||||
|
((f v)
|
||||||
|
(list (syntax->datum f) v)))
|
||||||
|
#'((field value) (... ...))))
|
||||||
|
(dflt (map (match-lambda
|
||||||
|
((f v)
|
||||||
|
(list (syntax->datum f) v)))
|
||||||
|
#'defaults)))
|
||||||
|
|
||||||
|
(define (field-value f)
|
||||||
|
(match (assoc f inits)
|
||||||
|
((_ v) v)
|
||||||
|
(#f (car (assoc-ref dflt f)))))
|
||||||
|
|
||||||
|
(if (lset= eq? (append fields (map car dflt))
|
||||||
|
'expected)
|
||||||
|
#`(ctor #,@(map field-value 'expected))
|
||||||
|
(error "missing or extraneous field initializers"
|
||||||
|
(lset-difference eq? fields 'expected))))))))))
|
||||||
|
|
||||||
|
(define (field-default-value s)
|
||||||
|
(syntax-case s (default)
|
||||||
|
((field (default val) _ ...)
|
||||||
|
(list #'field #'val))
|
||||||
|
((field _ options ...)
|
||||||
|
(field-default-value #'(field options ...)))
|
||||||
|
(_ #f)))
|
||||||
|
|
||||||
|
(syntax-case s ()
|
||||||
|
((_ type syntactic-ctor ctor pred
|
||||||
|
(field get options ...) ...)
|
||||||
|
#`(begin
|
||||||
|
(define-record-type type
|
||||||
|
(ctor field ...)
|
||||||
|
pred
|
||||||
|
(field get) ...)
|
||||||
|
#,(make-syntactic-constructor #'syntactic-ctor #'ctor
|
||||||
|
#'(field ...)
|
||||||
|
(filter-map field-default-value
|
||||||
|
#'((field options ...)
|
||||||
|
...))))))))
|
||||||
|
|
||||||
(define (memoize proc)
|
(define (memoize proc)
|
||||||
"Return a memoizing version of PROC."
|
"Return a memoizing version of PROC."
|
||||||
(let ((cache (make-hash-table)))
|
(let ((cache (make-hash-table)))
|
||||||
|
|
|
@ -26,7 +26,8 @@ (define-module (test-utils)
|
||||||
#:use-module (rnrs bytevectors)
|
#:use-module (rnrs bytevectors)
|
||||||
#:use-module (rnrs io ports)
|
#:use-module (rnrs io ports)
|
||||||
#:use-module (ice-9 rdelim)
|
#:use-module (ice-9 rdelim)
|
||||||
#:use-module (ice-9 popen))
|
#:use-module (ice-9 popen)
|
||||||
|
#:use-module (ice-9 match))
|
||||||
|
|
||||||
(test-begin "utils")
|
(test-begin "utils")
|
||||||
|
|
||||||
|
@ -98,6 +99,19 @@ (define-module (test-utils)
|
||||||
(equal? nix (gnu-triplet->nix-system gnu)))
|
(equal? nix (gnu-triplet->nix-system gnu)))
|
||||||
gnu nix))))
|
gnu nix))))
|
||||||
|
|
||||||
|
(test-assert "define-record-type*"
|
||||||
|
(begin
|
||||||
|
(define-record-type* <foo> foo make-foo
|
||||||
|
foo?
|
||||||
|
(bar foo-bar)
|
||||||
|
(baz foo-baz (default (+ 40 2))))
|
||||||
|
(and (match (foo (bar 1) (baz 2))
|
||||||
|
(($ <foo> 1 2) #t))
|
||||||
|
(match (foo (baz 2) (bar 1))
|
||||||
|
(($ <foo> 1 2) #t))
|
||||||
|
(match (foo (bar 1))
|
||||||
|
(($ <foo> 1 42) #t)))))
|
||||||
|
|
||||||
(test-end)
|
(test-end)
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue