Support functions.
This commit is contained in:
parent
a8a6ea06df
commit
8d0d50240b
4
check.sh
4
check.sh
|
@ -16,6 +16,7 @@ tests="
|
|||
01-script-backslash-twice.sh
|
||||
|
||||
03-echo
|
||||
03-echo-doublequotes
|
||||
03-echo-nesting
|
||||
03-echo-escaped-doublequotes
|
||||
03-echo-quoted-doublequotes
|
||||
|
@ -65,6 +66,9 @@ tests="
|
|||
|
||||
50-iohere
|
||||
|
||||
60-function
|
||||
60-subst
|
||||
|
||||
100-sed
|
||||
100-sed-once
|
||||
100-sed-global
|
||||
|
|
|
@ -24,8 +24,11 @@
|
|||
#:use-module (gash io)
|
||||
|
||||
#:export (
|
||||
%command-line
|
||||
%functions
|
||||
%global-variables
|
||||
assignment
|
||||
function
|
||||
set-shell-opt!
|
||||
shell-opt?
|
||||
variable
|
||||
|
@ -33,6 +36,8 @@
|
|||
variable-or
|
||||
))
|
||||
|
||||
(define %command-line (make-parameter (command-line)))
|
||||
|
||||
;; FIXME: export/env vs set
|
||||
(define %global-variables
|
||||
(map identity ;; FIXME: make mutable
|
||||
|
@ -46,6 +51,8 @@
|
|||
(cons key value)))
|
||||
(environ)))))
|
||||
|
||||
(define %functions '())
|
||||
|
||||
(define (assignment name value)
|
||||
(and value
|
||||
(set! %global-variables
|
||||
|
@ -53,13 +60,20 @@
|
|||
#t))
|
||||
|
||||
(define* (variable name #:optional (default ""))
|
||||
(let ((name (if (string-prefix? "$" name) (string-drop name 1) name)))
|
||||
(or (assoc-ref %global-variables name)
|
||||
(if (shell-opt? "nounset") (begin
|
||||
;; TODO: throw/error
|
||||
(format (current-error-port) "gash: ~a: unbound variable\n" name)
|
||||
#f)
|
||||
default))))
|
||||
(cond ((string->number name)
|
||||
=>
|
||||
(lambda (n)
|
||||
(if (< n (length (%command-line))) (list-ref (%command-line) n)
|
||||
"")))
|
||||
((equal? name "#")
|
||||
(number->string (length (%command-line))))
|
||||
(else
|
||||
(or (assoc-ref %global-variables name)
|
||||
(if (shell-opt? "nounset") (begin
|
||||
;; TODO: throw/error
|
||||
(format (current-error-port) "gash: ~a: unbound variable\n" name)
|
||||
#f)
|
||||
default)))))
|
||||
|
||||
(define (variable-or name default)
|
||||
(variable name default))
|
||||
|
@ -79,3 +93,7 @@
|
|||
|
||||
(define (shell-opt? name)
|
||||
(member name (string-split (assoc-ref %global-variables "SHELLOPTS") #\:)))
|
||||
|
||||
(define (function name body)
|
||||
(set! %functions
|
||||
(assoc-set! %functions name body)))
|
||||
|
|
25
gash/peg.scm
25
gash/peg.scm
|
@ -160,14 +160,14 @@
|
|||
pipeline-head <- sp* command
|
||||
pipeline-tail <- sp* pipe ws* command
|
||||
negate <-- '!'
|
||||
command <-- (compound-command (sp+ io-redirect)*) / simple-command (sp+ io-redirect)* / function-def
|
||||
command <-- function / (compound-command (sp+ io-redirect)*) / simple-command (sp+ io-redirect)*
|
||||
compound-command <- brace-group / subshell / for-clause / case-clause / if-clause / while-clause / until-clause
|
||||
simple-command <- (sp* (io-redirect sp+)* nonreserved)+
|
||||
nonreserved <- &(reserved word) word / !reserved word
|
||||
reserved < 'case' / 'esac' / 'if' / 'fi' / 'then' / 'else' / 'elif' / 'for' / 'done' / 'do' / 'until' / 'while'
|
||||
|
||||
function-def <-- name sp* lpar sp* rpar ws* (function-body / error)
|
||||
function-body <-- compound-command io-redirect*
|
||||
function <-- identifier sp* lpar sp* rpar ws* (function-body / error)
|
||||
function-body <- compound-command io-redirect*
|
||||
|
||||
io-redirect <-- [0-9]* sp* (io-here / io-file)
|
||||
io-file <-- ('<&' / '>&' / '>>' / '>' / '<>'/ '<' / '>|') sp* ([0-9]+ / filename)
|
||||
|
@ -175,7 +175,7 @@
|
|||
io-op < '<<-' / '<<' / '<&' / '>&' / '>>' / '>' / '<>'/ '<' / '>|'
|
||||
io-suffix <- sp* here-label sp* nl
|
||||
|
||||
brace-group <-- '{' (sp* (compound-list / error) sp* '}' / error)
|
||||
brace-group <-- lbrace (ws* (compound-list / error) ws* rbrace / error)
|
||||
subshell <-- lpar compound-list separator rpar
|
||||
compound-list <- term (separator term)*
|
||||
|
||||
|
@ -212,7 +212,7 @@
|
|||
filename <-- word
|
||||
name <-- identifier
|
||||
identifier <- [_a-zA-Z][_a-zA-Z0-9]*
|
||||
word <-- assignment / delim / (number / variable / variable-and-or / literal)+
|
||||
word <-- assignment / (delim / number / variable / variable-and-or / literal)+
|
||||
|
||||
number <-- [0-9]+
|
||||
lsubst < '$('
|
||||
|
@ -223,8 +223,8 @@
|
|||
rhs <- (substitution / word)*
|
||||
assign < '='
|
||||
dollar < '$'
|
||||
literal <-- backslash? (!ws !amp !tick !dollar !pipe !semi !par !nl !sp !rbrace !io-op .)+
|
||||
variable <-- dollar ('$' / '*' / '?' / '@' / [0-9] / identifier / lbrace identifier rbrace)
|
||||
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 <-- identifier plus rhs
|
||||
variable-or <-- identifier minus rhs
|
||||
|
@ -233,7 +233,7 @@
|
|||
dq < [\"]
|
||||
bt < [`]
|
||||
singlequotes <-- sq (doublequotes / (!sq .))* sq
|
||||
doublequotes <-- dq (singlequotes / substitution / variable / variable-and-or / (!dq .))* dq
|
||||
doublequotes <-- dq (singlequotes / substitution / number / variable / variable-and-or / literal / (!dq .))* dq
|
||||
break <- amp / semi !semi
|
||||
separator <- (sp* break ws*) / ws+
|
||||
sequential-sep <- (semi !semi ws*) / ws+
|
||||
|
@ -301,6 +301,9 @@
|
|||
|
||||
(('script terms ...) `(script ,@(map transform terms)))
|
||||
|
||||
(('pipeline ('command command ('io-redirect ('io-file ">" file-name))))
|
||||
(transform `(pipeline (command ,@(transform command)) (lambda _ (with-output-to-file ,(transform file-name) (lambda _ (display (read-string))))))))
|
||||
|
||||
(('pipeline o ...)
|
||||
(let ((commands (map transform o)))
|
||||
`(pipeline ,@(cons (trace commands) commands))))
|
||||
|
@ -339,6 +342,12 @@
|
|||
(('word 'singlequotes) "")
|
||||
(('word o) (transform o))
|
||||
(('word o ...) `(string-append ,@(map transform o)))
|
||||
|
||||
(('function name body)
|
||||
`(function ,name (lambda ( . args) ,(transform body))))
|
||||
|
||||
(('brace-group o) `(brace-group ,(transform o)))
|
||||
(('file-name o) `(file-name ,(transform o)))
|
||||
(_ ast)))
|
||||
|
||||
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#:use-module (ice-9 local-eval)
|
||||
#:use-module (ice-9 match)
|
||||
#:use-module (ice-9 pretty-print)
|
||||
#:use-module (ice-9 rdelim)
|
||||
#:use-module (ice-9 receive)
|
||||
#:use-module (ice-9 regex)
|
||||
|
||||
|
@ -41,9 +42,11 @@
|
|||
#:export (
|
||||
and-terms
|
||||
background
|
||||
brace-group
|
||||
builtin
|
||||
command
|
||||
doublequotes
|
||||
file-name
|
||||
for
|
||||
glob
|
||||
if-clause
|
||||
|
@ -72,6 +75,11 @@
|
|||
(define (command . args)
|
||||
(define (exec command)
|
||||
(cond ((procedure? command) command)
|
||||
((assoc-ref %functions (car command))
|
||||
=>
|
||||
(lambda (function)
|
||||
(parameterize ((%command-line args))
|
||||
(last (apply function args)))))
|
||||
((every string? command)
|
||||
(let* ((program (car command))
|
||||
(escape-builtin? (and (string? program) (string-prefix? "\\" program)))
|
||||
|
@ -155,7 +163,7 @@
|
|||
(string-join (flatten o) ""))
|
||||
|
||||
(define-syntax-rule (substitution commands)
|
||||
(with-output-to-string (lambda _ commands)))
|
||||
(string-trim-right (with-output-to-string (lambda _ commands))))
|
||||
|
||||
(define-syntax-rule (ignore-error o)
|
||||
(let ((errexit (shell-opt? "errexit")))
|
||||
|
@ -271,3 +279,9 @@
|
|||
(apply command (map (cut local-eval <> (the-environment)) args))
|
||||
(command))))
|
||||
(else #f)))))
|
||||
|
||||
(define (brace-group . o)
|
||||
o)
|
||||
|
||||
(define (file-name o)
|
||||
o)
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
echo "foo" b"ar"
|
|
@ -0,0 +1 @@
|
|||
foo bar
|
|
@ -0,0 +1,8 @@
|
|||
foo () {
|
||||
echo $1
|
||||
}
|
||||
|
||||
echo before
|
||||
foo bar
|
||||
foo baz
|
||||
echo after
|
|
@ -0,0 +1,4 @@
|
|||
before
|
||||
bar
|
||||
baz
|
||||
after
|
|
@ -0,0 +1,9 @@
|
|||
subst () {
|
||||
sed \
|
||||
-e s",foo,bar,"\
|
||||
$1 > $2
|
||||
}
|
||||
|
||||
subst test/data/foo foo.tmp
|
||||
cat foo.tmp
|
||||
rm foo.tmp
|
|
@ -0,0 +1,3 @@
|
|||
foo
|
||||
bar
|
||||
baz
|
Loading…
Reference in New Issue