forked from guix-mirror/guix
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
records: 'match-record' checks fields at macro-expansion time.
This allows 'match-record' to be more efficient (field offsets are computed at compilation time) and to report unknown fields at macro-expansion time. * guix/records.scm (map-fields): New macro. (define-record-type*)[rtd-identifier]: New procedure. Define TYPE as a macro and use a separate identifier for the RTD. (lookup-field, match-record-inner): New macros. (match-record): Rewrite in terms of 'match-error-inner'. * tests/records.scm ("match-record, simple") ("match-record, unknown field"): New tests. * gnu/services/cuirass.scm (cuirass-shepherd-service): Rename 'log-file' local variable to 'main-log-file'. * gnu/services/getmail.scm (serialize-getmail-configuration-file): Move after <getmail-configuration-file> definition.
- Loading branch information
Showing
4 changed files
with
122 additions
and
24 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,5 @@ | ||
;;; GNU Guix --- Functional package management for GNU | ||
;;; Copyright © 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, 2020, 2021 Ludovic Courtès <[email protected]> | ||
;;; Copyright © 2012-2022 Ludovic Courtès <[email protected]> | ||
;;; Copyright © 2018 Mark H Weaver <[email protected]> | ||
;;; | ||
;;; This file is part of GNU Guix. | ||
|
@@ -104,6 +104,10 @@ error-reporting purposes." | |
(() | ||
#t))))))) | ||
|
||
(define-syntax map-fields | ||
(lambda (x) | ||
(syntax-violation 'map-fields "bad use of syntactic keyword" x x))) | ||
|
||
(define-syntax-parameter this-record | ||
(lambda (s) | ||
"Return the record being defined. This macro may only be used in the | ||
|
@@ -325,6 +329,15 @@ This expression returns a new object equal to 'x' except for its 'name' | |
field and its 'loc' field---the latter is marked as \"innate\", so it is not | ||
inherited." | ||
|
||
(define (rtd-identifier type) | ||
;; Return an identifier derived from TYPE to name its record type | ||
;; descriptor (RTD). | ||
(let ((type-name (syntax->datum type))) | ||
(datum->syntax | ||
type | ||
(string->symbol | ||
(string-append "% " (symbol->string type-name) " rtd"))))) | ||
|
||
(define (field-default-value s) | ||
(syntax-case s (default) | ||
((field (default val) _ ...) | ||
|
@@ -428,10 +441,31 @@ inherited." | |
field))) | ||
field-spec))) | ||
#`(begin | ||
(define-record-type type | ||
(define-record-type #,(rtd-identifier #'type) | ||
(ctor field ...) | ||
pred | ||
field-spec* ...) | ||
|
||
;; Rectify the vtable type name... | ||
(set-struct-vtable-name! #,(rtd-identifier #'type) 'type) | ||
(cond-expand | ||
(guile-3 | ||
;; ... and the record type name. | ||
(struct-set! #,(rtd-identifier #'type) vtable-offset-user | ||
'type)) | ||
(else #f)) | ||
|
||
(define-syntax type | ||
(lambda (s) | ||
"This macro lets us query record type info at | ||
macro-expansion time." | ||
(syntax-case s (map-fields) | ||
((_ map-fields macro) | ||
#'(macro (field ...))) | ||
(id | ||
(identifier? #'id) | ||
#'#,(rtd-identifier #'type))))) | ||
|
||
(define #,(current-abi-identifier #'type) | ||
#,cookie) | ||
|
||
|
@@ -535,19 +569,50 @@ pairs. Stop upon an empty line (after consuming it) or EOF." | |
(else | ||
(error "unmatched line" line)))))))) | ||
|
||
|
||
;;; | ||
;;; Pattern matching. | ||
;;; | ||
|
||
(define-syntax lookup-field | ||
(lambda (s) | ||
"Look up FIELD in the given list and return an expression that represents | ||
its offset in the record. Raise a syntax violation when the field is not | ||
found." | ||
(syntax-case s () | ||
((_ field offset ()) | ||
(syntax-violation 'lookup-field "unknown record type field" | ||
s #'field)) | ||
((_ field offset (head tail ...)) | ||
(free-identifier=? #'field #'head) | ||
#'offset) | ||
((_ field offset (_ tail ...)) | ||
#'(lookup-field field (+ 1 offset) (tail ...)))))) | ||
|
||
(define-syntax match-record-inner | ||
(lambda (s) | ||
(syntax-case s () | ||
((_ record type (field rest ...) body ...) | ||
#`(let-syntax ((field-offset (syntax-rules () | ||
((_ f) | ||
(lookup-field field 0 f))))) | ||
(let* ((offset (type map-fields field-offset)) | ||
(field (struct-ref record offset))) | ||
(match-record-inner record type (rest ...) body ...)))) | ||
((_ record type () body ...) | ||
#'(begin body ...))))) | ||
|
||
(define-syntax match-record | ||
(syntax-rules () | ||
"Bind each FIELD of a RECORD of the given TYPE to it's FIELD name. | ||
The order in which fields appear does not matter. A syntax error is raised if | ||
an unknown field is queried. | ||
The current implementation does not support thunked and delayed fields." | ||
((_ record type (field fields ...) body ...) | ||
;; TODO support thunked and delayed fields | ||
((_ record type (fields ...) body ...) | ||
(if (eq? (struct-vtable record) type) | ||
;; TODO compute indices and report wrong-field-name errors at | ||
;; expansion time | ||
;; TODO support thunked and delayed fields | ||
(let ((field ((record-accessor type 'field) record))) | ||
(match-record record type (fields ...) body ...)) | ||
(throw 'wrong-type-arg record))) | ||
((_ record type () body ...) | ||
(begin body ...)))) | ||
(match-record-inner record type (fields ...) body ...) | ||
(throw 'wrong-type-arg record))))) | ||
|
||
;;; records.scm ends here |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters