style: Allow special forms to be scoped.
* guix/scripts/style.scm (vhashq): Add clause for 'lst, and change default clause. (%special-forms): Add context for 'add-after and 'add-before. Add 'replace. (prefix?, special-form-lead): New procedures. (special-form?): Remove. (pretty-print-with-comments): Add 'context' to the threaded state. Adjust 'print-sequence' and adjust 'loop' calls accordingly. * tests/style.scm: Add tests for 'replace.master
parent
97d0055edb
commit
208a7aa17b
|
@ -114,14 +114,19 @@
|
||||||
;;;
|
;;;
|
||||||
|
|
||||||
(define-syntax vhashq
|
(define-syntax vhashq
|
||||||
(syntax-rules ()
|
(syntax-rules (quote)
|
||||||
((_) vlist-null)
|
((_) vlist-null)
|
||||||
|
((_ (key (quote (lst ...))) rest ...)
|
||||||
|
(vhash-consq key '(lst ...) (vhashq rest ...)))
|
||||||
((_ (key value) rest ...)
|
((_ (key value) rest ...)
|
||||||
(vhash-consq key value (vhashq rest ...)))))
|
(vhash-consq key '((() . value)) (vhashq rest ...)))))
|
||||||
|
|
||||||
(define %special-forms
|
(define %special-forms
|
||||||
;; Forms that are indented specially. The number is meant to be understood
|
;; Forms that are indented specially. The number is meant to be understood
|
||||||
;; like Emacs' 'scheme-indent-function' symbol property.
|
;; like Emacs' 'scheme-indent-function' symbol property. When given an
|
||||||
|
;; alist instead of a number, the alist gives "context" in which the symbol
|
||||||
|
;; is a special form; for instance, context (modify-phases) means that the
|
||||||
|
;; symbol must appear within a (modify-phases ...) expression.
|
||||||
(vhashq
|
(vhashq
|
||||||
('begin 1)
|
('begin 1)
|
||||||
('lambda 2)
|
('lambda 2)
|
||||||
|
@ -148,9 +153,9 @@
|
||||||
('operating-system 1)
|
('operating-system 1)
|
||||||
('modify-inputs 2)
|
('modify-inputs 2)
|
||||||
('modify-phases 2)
|
('modify-phases 2)
|
||||||
('add-after 3)
|
('add-after '(((modify-phases) . 3)))
|
||||||
('add-before 3)
|
('add-before '(((modify-phases) . 3)))
|
||||||
;; ('replace 2)
|
('replace '(((modify-phases) . 2))) ;different from 'modify-inputs'
|
||||||
('substitute* 2)
|
('substitute* 2)
|
||||||
('substitute-keyword-arguments 2)
|
('substitute-keyword-arguments 2)
|
||||||
('call-with-input-file 2)
|
('call-with-input-file 2)
|
||||||
|
@ -158,8 +163,30 @@
|
||||||
('with-output-to-file 2)
|
('with-output-to-file 2)
|
||||||
('with-input-from-file 2)))
|
('with-input-from-file 2)))
|
||||||
|
|
||||||
(define (special-form? symbol)
|
(define (prefix? candidate lst)
|
||||||
(vhash-assq symbol %special-forms))
|
"Return true if CANDIDATE is a prefix of LST."
|
||||||
|
(let loop ((candidate candidate)
|
||||||
|
(lst lst))
|
||||||
|
(match candidate
|
||||||
|
(() #t)
|
||||||
|
((head1 . rest1)
|
||||||
|
(match lst
|
||||||
|
(() #f)
|
||||||
|
((head2 . rest2)
|
||||||
|
(and (equal? head1 head2)
|
||||||
|
(loop rest1 rest2))))))))
|
||||||
|
|
||||||
|
(define (special-form-lead symbol context)
|
||||||
|
"If SYMBOL is a special form in the given CONTEXT, return its number of
|
||||||
|
arguments; otherwise return #f. CONTEXT is a stack of symbols lexically
|
||||||
|
surrounding SYMBOL."
|
||||||
|
(match (vhash-assq symbol %special-forms)
|
||||||
|
(#f #f)
|
||||||
|
((_ . alist)
|
||||||
|
(any (match-lambda
|
||||||
|
((prefix . level)
|
||||||
|
(and (prefix? prefix context) (- level 1))))
|
||||||
|
alist))))
|
||||||
|
|
||||||
(define (escaped-string str)
|
(define (escaped-string str)
|
||||||
"Return STR with backslashes and double quotes escaped. Everything else, in
|
"Return STR with backslashes and double quotes escaped. Everything else, in
|
||||||
|
@ -192,8 +219,9 @@ Lists longer than LONG-LIST are written as one element per line."
|
||||||
(let loop ((indent indent)
|
(let loop ((indent indent)
|
||||||
(column indent)
|
(column indent)
|
||||||
(delimited? #t) ;true if comes after a delimiter
|
(delimited? #t) ;true if comes after a delimiter
|
||||||
|
(context '()) ;list of "parent" symbols
|
||||||
(obj obj))
|
(obj obj))
|
||||||
(define (print-sequence indent column lst delimited?)
|
(define (print-sequence context indent column lst delimited?)
|
||||||
(define long?
|
(define long?
|
||||||
(> (length lst) long-list))
|
(> (length lst) long-list))
|
||||||
|
|
||||||
|
@ -223,6 +251,7 @@ Lists longer than LONG-LIST are written as one element per line."
|
||||||
(comment? item)
|
(comment? item)
|
||||||
(loop indent column
|
(loop indent column
|
||||||
(or newline? delimited?)
|
(or newline? delimited?)
|
||||||
|
context
|
||||||
item)))))))
|
item)))))))
|
||||||
|
|
||||||
(define (sequence-would-protrude? indent lst)
|
(define (sequence-would-protrude? indent lst)
|
||||||
|
@ -243,6 +272,9 @@ Lists longer than LONG-LIST are written as one element per line."
|
||||||
#f))
|
#f))
|
||||||
lst))
|
lst))
|
||||||
|
|
||||||
|
(define (special-form? head)
|
||||||
|
(special-form-lead head context))
|
||||||
|
|
||||||
(match obj
|
(match obj
|
||||||
((? comment? comment)
|
((? comment? comment)
|
||||||
(if (comment-margin? comment)
|
(if (comment-margin? comment)
|
||||||
|
@ -261,45 +293,46 @@ Lists longer than LONG-LIST are written as one element per line."
|
||||||
(('quote lst)
|
(('quote lst)
|
||||||
(unless delimited? (display " " port))
|
(unless delimited? (display " " port))
|
||||||
(display "'" port)
|
(display "'" port)
|
||||||
(loop indent (+ column (if delimited? 1 2)) #t lst))
|
(loop indent (+ column (if delimited? 1 2)) #t context lst))
|
||||||
(('quasiquote lst)
|
(('quasiquote lst)
|
||||||
(unless delimited? (display " " port))
|
(unless delimited? (display " " port))
|
||||||
(display "`" port)
|
(display "`" port)
|
||||||
(loop indent (+ column (if delimited? 1 2)) #t lst))
|
(loop indent (+ column (if delimited? 1 2)) #t context lst))
|
||||||
(('unquote lst)
|
(('unquote lst)
|
||||||
(unless delimited? (display " " port))
|
(unless delimited? (display " " port))
|
||||||
(display "," port)
|
(display "," port)
|
||||||
(loop indent (+ column (if delimited? 1 2)) #t lst))
|
(loop indent (+ column (if delimited? 1 2)) #t context lst))
|
||||||
(('unquote-splicing lst)
|
(('unquote-splicing lst)
|
||||||
(unless delimited? (display " " port))
|
(unless delimited? (display " " port))
|
||||||
(display ",@" port)
|
(display ",@" port)
|
||||||
(loop indent (+ column (if delimited? 2 3)) #t lst))
|
(loop indent (+ column (if delimited? 2 3)) #t context lst))
|
||||||
(('gexp lst)
|
(('gexp lst)
|
||||||
(unless delimited? (display " " port))
|
(unless delimited? (display " " port))
|
||||||
(display "#~" port)
|
(display "#~" port)
|
||||||
(loop indent (+ column (if delimited? 2 3)) #t lst))
|
(loop indent (+ column (if delimited? 2 3)) #t context lst))
|
||||||
(('ungexp obj)
|
(('ungexp obj)
|
||||||
(unless delimited? (display " " port))
|
(unless delimited? (display " " port))
|
||||||
(display "#$" port)
|
(display "#$" port)
|
||||||
(loop indent (+ column (if delimited? 2 3)) #t obj))
|
(loop indent (+ column (if delimited? 2 3)) #t context obj))
|
||||||
(('ungexp-native obj)
|
(('ungexp-native obj)
|
||||||
(unless delimited? (display " " port))
|
(unless delimited? (display " " port))
|
||||||
(display "#+" port)
|
(display "#+" port)
|
||||||
(loop indent (+ column (if delimited? 2 3)) #t obj))
|
(loop indent (+ column (if delimited? 2 3)) #t context obj))
|
||||||
(('ungexp-splicing lst)
|
(('ungexp-splicing lst)
|
||||||
(unless delimited? (display " " port))
|
(unless delimited? (display " " port))
|
||||||
(display "#$@" port)
|
(display "#$@" port)
|
||||||
(loop indent (+ column (if delimited? 3 4)) #t lst))
|
(loop indent (+ column (if delimited? 3 4)) #t context lst))
|
||||||
(('ungexp-native-splicing lst)
|
(('ungexp-native-splicing lst)
|
||||||
(unless delimited? (display " " port))
|
(unless delimited? (display " " port))
|
||||||
(display "#+@" port)
|
(display "#+@" port)
|
||||||
(loop indent (+ column (if delimited? 3 4)) #t lst))
|
(loop indent (+ column (if delimited? 3 4)) #t context lst))
|
||||||
(((? special-form? head) arguments ...)
|
(((? special-form? head) arguments ...)
|
||||||
;; Special-case 'let', 'lambda', 'modify-inputs', etc. so the second
|
;; Special-case 'let', 'lambda', 'modify-inputs', etc. so the second
|
||||||
;; and following arguments are less indented.
|
;; and following arguments are less indented.
|
||||||
(let* ((lead (- (cdr (vhash-assq head %special-forms)) 1))
|
(let* ((lead (special-form-lead head context))
|
||||||
(head (symbol->string head))
|
(context (cons head context))
|
||||||
(total (length arguments)))
|
(head (symbol->string head))
|
||||||
|
(total (length arguments)))
|
||||||
(unless delimited? (display " " port))
|
(unless delimited? (display " " port))
|
||||||
(display "(" port)
|
(display "(" port)
|
||||||
(display head port)
|
(display head port)
|
||||||
|
@ -327,14 +360,14 @@ Lists longer than LONG-LIST are written as one element per line."
|
||||||
(() column)
|
(() column)
|
||||||
((head . tail)
|
((head . tail)
|
||||||
(inner (- n 1) tail
|
(inner (- n 1) tail
|
||||||
(loop initial-indent
|
(loop initial-indent column
|
||||||
column
|
|
||||||
(= n lead)
|
(= n lead)
|
||||||
|
context
|
||||||
head)))))))
|
head)))))))
|
||||||
|
|
||||||
;; Print the remaining arguments.
|
;; Print the remaining arguments.
|
||||||
(let ((column (print-sequence
|
(let ((column (print-sequence
|
||||||
indent new-column
|
context indent new-column
|
||||||
(drop arguments (min lead total))
|
(drop arguments (min lead total))
|
||||||
#t)))
|
#t)))
|
||||||
(display ")" port)
|
(display ")" port)
|
||||||
|
@ -343,14 +376,15 @@ Lists longer than LONG-LIST are written as one element per line."
|
||||||
(let* ((overflow? (>= column max-width))
|
(let* ((overflow? (>= column max-width))
|
||||||
(column (if overflow?
|
(column (if overflow?
|
||||||
(+ indent 1)
|
(+ indent 1)
|
||||||
(+ column (if delimited? 1 2)))))
|
(+ column (if delimited? 1 2))))
|
||||||
|
(context (cons head context)))
|
||||||
(if overflow?
|
(if overflow?
|
||||||
(begin
|
(begin
|
||||||
(newline port)
|
(newline port)
|
||||||
(display (make-string indent #\space) port))
|
(display (make-string indent #\space) port))
|
||||||
(unless delimited? (display " " port)))
|
(unless delimited? (display " " port)))
|
||||||
(display "(" port)
|
(display "(" port)
|
||||||
(let* ((new-column (loop column column #t head))
|
(let* ((new-column (loop column column #t context head))
|
||||||
(indent (if (or (>= new-column max-width)
|
(indent (if (or (>= new-column max-width)
|
||||||
(not (symbol? head))
|
(not (symbol? head))
|
||||||
(sequence-would-protrude?
|
(sequence-would-protrude?
|
||||||
|
@ -358,7 +392,7 @@ Lists longer than LONG-LIST are written as one element per line."
|
||||||
column
|
column
|
||||||
(+ new-column 1))))
|
(+ new-column 1))))
|
||||||
(define column
|
(define column
|
||||||
(print-sequence indent new-column tail #f))
|
(print-sequence context indent new-column tail #f))
|
||||||
(display ")" port)
|
(display ")" port)
|
||||||
(+ column 1))))
|
(+ column 1))))
|
||||||
(_
|
(_
|
||||||
|
|
|
@ -453,6 +453,18 @@ mnopqrstuvwxyz.\")"
|
||||||
\"abcdefghijklmnopqrstuvwxyz\")"
|
\"abcdefghijklmnopqrstuvwxyz\")"
|
||||||
#:max-width 33)
|
#:max-width 33)
|
||||||
|
|
||||||
|
(test-pretty-print "\
|
||||||
|
(modify-phases %standard-phases
|
||||||
|
(replace 'build
|
||||||
|
;; Nicely indented in 'modify-phases' context.
|
||||||
|
(lambda _
|
||||||
|
#t)))")
|
||||||
|
|
||||||
|
(test-pretty-print "\
|
||||||
|
(modify-inputs inputs
|
||||||
|
;; Regular indentation for 'replace' here.
|
||||||
|
(replace \"gmp\" gmp))")
|
||||||
|
|
||||||
(test-end)
|
(test-end)
|
||||||
|
|
||||||
;; Local Variables:
|
;; Local Variables:
|
||||||
|
|
Reference in New Issue