parser: refactor, use `pipeline' instead of `expression'.
This commit is contained in:
parent
9623e014f0
commit
d065723221
|
@ -111,7 +111,6 @@ TERMINAL-WIDTH. Use COLUMN-GAP spaces between two subsequent columns."
|
|||
(()
|
||||
(display-tabulated (scandir ".")))
|
||||
(args
|
||||
(format (current-error-port) "hiero:args=~s\n" args)
|
||||
(let* ((option-spec
|
||||
'((all (single-char #\a))
|
||||
(help)
|
||||
|
|
|
@ -34,7 +34,7 @@
|
|||
#:use-module (gash guix-build-utils)
|
||||
#:use-module (gash io)
|
||||
#:use-module (gash job)
|
||||
#:use-module (gash peg) ; pipeline
|
||||
#:use-module (gash pipe)
|
||||
|
||||
#:export (
|
||||
%builtin-commands
|
||||
|
@ -48,6 +48,7 @@
|
|||
for
|
||||
substitution
|
||||
sh-exec
|
||||
if-clause
|
||||
|
||||
bg-command
|
||||
cd-command
|
||||
|
@ -131,7 +132,7 @@ mostly works, pipes work, some redirections work.
|
|||
(let* ((option-spec
|
||||
'((help)
|
||||
(version)))
|
||||
(options (getopt-long (cons "ls" args) option-spec))
|
||||
(options (getopt-long (cons "find" args) option-spec))
|
||||
(help? (option-ref options 'help #f))
|
||||
(version? (option-ref options 'version #f))
|
||||
(files (option-ref options '() '()))
|
||||
|
@ -164,7 +165,7 @@ Options:
|
|||
(help)
|
||||
(show (single-char #\v))
|
||||
(version)))
|
||||
(options (getopt-long (cons "ls" args) option-spec))
|
||||
(options (getopt-long (cons "command" args) option-spec))
|
||||
(help? (option-ref options 'help #f))
|
||||
(version? (option-ref options 'version #f))
|
||||
(files (option-ref options '() '())))
|
||||
|
@ -206,7 +207,7 @@ Options:
|
|||
'((help)
|
||||
(canonical-file-name (single-char #\p))
|
||||
(version)))
|
||||
(options (getopt-long (cons "ls" args) option-spec))
|
||||
(options (getopt-long (cons "type" args) option-spec))
|
||||
(help? (option-ref options 'help #f))
|
||||
(version? (option-ref options 'version #f))
|
||||
(files (option-ref options '() '())))
|
||||
|
@ -253,12 +254,10 @@ Options:
|
|||
(is-writable (single-char #\w))
|
||||
(is-exeutable (single-char #\x))
|
||||
(version)))
|
||||
(options (getopt-long (cons "ls" args) option-spec))
|
||||
(options (getopt-long (cons "test" args) option-spec))
|
||||
(help? (option-ref options 'help #f))
|
||||
(version? (option-ref options 'version #f))
|
||||
(files (option-ref options '() '()))
|
||||
(files (if (equal? (last files) "]") (drop-right files 1)
|
||||
files))
|
||||
(file (and (pair? files) (car files))))
|
||||
(cond (help? (display "Usage: test [EXPRESSION]
|
||||
|
||||
|
@ -284,11 +283,12 @@ Options:
|
|||
(left "==" right))
|
||||
(equal? left right))
|
||||
(expression
|
||||
(let ((status (sh-exec `(pipeline (command ',expression)))))
|
||||
(zero? status)))))
|
||||
(pipeline (command expression)))))
|
||||
((not (= (length files) 1))
|
||||
(format (current-error-port) "test: too many files: ~a\n" files)
|
||||
1)
|
||||
((option-ref options 'is-file #f)
|
||||
(regular-file? file))
|
||||
((option-ref options 'is-directory #f)
|
||||
(directory-exists? file))
|
||||
((option-ref options 'exists #f)
|
||||
|
@ -304,7 +304,22 @@ Options:
|
|||
(access? file W_OK))
|
||||
((option-ref options 'is-exeutable #f)
|
||||
(access? file X_OK))
|
||||
(else #f))))))
|
||||
(else
|
||||
(error "gash: test: not supported" args)))))))
|
||||
|
||||
(define bracket-command
|
||||
(case-lambda
|
||||
(() #f)
|
||||
(args
|
||||
(cond ((and (pair? args) (equal? (car args) "--help"))
|
||||
(test-command "--help"))
|
||||
((and (pair? args) (equal? (car args) "--version"))
|
||||
(test-command "--version"))
|
||||
(else
|
||||
(if (not (equal? (last args) "]")) (begin
|
||||
(format (current-error-port) "gash: [: missing `]'\n")
|
||||
#f)
|
||||
(apply test-command (drop-right args 1))))))))
|
||||
|
||||
(define grep-command
|
||||
(case-lambda
|
||||
|
@ -338,8 +353,8 @@ Options:
|
|||
(version? (format #t "grep (GASH) ~a\n" %version))
|
||||
((null? files) #t)
|
||||
(else
|
||||
(let* ((pattern (warn 'pattern (car files)))
|
||||
(files (warn 'files (cdr files)))
|
||||
(let* ((pattern (car files))
|
||||
(files (cdr files))
|
||||
(matches (append-map (cut grep pattern <>) files)))
|
||||
(define (display-match o)
|
||||
(let* ((s (grep-match-string o))
|
||||
|
@ -472,17 +487,26 @@ Options:
|
|||
(define (substitution . commands)
|
||||
(apply (@ (gash pipe) pipeline->string) (map cdr commands))) ;;HACK
|
||||
|
||||
(define (sh-exec ast)
|
||||
(define (exec cmd)
|
||||
(when (> %debug-level 0)
|
||||
(format (current-error-port) "sh-exec:exec cmd=~s\n" cmd))
|
||||
(let* ((job (local-eval cmd (the-environment)))
|
||||
(stati (cond ((job? job) (map status:exit-val (job-status job)))
|
||||
(define-syntax if-clause
|
||||
(lambda (x)
|
||||
(syntax-case x ()
|
||||
((_ expr then)
|
||||
(with-syntax ((it (datum->syntax x 'it)))
|
||||
#'(let ((it expr))
|
||||
(if (zero? it) then))))
|
||||
((_ expr then else)
|
||||
(with-syntax ((it (datum->syntax x 'it)))
|
||||
#'(let ((it expr))
|
||||
(if (zero? it) then else)))))))
|
||||
|
||||
(define (pipeline . commands)
|
||||
(define (handle job)
|
||||
(let* ((stati (cond ((job? job) (map status:exit-val (job-status job)))
|
||||
((boolean? job) (list (if job 0 1)))
|
||||
((number? job) (list job))
|
||||
(else (list 0))))
|
||||
(status (if (shell-opt? "pipefail") (or (find (negate zero?) stati) 0)
|
||||
(car stati)))
|
||||
(status (if (shell-opt? "pipefail") (or (find (negate zero?) stati) 0)
|
||||
(car stati)))
|
||||
(pipestatus (string-append
|
||||
"("
|
||||
(string-join
|
||||
|
@ -497,36 +521,18 @@ Options:
|
|||
(shell-opt? "errexit"))
|
||||
(exit status))
|
||||
status))
|
||||
(when (> %debug-level 1)
|
||||
(format (current-error-port) "sh-exec:exec ast=~s\n" ast))
|
||||
(match ast
|
||||
('script #t) ;; skip
|
||||
(('pipeline commands ...)
|
||||
(when (shell-opt? "xtrace")
|
||||
(for-each
|
||||
(lambda (o)
|
||||
(match o
|
||||
(('command command ...)
|
||||
;;(format (current-error-port) "+ ~a\n" (string-join command))
|
||||
;; FIXME: side-effects done twice?!
|
||||
;; '(variable "$?"): not a string...hmm
|
||||
(format (current-error-port) "+ ~a\n" (string-join (map (cut local-eval <> (the-environment)) command)))
|
||||
)
|
||||
(_ (format (current-error-port) "FIXME trace:~s" o))))
|
||||
(reverse commands)))
|
||||
(exec ast))
|
||||
(_ (for-each exec ast))))
|
||||
|
||||
(define (pipeline . commands)
|
||||
(when (> %debug-level 1)
|
||||
(format (current-error-port) "pijp: commands=~s\n" commands))
|
||||
;; FIXME: after running a builtin, we still end up here with the builtin's result
|
||||
;; that should probably not happen, however, cater for it here for now
|
||||
(match commands
|
||||
(((and (? boolean?) boolean)) (if boolean 0 1))
|
||||
(((and (? number?) number)) number)
|
||||
(((? unspecified?)) 0)
|
||||
(_ (apply (@ (gash pipe) pipeline) #t commands))))
|
||||
(((and (? boolean?) boolean))
|
||||
(handle boolean))
|
||||
(((and (? number?) number))
|
||||
(handle number))
|
||||
(((? unspecified?))
|
||||
(handle #t))
|
||||
(_ (handle (apply pipeline+ #t commands)))))
|
||||
|
||||
(define %builtin-commands
|
||||
`(
|
||||
|
@ -551,5 +557,5 @@ Options:
|
|||
("type" . ,type-command)
|
||||
("wc" . ,wc-command)
|
||||
("which" . ,which-command)
|
||||
("[" . ,test-command)
|
||||
("[" . ,bracket-command)
|
||||
))
|
||||
|
|
|
@ -44,6 +44,7 @@
|
|||
|
||||
directory-exists?
|
||||
executable-file?
|
||||
regular-file?
|
||||
symbolic-link?
|
||||
))
|
||||
|
||||
|
@ -67,9 +68,17 @@
|
|||
(and s
|
||||
(not (zero? (logand (stat:mode s) #o100))))))
|
||||
|
||||
(define (regular-file? file)
|
||||
"Return #t if FILE is a regular file."
|
||||
(let ((s (stat file #f)))
|
||||
(and s
|
||||
(eq? (stat:type s) 'regular))))
|
||||
|
||||
(define (symbolic-link? file)
|
||||
"Return #t if FILE is a symbolic link (aka. \"symlink\".)"
|
||||
(eq? (stat:type (lstat file)) 'symlink))
|
||||
(let ((s (lstat file)))
|
||||
(and s
|
||||
(eq? (stat:type s) 'symlink))))
|
||||
|
||||
(define (file-name-predicate regexp)
|
||||
"Return a predicate that returns true when passed a file name whose base
|
||||
|
|
21
gash/peg.scm
21
gash/peg.scm
|
@ -119,15 +119,14 @@
|
|||
|
||||
for-keyword < 'for'
|
||||
in-keyword < 'in'
|
||||
for-clause <-- for-keyword sp+ name (ws+ in-keyword expression)? sp* sequential-sep do-group
|
||||
expression <-- (sp+ word)+
|
||||
for-clause <-- for-keyword sp+ name (ws+ in-keyword pipeline)? sp* sequential-sep do-group
|
||||
do-keyword < 'do'
|
||||
done-keyword < 'done'
|
||||
do-group <- do-keyword ws* compound-list separator done-keyword
|
||||
|
||||
if-keyword < 'if'
|
||||
fi-keyword < 'fi'
|
||||
if-clause <-- if-keyword expression separator then-part elif-part* else-part? fi-keyword
|
||||
if-clause <-- if-keyword pipeline separator then-part elif-part* else-part? fi-keyword
|
||||
then-keyword < 'then'
|
||||
then-part <-- then-keyword ws* compound-list separator
|
||||
elif-keyword < 'elif'
|
||||
|
@ -144,11 +143,8 @@
|
|||
filename <-- word
|
||||
name <-- identifier
|
||||
identifier <- [_a-zA-Z][_a-zA-Z0-9]*
|
||||
word <- test / substitution / assignment / number / variable / delim / literal
|
||||
word <- substitution / assignment / number / variable / delim / literal
|
||||
number <-- [0-9]+
|
||||
test <-- ltest expression rtest
|
||||
ltest < '[ '
|
||||
rtest < ' ]'
|
||||
lsubst < '$('
|
||||
rsubst < ')'
|
||||
tick < '`'
|
||||
|
@ -156,7 +152,7 @@
|
|||
assignment <-- name assign (substitution / word)*
|
||||
assign < '='
|
||||
dollar <- '$'
|
||||
literal <-- (!ltest !tick !dollar !pipe !semi !par !nl !sp .)+
|
||||
literal <-- (!tick !dollar !pipe !semi !par !nl !sp .)+
|
||||
variable <-- dollar (dollar / '*' / '?' / '@' / [0-9] / identifier / ([{] (![}] .)+ [}]))
|
||||
delim <- singlequotes / doublequotes / substitution
|
||||
sq < [']
|
||||
|
@ -201,7 +197,7 @@
|
|||
((eq? ast 'script)
|
||||
#t)
|
||||
(else
|
||||
(map sh-exec ast)
|
||||
(map (cut local-eval <> (the-environment)) ast)
|
||||
ast))))
|
||||
|
||||
(define (unspecified? o)
|
||||
|
@ -217,8 +213,6 @@
|
|||
(('pipeline h t) (pk `(pipeline ,(transform h) ,@(map transform t))))
|
||||
(('command o ...) (let* ((command (map transform o))
|
||||
(program (car command))
|
||||
;; if [ 0 = 1 ] ... program = '(if ...) not a string
|
||||
;; this escape-builtin? is probably not deep enough?
|
||||
(escape-builtin? (and (string? program) (string-prefix? "\\" program)))
|
||||
(program (if escape-builtin? (string-drop program 1) program))
|
||||
(command (cons program (cdr command))))
|
||||
|
@ -230,11 +224,10 @@
|
|||
(('literal o) (transform o))
|
||||
(('name o) o)
|
||||
(('number o) o)
|
||||
(('expression o ...) `(expression ,@(map transform o)))
|
||||
(('assignment a b) `(lambda _ (assignment ,(transform a) ,(transform b))))
|
||||
(('for-clause name expr do) `(for ,(transform name) (lambda _ ,(transform expr)) (lambda _ ,(transform do))))
|
||||
(('if-clause expr then) `(if ,(transform expr) ,(transform then)))
|
||||
(('if-clause expr then else) `(if ,(transform expr) ,(transform then) ,(transform else)))
|
||||
(('if-clause expr then) `(if-clause ,(transform expr) ,(transform then)))
|
||||
(('if-clause expr then else) `(if-clause ,(transform expr) ,(transform then) ,(transform else)))
|
||||
(('then-part o ...) `(begin ,@(map transform o)))
|
||||
(('else-part o ...) `(begin ,@(map transform o)))
|
||||
(_ ast)))
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
#:use-module (gash job)
|
||||
#:use-module (gash io)
|
||||
|
||||
#:export (handle-error pipeline pipeline->string substitute))
|
||||
#:export (handle-error pipeline+ pipeline->string substitute))
|
||||
|
||||
(define (handle-error job error)
|
||||
(let ((status (wait job)))
|
||||
|
@ -87,14 +87,9 @@
|
|||
(map close w)
|
||||
r))))
|
||||
|
||||
(define (pipeline fg? . commands)
|
||||
(define (pipeline+ fg? . commands)
|
||||
(when (> %debug-level 0)
|
||||
(format (current-error-port) "pipeline[~a]: COMMANDS: ~s\n" fg? commands))
|
||||
;; (when (shell-opt? "xtrace")
|
||||
;; (for-each
|
||||
;; (lambda (o)
|
||||
;; (format (current-error-port) "+ ~a\n" (string-join o)))
|
||||
;; (reverse commands)))
|
||||
(format (current-error-port) "pipeline+[~a]: COMMANDS: ~s\n" fg? commands))
|
||||
(receive (r w)
|
||||
(pipe*)
|
||||
(move->fdes w 2)
|
||||
|
@ -136,16 +131,16 @@
|
|||
|
||||
(define (pipeline->string . commands)
|
||||
(receive (job ports)
|
||||
(apply pipeline #f commands)
|
||||
(apply pipeline+ #f commands)
|
||||
(let ((output (read-string (car ports))))
|
||||
(wait job)
|
||||
output)))
|
||||
|
||||
;;(pipeline #f '("head" "-c128" "/dev/urandom") '("tr" "-dc" "A-Z0-9") (lambda () (display (read-string))))
|
||||
;;(pipeline #f '("head" "-c128" "/dev/urandom") '("tr" "-dc" "A-Z0-9") '("cat"))
|
||||
;;(pipeline #f (lambda () (display 'foo)) '("grep" "o") '("tr" "o" "e"))
|
||||
;;(pipeline+ #f '("head" "-c128" "/dev/urandom") '("tr" "-dc" "A-Z0-9") (lambda () (display (read-string))))
|
||||
;;(pipeline+ #f '("head" "-c128" "/dev/urandom") '("tr" "-dc" "A-Z0-9") '("cat"))
|
||||
;;(pipeline+ #f (lambda () (display 'foo)) '("grep" "o") '("tr" "o" "e"))
|
||||
|
||||
;; (pipeline #f
|
||||
;; (pipeline+ #f
|
||||
;; (lambda () (display "\nbin\nboot\nroot\nusr\nvar"))
|
||||
;; '("tr" "u" "a")
|
||||
;; (lambda () (display (string-map (lambda (c) (if (eq? c #\o) #\e c)) (read-string))))
|
||||
|
@ -153,7 +148,7 @@
|
|||
;; (lambda () (display (read-string))))
|
||||
|
||||
;; (receive (job ports)
|
||||
;; (pipeline #f
|
||||
;; (pipeline+ #f
|
||||
;; (lambda ()
|
||||
;; (display "foo")
|
||||
;; (display "bar" (current-error-port)))
|
||||
|
|
Loading…
Reference in New Issue