me
/
guix
Archived
1
0
Fork 0

gexp: Preserve source location for #~ and #$ read extensions.

Read hash extensions preserve source location info as source properties
on their result.  However, in Guile 3.0.8, that location would be
dismissed, leading 'local-file' to fail to resolve file names relative
to the source directory.

Fixes <https://issues.guix.gnu.org/54003>.
Reported by Aleksandr Vityazev <avityazev@posteo.org>.

* guix/gexp.scm <eval-when> [read-syntax-redefined?, read-procedure]
[read-syntax*]: New variables.
[read-ungexp]: Adjust to expect either sexps or syntax objects.
[read-gexp]: Call 'read-procedure'.
* tests/gexp.scm ("local-file, relative file name, within gexp")
("local-file, relative file name, within gexp, compiled"): New tests.
Ludovic Courtès 2022-02-16 11:27:43 +01:00
parent 176354c2f8
commit ca155a20ae
No known key found for this signature in database
GPG Key ID: 090B11993D9AEBB5
2 changed files with 72 additions and 5 deletions

View File

@ -2176,6 +2176,29 @@ is true, the derivation will not print anything."
;;;
(eval-when (expand load eval)
(define-once read-syntax-redefined?
;; Have we already redefined 'read-syntax'? This needs to be done on
;; 3.0.8 only to work around <https://issues.guix.gnu.org/54003>.
(or (not (module-variable the-scm-module 'read-syntax))
(not (guile-version>? "3.0.7"))))
(define read-procedure
;; The current read procedure being called: either 'read' or
;; 'read-syntax'.
(make-parameter read))
(define read-syntax*
;; Replacement for 'read-syntax'.
(let ((read-syntax (and=> (module-variable the-scm-module 'read-syntax)
variable-ref)))
(lambda (port . rest)
(parameterize ((read-procedure read-syntax))
(apply read-syntax port rest)))))
(unless read-syntax-redefined?
(set! (@ (guile) read-syntax) read-syntax*)
(set! read-syntax-redefined? #t))
(define* (read-ungexp chr port #:optional native?)
"Read an 'ungexp' or 'ungexp-splicing' form from PORT. When NATIVE? is
true, use 'ungexp-native' and 'ungexp-native-splicing' instead."
@ -2191,22 +2214,39 @@ true, use 'ungexp-native' and 'ungexp-native-splicing' instead."
'ungexp-native
'ungexp))))
(match (read port)
((? symbol? symbol)
(let ((str (symbol->string symbol)))
(define symbolic?
;; Depending on whether (read-procedure) is 'read' or 'read-syntax', we
;; might get either sexps or syntax objects. Adjust accordingly.
(if (eq? (read-procedure) read)
symbol?
(compose symbol? syntax->datum)))
(define symbolic->string
(if (eq? (read-procedure) read)
symbol->string
(compose symbol->string syntax->datum)))
(define wrapped-symbol
(if (eq? (read-procedure) read)
(lambda (_ symbol) symbol)
datum->syntax))
(match ((read-procedure) port)
((? symbolic? symbol)
(let ((str (symbolic->string symbol)))
(match (string-index-right str #\:)
(#f
`(,unquote-symbol ,symbol))
(colon
(let ((name (string->symbol (substring str 0 colon)))
(output (substring str (+ colon 1))))
`(,unquote-symbol ,name ,output))))))
`(,unquote-symbol ,(wrapped-symbol symbol name) ,output))))))
(x
`(,unquote-symbol ,x))))
(define (read-gexp chr port)
"Read a 'gexp' form from PORT."
`(gexp ,(read port)))
`(gexp ,((read-procedure) port)))
;; Extend the reader
(read-hash-extend #\~ read-gexp)

View File

@ -28,6 +28,7 @@
#:use-module (guix tests)
#:use-module ((guix build utils) #:select (with-directory-excursion))
#:use-module ((guix utils) #:select (call-with-temporary-directory))
#:use-module ((guix ui) #:select (load*))
#:use-module (gnu packages)
#:use-module (gnu packages base)
#:use-module (gnu packages bootstrap)
@ -222,6 +223,32 @@
(let ((file (local-file (string-copy "../base32.scm"))))
(local-file-absolute-file-name file)))))
(test-assert "local-file, relative file name, within gexp"
(let* ((file (search-path %load-path "guix/base32.scm"))
(interned (add-to-store %store "base32.scm" #f "sha256" file)))
(equal? `(the file is ,interned)
(gexp->sexp*
#~(the file is #$(local-file "../guix/base32.scm"))))))
(test-assert "local-file, relative file name, within gexp, compiled"
;; In Guile 3.0.8, everything read by the #~ and #$ read hash extensions
;; would lack source location info, which in turn would lead
;; (current-source-directory), called by 'local-file', to return #f, thereby
;; breaking 'local-file' resolution. See
;; <https://issues.guix.gnu.org/54003>.
(let ((file (tmpnam)))
(call-with-output-file file
(lambda (port)
(display (string-append "#~(this file is #$(local-file \""
(basename file) "\" \"t.scm\"))")
port)))
(let* ((interned (add-to-store %store "t.scm" #f "sha256" file))
(module (make-fresh-user-module)))
(module-use! module (resolve-interface '(guix gexp)))
(equal? `(this file is ,interned)
(gexp->sexp* (load* file module))))))
(test-assertm "local-file, #:select?"
(mlet* %store-monad ((select? -> (lambda (file stat)
(member (basename file)