diff options
| author | Ludovic Courtès <ludo@gnu.org> | 2016-07-14 18:58:36 +0200 |
|---|---|---|
| committer | Ludovic Courtès <ludo@gnu.org> | 2016-07-14 19:07:07 +0200 |
| commit | babc2c80a7e1f1b5e72fd1685ef6604b93157a8e (patch) | |
| tree | 5a6988c157c2efafe0da57d04b37e3f99db77dd0 | |
| parent | db8f6b34121b392df12b551b3f7ca16349dc7018 (diff) | |
records: Improve reporting of invalid field specifiers.
Fixes <http://bugs.gnu.org/23969>.
Reported by Vincent Legoll <vincent.legoll@gmail.com>.
* guix/records.scm (report-invalid-field-specifier): New procedure.
* tests/records.scm ("define-record-type* & wrong field specifier"): New
test.
| -rw-r--r-- | guix/records.scm | 19 | ||||
| -rw-r--r-- | tests/records.scm | 29 |
2 files changed, 45 insertions, 3 deletions
diff --git a/guix/records.scm b/guix/records.scm index 0d35a747b00..f3f3aafb045 100644 --- a/guix/records.scm +++ b/guix/records.scm | |||
| @@ -1,5 +1,5 @@ | |||
| 1 | ;;; GNU Guix --- Functional package management for GNU | 1 | ;;; GNU Guix --- Functional package management for GNU |
| 2 | ;;; Copyright © 2012, 2013, 2014, 2015 Ludovic Courtès <ludo@gnu.org> | 2 | ;;; Copyright © 2012, 2013, 2014, 2015, 2016 Ludovic Courtès <ludo@gnu.org> |
| 3 | ;;; | 3 | ;;; |
| 4 | ;;; This file is part of GNU Guix. | 4 | ;;; This file is part of GNU Guix. |
| 5 | ;;; | 5 | ;;; |
| @@ -42,6 +42,15 @@ | |||
| 42 | (format #f fmt args ...) | 42 | (format #f fmt args ...) |
| 43 | form)))) | 43 | form)))) |
| 44 | 44 | ||
| 45 | (define (report-invalid-field-specifier name bindings) | ||
| 46 | "Report the first invalid binding among BINDINGS." | ||
| 47 | (let loop ((bindings bindings)) | ||
| 48 | (syntax-case bindings () | ||
| 49 | (((field value) rest ...) ;good | ||
| 50 | (loop #'(rest ...))) | ||
| 51 | ((weird _ ...) ;weird! | ||
| 52 | (syntax-violation name "invalid field specifier" #'weird))))) | ||
| 53 | |||
| 45 | (define-syntax make-syntactic-constructor | 54 | (define-syntax make-syntactic-constructor |
| 46 | (syntax-rules () | 55 | (syntax-rules () |
| 47 | "Make the syntactic constructor NAME for TYPE, that calls CTOR, and | 56 | "Make the syntactic constructor NAME for TYPE, that calls CTOR, and |
| @@ -147,7 +156,13 @@ fields, and DELAYED is the list of identifiers of delayed fields." | |||
| 147 | "missing field initializers ~a" | 156 | "missing field initializers ~a" |
| 148 | (lset-difference eq? | 157 | (lset-difference eq? |
| 149 | '(expected ...) | 158 | '(expected ...) |
| 150 | fields))))))))))))) | 159 | fields))))))) |
| 160 | ((_ bindings (... ...)) | ||
| 161 | ;; One of BINDINGS doesn't match the (field value) pattern. | ||
| 162 | ;; Report precisely which one is faulty, instead of letting the | ||
| 163 | ;; "source expression failed to match any pattern" error. | ||
| 164 | (report-invalid-field-specifier 'name | ||
| 165 | #'(bindings (... ...)))))))))) | ||
| 151 | 166 | ||
| 152 | (define-syntax-rule (define-field-property-predicate predicate property) | 167 | (define-syntax-rule (define-field-property-predicate predicate property) |
| 153 | "Define PREDICATE as a procedure that takes a syntax object and, when passed | 168 | "Define PREDICATE as a procedure that takes a syntax object and, when passed |
diff --git a/tests/records.scm b/tests/records.scm index c6f85d4a81d..d6d27bb96a6 100644 --- a/tests/records.scm +++ b/tests/records.scm | |||
| @@ -1,5 +1,5 @@ | |||
| 1 | ;;; GNU Guix --- Functional package management for GNU | 1 | ;;; GNU Guix --- Functional package management for GNU |
| 2 | ;;; Copyright © 2012, 2013, 2014, 2015 Ludovic Courtès <ludo@gnu.org> | 2 | ;;; Copyright © 2012, 2013, 2014, 2015, 2016 Ludovic Courtès <ludo@gnu.org> |
| 3 | ;;; | 3 | ;;; |
| 4 | ;;; This file is part of GNU Guix. | 4 | ;;; This file is part of GNU Guix. |
| 5 | ;;; | 5 | ;;; |
| @@ -17,6 +17,7 @@ | |||
| 17 | ;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>. | 17 | ;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>. |
| 18 | 18 | ||
| 19 | (define-module (test-records) | 19 | (define-module (test-records) |
| 20 | #:use-module (srfi srfi-1) | ||
| 20 | #:use-module (srfi srfi-64) | 21 | #:use-module (srfi srfi-64) |
| 21 | #:use-module (ice-9 match) | 22 | #:use-module (ice-9 match) |
| 22 | #:use-module (ice-9 regex) | 23 | #:use-module (ice-9 regex) |
| @@ -214,6 +215,32 @@ | |||
| 214 | (equal? (foo-bar y) 1)) ;promise was already forced | 215 | (equal? (foo-bar y) 1)) ;promise was already forced |
| 215 | (eq? (foo-baz y) 'b))))) | 216 | (eq? (foo-baz y) 'b))))) |
| 216 | 217 | ||
| 218 | (test-assert "define-record-type* & wrong field specifier" | ||
| 219 | (let ((exp '(begin | ||
| 220 | (define-record-type* <foo> foo make-foo | ||
| 221 | foo? | ||
| 222 | (bar foo-bar (default 42)) | ||
| 223 | (baz foo-baz)) | ||
| 224 | |||
| 225 | (foo (baz 1 2 3 4 5)))) ;syntax error | ||
| 226 | (loc (current-source-location))) ;keep this alignment! | ||
| 227 | (catch 'syntax-error | ||
| 228 | (lambda () | ||
| 229 | (eval exp (test-module)) | ||
| 230 | #f) | ||
| 231 | (lambda (key proc message location form . args) | ||
| 232 | (and (eq? proc 'foo) | ||
| 233 | (string-match "invalid field" message) | ||
| 234 | (equal? form '(baz 1 2 3 4 5)) | ||
| 235 | |||
| 236 | ;; Make sure the location is that of the field specifier. | ||
| 237 | ;; See <http://bugs.gnu.org/23969>. | ||
| 238 | (lset= equal? | ||
| 239 | (pk 'expected-loc | ||
| 240 | `((line . ,(- (assq-ref loc 'line) 1)) | ||
| 241 | ,@(alist-delete 'line loc))) | ||
| 242 | (pk 'actual-loc location))))))) | ||
| 243 | |||
| 217 | (test-assert "define-record-type* & missing initializers" | 244 | (test-assert "define-record-type* & missing initializers" |
| 218 | (catch 'syntax-error | 245 | (catch 'syntax-error |
| 219 | (lambda () | 246 | (lambda () |
