packages: Add 'package-definition-location'.
Suggested by Maxime Devos <maximedevos@telenet.be>.
* guix/packages.scm (current-definition-location): New syntax parameter.
(define-public*): New macro.
(<package>)[definition-location]: New field.
(package-definition-location): New procedure.
* tests/packages.scm ("package-definition-location"): New test.
			
			
This commit is contained in:
		
							parent
							
								
									10c981b135
								
							
						
					
					
						commit
						8531997d2a
					
				
					 2 changed files with 58 additions and 1 deletions
				
			
		| 
						 | 
					@ -52,6 +52,7 @@
 | 
				
			||||||
  #:re-export (%current-system
 | 
					  #:re-export (%current-system
 | 
				
			||||||
               %current-target-system
 | 
					               %current-target-system
 | 
				
			||||||
               search-path-specification)         ;for convenience
 | 
					               search-path-specification)         ;for convenience
 | 
				
			||||||
 | 
					  #:replace ((define-public* . define-public))
 | 
				
			||||||
  #:export (content-hash
 | 
					  #:export (content-hash
 | 
				
			||||||
            content-hash?
 | 
					            content-hash?
 | 
				
			||||||
            content-hash-algorithm
 | 
					            content-hash-algorithm
 | 
				
			||||||
| 
						 | 
					@ -99,6 +100,7 @@
 | 
				
			||||||
            package-supported-systems
 | 
					            package-supported-systems
 | 
				
			||||||
            package-properties
 | 
					            package-properties
 | 
				
			||||||
            package-location
 | 
					            package-location
 | 
				
			||||||
 | 
					            package-definition-location
 | 
				
			||||||
            hidden-package
 | 
					            hidden-package
 | 
				
			||||||
            hidden-package?
 | 
					            hidden-package?
 | 
				
			||||||
            package-superseded
 | 
					            package-superseded
 | 
				
			||||||
