(address . bug-guix@gnu.org)
G-expressions currently do not consistently preserve the distinction
between #nil and '(), which causes trouble for programs that rely on
that distinction. In particular, the issue affects programs that use
(guix build json), because that library uses #nil to represent the JSON
value `null', whereas it uses '() to represent an empty JSON array.
The following program exposes the error:
Toggle snippet (67 lines)
(use-modules (guix build json)
(guix gexp)
(guix monads)
(guix store)
(guix derivations)
(rnrs conditions)
(ice-9 textual-ports))
(define (check-equal? actual expected message)
(define who 'check-equal?)
(unless (equal? actual expected)
(raise-exception
(condition
(make-assertion-violation)
(make-who-condition 'check-equal?)
(make-irritants-condition (list actual))
(make-message-condition
(format #f "~a: ~a\n ~a: ~s\n ~a: ~s\n ~a: ~s"
who "test failed"
"message" message
"expected" expected
"actual" actual))))))
(define (sexp->json-string sx)
(call-with-output-string
(lambda (out)
(write-json sx out))))
(define (gexp->json-string gx)
(run-with-store (open-connection)
(mlet* %store-monad ((drv (gexp->derivation "example.json"
(with-imported-modules `((guix build json))
#~(begin
(use-modules (guix build json))
(call-with-output-file #$output
(lambda (out)
(write-json #$gx out)))))))
(_built (built-derivations (list drv))))
(return (call-with-input-file (derivation->output-path drv)
get-string-all)))))
(check-equal? (sexp->json-string '())
"[]"
"sexp: empty array")
(check-equal? (gexp->json-string #~'())
"[]"
"gexp: empty array")
(check-equal? (sexp->json-string #nil)
"null"
"sexp: null")
(check-equal? (gexp->json-string #~#nil)
"null"
"gexp: null")
(check-equal? (sexp->json-string '(@ ("k" . #nil)))
"{\"k\":null}"
"sexp: null in object")
;; This one fails!
(check-equal? (gexp->json-string #~'(@ ("k" . #nil)))
"{\"k\":null}"
"gexp: null in object")
-Philip