# Iteration 10: Function definitions
# === POSIX form: name() compound_command ===
=== simple function
f() { echo hi; }
---
(function "f" (brace-group (command (word "echo") (word "hi"))))
---
=== function with subshell body
f() ( echo hi )
---
(function "f" (subshell (command (word "echo") (word "hi"))))
---
=== function no space before parens
f(){ echo hi; }
---
(function "f" (brace-group (command (word "echo") (word "hi"))))
---
=== function with space after parens
f() { echo hi; }
---
(function "f" (brace-group (command (word "echo") (word "hi"))))
---
=== function multi-line body
f() {
echo hi
}
---
(function "f" (brace-group (command (word "echo") (word "hi"))))
---
=== function with multiple commands
f() { echo a; echo b; }
---
(function "f" (brace-group (semi (command (word "echo") (word "a")) (command (word "echo") (word "b")))))
---
=== function with pipeline body
f() { echo hi | cat; }
---
(function "f" (brace-group (pipe (command (word "echo") (word "hi")) (command (word "cat")))))
---
=== function with if body
f() { if true; then echo yes; fi; }
---
(function "f" (brace-group (if (command (word "true")) (command (word "echo") (word "yes")))))
---
# === function keyword form ===
=== function keyword with parens
function f() { echo hi; }
---
(function "f" (brace-group (command (word "echo") (word "hi"))))
---
=== function keyword without parens
function f { echo hi; }
---
(function "f" (brace-group (command (word "echo") (word "hi"))))
---
=== function keyword with subshell
function f() ( echo hi )
---
(function "f" (subshell (command (word "echo") (word "hi"))))
---
=== function keyword no parens subshell
function f ( echo hi )
---
(function "f" (subshell (command (word "echo") (word "hi"))))
---
# === function names ===
=== function with underscore name
_foo() { echo hi; }
---
(function "_foo" (brace-group (command (word "echo") (word "hi"))))
---
=== function with number in name
foo123() { echo hi; }
---
(function "foo123" (brace-group (command (word "echo") (word "hi"))))
---
=== function with dash in name
foo-bar() { echo hi; }
---
(function "foo-bar" (brace-group (command (word "echo") (word "hi"))))
---
=== function with dots in name
foo.bar() { echo hi; }
---
(function "foo.bar" (brace-group (command (word "echo") (word "hi"))))
---
# === functions in context ===
=== function then command
f() { echo hi; }; f
---
(semi (function "f" (brace-group (command (word "echo") (word "hi")))) (command (word "f")))
---
=== function in list
f() { echo a; } && g() { echo b; }
---
(and (function "f" (brace-group (command (word "echo") (word "a")))) (function "g" (brace-group (command (word "echo") (word "b")))))
---
=== multiple function definitions
f() { echo f; }
g() { echo g; }
---
(function "f" (brace-group (command (word "echo") (word "f"))))
(function "g" (brace-group (command (word "echo") (word "g"))))
---
# === Brutal edge cases ===
# Unusual but valid function names
=== function name with colon
foo:bar() { echo hi; }
---
(function "foo:bar" (brace-group (command (word "echo") (word "hi"))))
---
=== function name with double colon
foo::bar() { echo hi; }
---
(function "foo::bar" (brace-group (command (word "echo") (word "hi"))))
---
=== function name underscore only
_() { echo hi; }
---
(function "_" (brace-group (command (word "echo") (word "hi"))))
---
=== function name double underscore
__() { echo hi; }
---
(function "__" (brace-group (command (word "echo") (word "hi"))))
---
=== function overriding colon builtin
:() { echo not noop; }
---
(function ":" (brace-group (command (word "echo") (word "not") (word "noop"))))
---
=== function overriding true
true() { echo fake; }
---
(function "true" (brace-group (command (word "echo") (word "fake"))))
---
# Reserved words as function names (requires function keyword)
=== function keyword with reserved word if
function if { echo shadowed; }
---
(function "if" (brace-group (command (word "echo") (word "shadowed"))))
---
=== function keyword with reserved word for
function for { echo shadowed; }
---
(function "for" (brace-group (command (word "echo") (word "shadowed"))))
---
=== function keyword with reserved word while
function while { echo shadowed; }
---
(function "while" (brace-group (command (word "echo") (word "shadowed"))))
---
=== function keyword with reserved word case
function case { echo shadowed; }
---
(function "case" (brace-group (command (word "echo") (word "shadowed"))))
---
=== function keyword with reserved word do
function do { echo shadowed; }
---
(function "do" (brace-group (command (word "echo") (word "shadowed"))))
---
=== function keyword with reserved word done
function done { echo shadowed; }
---
(function "done" (brace-group (command (word "echo") (word "shadowed"))))
---
# Whitespace variations
=== function newline before brace
f()
{ echo hi; }
---
(function "f" (brace-group (command (word "echo") (word "hi"))))
---
=== function keyword newline before brace
function f
{ echo hi; }
---
(function "f" (brace-group (command (word "echo") (word "hi"))))
---
=== function space before parens
f () { echo hi; }
---
(function "f" (brace-group (command (word "echo") (word "hi"))))
---
=== function tabs everywhere
f () { echo hi; }
---
(function "f" (brace-group (command (word "echo") (word "hi"))))
---
# Nested functions
=== nested function definition
outer() { inner() { echo inner; }; inner; }
---
(function "outer" (brace-group (semi (function "inner" (brace-group (command (word "echo") (word "inner")))) (command (word "inner")))))
---
=== deeply nested functions
a() { b() { c() { echo c; }; c; }; b; }
---
(function "a" (brace-group (semi (function "b" (brace-group (semi (function "c" (brace-group (command (word "echo") (word "c")))) (command (word "c"))))) (command (word "b")))))
---
# Functions in compound commands
=== function in subshell
( f() { echo hi; }; f )
---
(subshell (semi (function "f" (brace-group (command (word "echo") (word "hi")))) (command (word "f"))))
---
=== function in brace group
{ f() { echo hi; }; f; }
---
(brace-group (semi (function "f" (brace-group (command (word "echo") (word "hi")))) (command (word "f"))))
---
=== function after if
if true; then f() { echo hi; }; fi
---
(if (command (word "true")) (function "f" (brace-group (command (word "echo") (word "hi")))))
---
=== function in while body
while false; do f() { :; }; done
---
(while (command (word "false")) (function "f" (brace-group (command (word ":")))))
---
# Empty and minimal functions
=== empty function with colon
noop() { :; }
---
(function "noop" (brace-group (command (word ":"))))
---
=== empty function with true
stub() { true; }
---
(function "stub" (brace-group (command (word "true"))))
---
# Chained functions
=== chained function definitions
a() { :; }; b() { :; }; c() { :; }
---
(semi (semi (function "a" (brace-group (command (word ":")))) (function "b" (brace-group (command (word ":"))))) (function "c" (brace-group (command (word ":")))))
---
=== function after command
echo start; f() { echo f; }
---
(semi (command (word "echo") (word "start")) (function "f" (brace-group (command (word "echo") (word "f")))))
---
=== command after function
f() { echo f; }; echo end
---
(semi (function "f" (brace-group (command (word "echo") (word "f")))) (command (word "echo") (word "end")))
---
# Complex bodies
=== function with for loop
f() { for i in a b c; do echo $i; done; }
---
(function "f" (brace-group (for (word "i") (in (word "a") (word "b") (word "c")) (command (word "echo") (word "$i")))))
---
=== function with case
f() { case $1 in a) echo a;; esac; }
---
(function "f" (brace-group (case (word "$1") (pattern ((word "a")) (command (word "echo") (word "a"))))))
---
=== function with while
f() { while true; do echo loop; break; done; }
---
(function "f" (brace-group (while (command (word "true")) (semi (command (word "echo") (word "loop")) (command (word "break"))))))
---
=== function with nested if
f() { if a; then if b; then c; fi; fi; }
---
(function "f" (brace-group (if (command (word "a")) (if (command (word "b")) (command (word "c"))))))
---