| 
						 | 
					@ -385,6 +387,35 @@ one-indexed line numbers."
 | 
				
			||||||
                      (location-line loc)
 | 
					                      (location-line loc)
 | 
				
			||||||
                      (location-column loc)))))
 | 
					                      (location-column loc)))))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					(define-syntax-parameter current-definition-location
 | 
				
			||||||
 | 
					  ;; Location of the encompassing 'define-public'.
 | 
				
			||||||
 | 
					  (const #f))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					(define-syntax define-public*
 | 
				
			||||||
 | 
					  (lambda (s)
 | 
				
			||||||
 | 
					    "Like 'define-public' but set 'current-definition-location' for the
 | 
				
			||||||
 | 
					lexical scope of its body."
 | 
				
			||||||
 | 
					    (define location
 | 
				
			||||||
 | 
					      (match (syntax-source s)
 | 
				
			||||||
 | 
					        (#f #f)
 | 
				
			||||||
 | 
					        (properties
 | 
				
			||||||
 | 
					         (let ((line   (assq-ref properties 'line))
 | 
				
			||||||
 | 
					               (column (assq-ref properties 'column)))
 | 
				
			||||||
 | 
					           ;; Don't repeat the file name since it's redundant with 'location'.
 | 
				
			||||||
 | 
					           ;; Encode the whole thing so that it fits in a fixnum on 32-bit
 | 
				
			||||||
 | 
					           ;; platforms, which leaves us 29 bits: 7 bits for COLUMN (which is
 | 
				
			||||||
 | 
					           ;; almost always zero), and 22 bits for LINE.
 | 
				
			||||||
 | 
					           (and line column
 | 
				
			||||||
 | 
					                (logior (ash (logand #x7f column) 22)
 | 
				
			||||||
 | 
					                        (logand (- (expt 2 22) 1) (+ 1 line))))))))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    (syntax-case s ()
 | 
				
			||||||
 | 
					      ((_ prototype body ...)
 | 
				
			||||||
 | 
					       #`(define-public prototype
 | 
				
			||||||
 | 
					           (syntax-parameterize ((current-definition-location
 | 
				
			||||||
 | 
					                                  (lambda (s) #,location)))
 | 
				
			||||||
 | 
					             body ...))))))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
;; A package.
 | 
					;; A package.
 | 
				
			||||||
(define-record-type* <package>
 | 
					(define-record-type* <package>
 | 
				
			||||||
  package make-package
 | 
					  package make-package
 | 
				
			||||||
| 
						 | 
					@ -430,7 +461,10 @@ one-indexed line numbers."
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  (location package-location-vector
 | 
					  (location package-location-vector
 | 
				
			||||||
            (default (current-location-vector))
 | 
					            (default (current-location-vector))
 | 
				
			||||||
            (innate) (sanitize sanitize-location)))
 | 
					            (innate) (sanitize sanitize-location))
 | 
				
			||||||
 | 
					  (definition-location package-definition-location-code
 | 
				
			||||||
 | 
					                       (default (current-definition-location))
 | 
				
			||||||
 | 
					                       (innate)))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
(set-record-type-printer! <package>
 | 
					(set-record-type-printer! <package>
 | 
				
			||||||
                          (lambda (package port)
 | 
					                          (lambda (package port)
 | 
				
			||||||
| 
						 | 
					@ -455,6 +489,18 @@ it is not known."
 | 
				
			||||||
    (#f #f)
 | 
					    (#f #f)
 | 
				
			||||||
    (#(file line column) (location file line column))))
 | 
					    (#(file line column) (location file line column))))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					(define (package-definition-location package)
 | 
				
			||||||
 | 
					  "Like 'package-location', but return the location of the definition
 | 
				
			||||||
 | 
					itself--i.e., that of the enclosing 'define-public' form, if any, or #f."
 | 
				
			||||||
 | 
					  (match (package-definition-location-code package)
 | 
				
			||||||
 | 
					    (#f #f)
 | 
				
			||||||
 | 
					    (code
 | 
				
			||||||
 | 
					     (let ((column (bit-extract code 22 29))
 | 
				
			||||||
 | 
					           (line   (bit-extract code 0 21)))
 | 
				
			||||||
 | 
					      (match (package-location-vector package)
 | 
				
			||||||
 | 
					        (#f #f)
 | 
				
			||||||
 | 
					        (#(file _ _) (location file line column)))))))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
(define-syntax-rule (package/inherit p overrides ...)
 | 
					(define-syntax-rule (package/inherit p overrides ...)
 | 
				
			||||||
  "Like (package (inherit P) OVERRIDES ...), except that the same
 | 
					  "Like (package (inherit P) OVERRIDES ...), except that the same
 | 
				
			||||||
transformation is done to the package P's replacement, if any.  P must be a bare
 | 
					transformation is done to the package P's replacement, if any.  P must be a bare
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -236,6 +236,17 @@
 | 
				
			||||||
                (eq? item new)))
 | 
					                (eq? item new)))
 | 
				
			||||||
             (null? (manifest-transaction-remove tx)))))))
 | 
					             (null? (manifest-transaction-remove tx)))))))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					(test-assert "package-definition-location"
 | 
				
			||||||
 | 
					  (let ((location   (package-location hello))
 | 
				
			||||||
 | 
					        (definition (package-definition-location hello)))
 | 
				
			||||||
 | 
					    ;; Check for the usual layout of (define-public hello (package ...)).
 | 
				
			||||||
 | 
					    (and (string=? (location-file location)
 | 
				
			||||||
 | 
					                   (location-file definition))
 | 
				
			||||||
 | 
					         (= 0 (location-column definition))
 | 
				
			||||||
 | 
					         (= 2 (location-column location))
 | 
				
			||||||
 | 
					         (= (location-line definition)
 | 
				
			||||||
 | 
					            (- (location-line location) 1)))))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
(test-assert "package-field-location"
 | 
					(test-assert "package-field-location"
 | 
				
			||||||
  (let ()
 | 
					  (let ()
 | 
				
			||||||
    (define (goto port line column)
 | 
					    (define (goto port line column)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Reference in a new issue