Support ${ # ## % %% }.

This commit is contained in:
Jan Nieuwenhuizen 2018-11-05 22:37:55 +01:00
parent 1e51c5cbd1
commit 8ca428c7f2
13 changed files with 95 additions and 11 deletions

View File

@ -69,6 +69,12 @@ tests="
60-function
60-subst
70-hash.sh
70-hash-hash.sh
70-percent.sh
70-percent-percent.sh
70-percent-space.sh
100-sed
100-sed-once
100-sed-global

View File

@ -225,9 +225,13 @@
dollar < '$'
literal <-- backslash? (!ws !amp !tick !dollar !pipe !semi !par !nl !sp !rbrace !io-op !dq !sq .)+
variable <-- dollar ('$' / '#' / '*' / '?' / '@' / [0-9] / identifier / lbrace identifier rbrace)
variable-and-or <- dollar lbrace (variable-or / variable-and ) rbrace
variable-and-or <- dollar lbrace (variable-or / variable-and / variable-hash-hash / variable-hash / variable-percent-percent / variable-percent ) rbrace
variable-and <-- identifier plus rhs
variable-or <-- identifier minus rhs
variable-hash <-- identifier hash rhs
variable-hash-hash <-- identifier hash hash rhs
variable-percent <-- identifier percent rhs
variable-percent-percent <-- identifier percent percent rhs
delim <- singlequotes / doublequotes / substitution
sq < [']
dq < [\"]
@ -248,6 +252,8 @@
rbrace < [}]
plus < [+]
minus < '-'
hash < '#'
percent < '%'
par < lpar / rpar
nl < '\n'
sp < '\t' / ' ' / (escaped-nl sp*)
@ -351,19 +357,20 @@
(('brace-group o) `(brace-group ,(transform o)))
(('file-name o) `(file-name ,(transform o)))
(_ ast)))
(define (remove-shell-comments s)
(define (remove-line-comments s)
(string-join (map
(lambda (s)
(let* ((n (string-index s #\#)))
(if n (string-pad-right s (string-length s) #\space 0 n)
(let ((n (string-index s #\#)))
(if (and n (zero? n)) (string-pad-right s (string-length s) #\space 0 n)
s)))
(string-split s #\newline)) "\n"))
(define (parse-string string)
(let* ((pt ((compose parse- remove-shell-comments) string))
(let* ((pt ((compose parse- remove-line-comments) string))
(foo (when (> %debug-level 1) (display "tree:\n") (pretty-print pt)))
(flat (flatten pt))
(foo (when (> %debug-level 0) (display "flat:\n") (pretty-print flat)))

View File

@ -91,14 +91,16 @@
(else (lambda () #t))))
(exec (append-map glob args)))
(define (glob pattern)
(define (glob? pattern)
(and (string? pattern) (string-match "\\?|\\*" pattern)))
(define (glob2regex pattern)
(define (glob? pattern)
(and (string? pattern) (string-match "\\?|\\*" pattern)))
(define* (glob->regex pattern #:key (begin "^") (end "$"))
(let* ((pattern (regexp-substitute/global #f "\\." pattern 'pre "\\." 'post))
(pattern (regexp-substitute/global #f "\\?" pattern 'pre "." 'post))
(pattern (regexp-substitute/global #f "\\*" pattern 'pre ".*" 'post)))
(make-regexp (string-append "^" pattern "$"))))
(make-regexp (string-append begin pattern end))))
(define (glob pattern)
(define (glob-match regex path) ;; pattern path -> bool
(regexp-match? (regexp-exec regex path)))
(define (glob- pattern file-names)
@ -107,7 +109,7 @@
(append-map (lambda (file-name)
(map (cut string-append (if (string=? "/" file-name) "" file-name) "/" <>)
(filter (conjoin (negate (cut string-prefix? "." <>))
(cute glob-match (glob2regex pattern) <>))
(cute glob-match (glob->regex pattern) <>))
(or (scandir file-name) '()))))
file-names)))
(cond
@ -285,3 +287,57 @@
(define (file-name o)
o)
(define (regexp-exec-non-greedy regexp string)
(let ((max (string-length string)))
(let loop ((size 1))
(and (<= size max)
(or (regexp-exec regexp (substring string 0 size))
(loop (1+ size)))))))
(define (regexp-exec-non-greedy-reverse regexp string)
(let ((max (string-length string)))
(let loop ((start (1- max)))
(and (>= start 0)
(or (regexp-exec regexp (substring string start))
(loop (1- start)))))))
(define (variable-hash name pattern)
(let ((value (variable name))
(glob? (glob? pattern)))
(if glob? (let* ((regexp (glob->regex pattern #:end ""))
(match (regexp-exec-non-greedy regexp value)))
(if match (string-drop value (match:end match))
value))
(if (string-prefix? pattern value) (string-drop value (string-length pattern))
value))))
(define (variable-hash-hash name pattern)
(let ((value (variable name))
(glob? (glob? pattern)))
(if glob? (let* ((regexp (glob->regex pattern #:end ""))
(match (regexp-exec regexp value)))
(if match (string-drop value (match:end match))
value))
(if (string-prefix? pattern value) (string-drop value (string-length pattern))
value))))
(define (variable-percent name pattern)
(let ((value (variable name))
(glob? (glob? pattern)))
(if glob? (let* ((regexp (glob->regex pattern #:begin ""))
(match (regexp-exec-non-greedy-reverse regexp value)))
(if match (substring value 0 (- (string-length value) (match:end match)))
value))
(if (string-suffix? pattern value) (substring value 0 (string-length pattern))
value))))
(define (variable-percent-percent name pattern)
(let ((value (variable name))
(glob? (glob? pattern)))
(if glob? (let* ((regexp (glob->regex pattern #:begin ""))
(match (regexp-exec regexp value)))
(if match (substring value 0 (match:start match))
value))
(if (string-suffix? pattern value) (substring value 0 (string-length pattern))
value))))

2
test/70-hash-hash.sh Normal file
View File

@ -0,0 +1,2 @@
file=dir/sub/name.ext
echo ${file##*/}

1
test/70-hash-hash.stdout Normal file
View File

@ -0,0 +1 @@
name.ext

2
test/70-hash.sh Normal file
View File

@ -0,0 +1,2 @@
file=dir/sub/name.ext
echo ${file#*/}

1
test/70-hash.stdout Normal file
View File

@ -0,0 +1 @@
sub/name.ext

View File

@ -0,0 +1,2 @@
file=dir/sub/name.ext
echo ${file%%/*}

View File

@ -0,0 +1 @@
dir

2
test/70-percent-space.sh Normal file
View File

@ -0,0 +1,2 @@
args="--prefix=/usr "
echo ${args% *}/

View File

@ -0,0 +1 @@
--prefix=/usr/

2
test/70-percent.sh Normal file
View File

@ -0,0 +1,2 @@
file=dir/sub/name.ext
echo ${file%/*}

1
test/70-percent.stdout Normal file
View File

@ -0,0 +1 @@
dir/sub