aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMu Qiao <qiaomuf@gentoo.org>2011-07-29 19:50:09 +0800
committerMu Qiao <qiaomuf@gentoo.org>2011-08-02 15:52:19 +0800
commit2736a7699bd775649a9f0c3ebdae6bf1331c71aa (patch)
tree1cacc1e81dab0f23ab9d3d7ed6a4f455c6db4432 /bashast
parentParser: allow 'test' to be string literal (diff)
downloadlibbash-2736a7699bd775649a9f0c3ebdae6bf1331c71aa.tar.gz
libbash-2736a7699bd775649a9f0c3ebdae6bf1331c71aa.tar.bz2
libbash-2736a7699bd775649a9f0c3ebdae6bf1331c71aa.zip
Parser: allow 'function' to be string literal
Diffstat (limited to 'bashast')
-rw-r--r--bashast/bashast.g11
-rw-r--r--bashast/features_script/features.sh.ast2
-rw-r--r--bashast/features_script/features.sh.tokens4
-rw-r--r--bashast/gunit/function.gunit22
-rw-r--r--bashast/gunit/simp_prog.gunit2
5 files changed, 22 insertions, 19 deletions
diff --git a/bashast/bashast.g b/bashast/bashast.g
index 6d9ba7e..ea8185f 100644
--- a/bashast/bashast.g
+++ b/bashast/bashast.g
@@ -127,6 +127,8 @@ tokens{
NOT_EQUALS;
EQUALS_TO;
BUILTIN_LOGIC;
+
+ FUNCTION;
}
@lexer::context
@@ -377,10 +379,12 @@ command_atom
LA(1) == CASE|| LA(1) == LPAREN|| LA(1) == LBRACE|| LA(1) == LLPAREN|| LA(1) == LSQUARE||
#ifdef OUTPUT_C
(LA(1) == NAME && LA(2) == BLANK && "test" == get_string(LT(1)))}? => compound_command
+ | {LA(1) == NAME && LA(2) == BLANK && "function" == get_string(LT(1))}? =>
#else
(LA(1) == NAME && LA(2) == BLANK && "test".equals(get_string(LT(1))))}? => compound_command
+ | {LA(1) == NAME && LA(2) == BLANK && "function".equals(get_string(LT(1)))}? =>
#endif
- | FUNCTION BLANK string_expr_no_reserved_word ((BLANK? parens wspace?)|wspace) compound_command
+ NAME BLANK string_expr_no_reserved_word ((BLANK? parens wspace?)|wspace) compound_command
-> ^(FUNCTION string_expr_no_reserved_word compound_command)
| (name (LSQUARE|EQUALS|PLUS EQUALS)) => variable_definitions
(
@@ -394,7 +398,7 @@ command_atom
| command_name
(
(BLANK? parens) => BLANK? parens wspace? compound_command
- -> ^(FUNCTION["function"] command_name compound_command)
+ -> ^(FUNCTION command_name compound_command)
| (
{LA(1) == BLANK &&
(
@@ -689,7 +693,7 @@ string_expr_no_reserved_word
);
reserved_word
- : CASE|DO|DONE|ELIF|ELSE|ESAC|FI|FOR|FUNCTION|IF|IN|SELECT|THEN|UNTIL|WHILE|TIME;
+ : CASE|DO|DONE|ELIF|ELSE|ESAC|FI|FOR|IF|IN|SELECT|THEN|UNTIL|WHILE|TIME;
non_quoted_string
: string_part
@@ -1033,7 +1037,6 @@ ELSE : 'else';
ESAC : 'esac';
FI : 'fi';
FOR : 'for';
-FUNCTION: 'function';
IF : 'if';
IN : 'in';
SELECT : 'select';
diff --git a/bashast/features_script/features.sh.ast b/bashast/features_script/features.sh.ast
index 87e4072..fc0eb4c 100644
--- a/bashast/features_script/features.sh.ast
+++ b/bashast/features_script/features.sh.ast
@@ -1 +1 @@
-(LIST (COMMAND (function (STRING lots_o_echo) (CURRENT_SHELL (LIST (COMMAND (STRING echo) (STRING (DOUBLE_QUOTED_STRING The number of tests that have failed : (VAR_REF failedtests)))) (COMMAND (STRING echo) (STRING (SINGLE_QUOTED_STRING '$failedtests'))) (COMMAND (STRING echo) (STRING (VAR_REF failedtests))))))) (COMMAND (function (STRING do_some_arith) (CURRENT_SHELL (LIST (COMMAND (ARITHMETIC_EXPRESSION (* 5 4))) (COMMAND (ARITHMETIC_EXPRESSION (** 5 4))) (COMMAND (ARITHMETIC_EXPRESSION (+ (VAR_REF failedtests) (/ 5 4)))) (COMMAND (ARITHMETIC_EXPRESSION (+ (VAR_REF z) (MINUS_SIGN 3)))))))) (COMMAND (function (STRING arrays) (SUBSHELL (LIST (COMMAND (VARIABLE_DEFINITIONS (= asdf (ARRAY (STRING a) (STRING b) (STRING c) (STRING d))))) (COMMAND (STRING echo) (STRING (VAR_REF (asdf 3)))) (COMMAND (VARIABLE_DEFINITIONS (= foo (ARRAY (STRING (COMMAND_SUB `echo 6`)) (STRING b) (STRING c) (STRING d))))) (COMMAND (VARIABLE_DEFINITIONS (= (arr (VAR_REF foo)) (STRING 3)))) (COMMAND (VARIABLE_DEFINITIONS (= bar (ARRAY (STRING a) (STRING b) (= 5 (STRING c)))))))))) (COMMAND (STRING echo) (STRING (BRACE_EXP (STRING a) (STRING b)))) (COMMAND (STRING echo) (STRING (BRACE_EXP (.. a d)))) (COMMAND (STRING echo) (STRING (BRACE_EXP (STRING (BRACE_EXP (STRING a) (STRING b))) (STRING c) (STRING d)))) (COMMAND (STRING echo) (STRING a (BRACE_EXP (STRING b) (STRING c)))) (COMMAND (STRING (COMMAND_SUB $(echo foobar)))) (| (COMMAND (STRING ls)) (COMMAND (STRING grep) (STRING gunit) (REDIR >> (STRING filelist)))) (COMMAND (case (STRING (COMMAND_SUB `echo asdf`)) (CASE_PATTERN (BRANCH gz) CASE_COMMAND (LIST (COMMAND (STRING echo) (STRING yay)))) (CASE_PATTERN (BRANCH bzip) CASE_COMMAND (LIST (COMMAND (STRING echo) (STRING three)))) (CASE_PATTERN (BRANCH MATCH_ALL) CASE_COMMAND (LIST (COMMAND (STRING echo) (STRING woo)))))) (COMMAND (for each (STRING (COMMAND_SUB `ls |grep log`)) (LIST (COMMAND (STRING echo) (STRING (VAR_REF each))) (COMMAND (STRING cat) (STRING each))))) (COMMAND (CFOR (FOR_INIT (+ 5 3)) (FOR_COND (+ 6 2)) (LIST (COMMAND (STRING echo) (STRING yay))) (FOR_MOD (+ 3 1)))) (COMMAND (select each (STRING (COMMAND_SUB `ls |grep output`)) (LIST (COMMAND (STRING echo) (STRING asdf) (REDIR 2 > (STRING / dev / null)))))) (COMMAND (IF_STATEMENT (if (LIST (COMMAND (STRING echo) (STRING yay2))) (LIST (COMMAND (STRING echo) (STRING yay)))))) (COMMAND (until (LIST (COMMAND (COMPOUND_COND (KEYWORD_TEST (a (STRING this / is . afile)))))) (LIST (COMMAND (STRING touch) (STRING this / is . afile))))) (COMMAND (while (LIST (COMMAND (COMPOUND_COND (BUILTIN_TEST (n (STRING foobar)))))) (LIST (COMMAND (STRING echo) (STRING (DOUBLE_QUOTED_STRING file found)))))) (COMMAND (IF_STATEMENT (if (LIST (COMMAND (COMPOUND_COND (BUILTIN_TEST (eq (STRING 5) (STRING 6)))))) (LIST (COMMAND (STRING echo) (STRING (DOUBLE_QUOTED_STRING something ' s wrong))))))) (COMMAND (STRING echo) (STRING this) (STRING command) (STRING has) (STRING multiple) (STRING arguments)) (COMMAND (STRING wc) (PROCESS_SUBSTITUTION < (LIST (COMMAND (STRING cat) (STRING / usr / share / dict / linux . words))))) (|| (&& (&& (&& (COMMAND (STRING cd) (STRING build)) (COMMAND (STRING . / configure))) (COMMAND (STRING make))) (COMMAND (STRING make_install))) (COMMAND (STRING echo) (STRING fail))) (COMMAND (STRING cd) (STRING / usr / bin)) (| (COMMAND (STRING ls) (STRING - al)) (COMMAND (STRING grep) (STRING more))) (COMMAND (VARIABLE_DEFINITIONS (= asdf (STRING parameters)))) (COMMAND (STRING (VAR_REF (USE_DEFAULT_WHEN_UNSET_OR_NULL asdf (STRING foo))))) (COMMAND (STRING (VAR_REF (OFFSET asdf 8)))) (COMMAND (STRING (VAR_REF (! asdf *)))) (COMMAND (STRING (VAR_REF (! asdf @)))) (COMMAND (STRING (VAR_REF (# foo)))) (COMMAND (STRING (VAR_REF (REPLACE_FIRST replaice (STRING with) (STRING pattern))))) (COMMAND (STRING (VAR_REF (LAZY_REMOVE_AT_START asdf (STRING bar))))) (COMMAND (STRING (VAR_REF (REPLACE_AT_START asdf (STRING bar))))) (COMMAND (STRING (VAR_REF (LAZY_REMOVE_AT_END asdf (STRING bar))))) (COMMAND (STRING (VAR_REF (LAZY_REMOVE_AT_END asdf (STRING bar))))) (COMMAND (STRING (VAR_REF 1)) (STRING (VAR_REF @)) (STRING (VAR_REF *))) (COMMAND (STRING (VAR_REF ?))) (COMMAND (STRING (VAR_REF (REPLACE_ALL PV (STRING .) (STRING _))))) (COMMAND (STRING (VAR_REF (REPLACE_AT_START PV (STRING foo) (STRING bar))))) (COMMAND (STRING (VAR_REF (REPLACE_AT_END PV (STRING foo) (STRING bar))))) (COMMAND (VARIABLE_DEFINITIONS (= MY_PN (STRING (VAR_REF (REPLACE_FIRST PN (STRING asterisk -))))))) (| (COMMAND (STRING cat) (STRING asdf)) (COMMAND (STRING grep) (STRING three) (REDIR 2 >& (FILE_DESCRIPTOR 1)) (REDIR > (STRING / dev / null)))) (COMMAND (STRING echo) (STRING asdf) (REDIR >> (STRING APPEND))) (COMMAND (STRING echo) (STRING cat) (<<< (STRING word))))
+(LIST (COMMAND (FUNCTION (STRING lots_o_echo) (CURRENT_SHELL (LIST (COMMAND (STRING echo) (STRING (DOUBLE_QUOTED_STRING The number of tests that have failed : (VAR_REF failedtests)))) (COMMAND (STRING echo) (STRING (SINGLE_QUOTED_STRING '$failedtests'))) (COMMAND (STRING echo) (STRING (VAR_REF failedtests))))))) (COMMAND (FUNCTION (STRING do_some_arith) (CURRENT_SHELL (LIST (COMMAND (ARITHMETIC_EXPRESSION (* 5 4))) (COMMAND (ARITHMETIC_EXPRESSION (** 5 4))) (COMMAND (ARITHMETIC_EXPRESSION (+ (VAR_REF failedtests) (/ 5 4)))) (COMMAND (ARITHMETIC_EXPRESSION (+ (VAR_REF z) (MINUS_SIGN 3)))))))) (COMMAND (FUNCTION (STRING arrays) (SUBSHELL (LIST (COMMAND (VARIABLE_DEFINITIONS (= asdf (ARRAY (STRING a) (STRING b) (STRING c) (STRING d))))) (COMMAND (STRING echo) (STRING (VAR_REF (asdf 3)))) (COMMAND (VARIABLE_DEFINITIONS (= foo (ARRAY (STRING (COMMAND_SUB `echo 6`)) (STRING b) (STRING c) (STRING d))))) (COMMAND (VARIABLE_DEFINITIONS (= (arr (VAR_REF foo)) (STRING 3)))) (COMMAND (VARIABLE_DEFINITIONS (= bar (ARRAY (STRING a) (STRING b) (= 5 (STRING c)))))))))) (COMMAND (STRING echo) (STRING (BRACE_EXP (STRING a) (STRING b)))) (COMMAND (STRING echo) (STRING (BRACE_EXP (.. a d)))) (COMMAND (STRING echo) (STRING (BRACE_EXP (STRING (BRACE_EXP (STRING a) (STRING b))) (STRING c) (STRING d)))) (COMMAND (STRING echo) (STRING a (BRACE_EXP (STRING b) (STRING c)))) (COMMAND (STRING (COMMAND_SUB $(echo foobar)))) (| (COMMAND (STRING ls)) (COMMAND (STRING grep) (STRING gunit) (REDIR >> (STRING filelist)))) (COMMAND (case (STRING (COMMAND_SUB `echo asdf`)) (CASE_PATTERN (BRANCH gz) CASE_COMMAND (LIST (COMMAND (STRING echo) (STRING yay)))) (CASE_PATTERN (BRANCH bzip) CASE_COMMAND (LIST (COMMAND (STRING echo) (STRING three)))) (CASE_PATTERN (BRANCH MATCH_ALL) CASE_COMMAND (LIST (COMMAND (STRING echo) (STRING woo)))))) (COMMAND (for each (STRING (COMMAND_SUB `ls |grep log`)) (LIST (COMMAND (STRING echo) (STRING (VAR_REF each))) (COMMAND (STRING cat) (STRING each))))) (COMMAND (CFOR (FOR_INIT (+ 5 3)) (FOR_COND (+ 6 2)) (LIST (COMMAND (STRING echo) (STRING yay))) (FOR_MOD (+ 3 1)))) (COMMAND (select each (STRING (COMMAND_SUB `ls |grep output`)) (LIST (COMMAND (STRING echo) (STRING asdf) (REDIR 2 > (STRING / dev / null)))))) (COMMAND (IF_STATEMENT (if (LIST (COMMAND (STRING echo) (STRING yay2))) (LIST (COMMAND (STRING echo) (STRING yay)))))) (COMMAND (until (LIST (COMMAND (COMPOUND_COND (KEYWORD_TEST (a (STRING this / is . afile)))))) (LIST (COMMAND (STRING touch) (STRING this / is . afile))))) (COMMAND (while (LIST (COMMAND (COMPOUND_COND (BUILTIN_TEST (n (STRING foobar)))))) (LIST (COMMAND (STRING echo) (STRING (DOUBLE_QUOTED_STRING file found)))))) (COMMAND (IF_STATEMENT (if (LIST (COMMAND (COMPOUND_COND (BUILTIN_TEST (eq (STRING 5) (STRING 6)))))) (LIST (COMMAND (STRING echo) (STRING (DOUBLE_QUOTED_STRING something ' s wrong))))))) (COMMAND (STRING echo) (STRING this) (STRING command) (STRING has) (STRING multiple) (STRING arguments)) (COMMAND (STRING wc) (PROCESS_SUBSTITUTION < (LIST (COMMAND (STRING cat) (STRING / usr / share / dict / linux . words))))) (|| (&& (&& (&& (COMMAND (STRING cd) (STRING build)) (COMMAND (STRING . / configure))) (COMMAND (STRING make))) (COMMAND (STRING make_install))) (COMMAND (STRING echo) (STRING fail))) (COMMAND (STRING cd) (STRING / usr / bin)) (| (COMMAND (STRING ls) (STRING - al)) (COMMAND (STRING grep) (STRING more))) (COMMAND (VARIABLE_DEFINITIONS (= asdf (STRING parameters)))) (COMMAND (STRING (VAR_REF (USE_DEFAULT_WHEN_UNSET_OR_NULL asdf (STRING foo))))) (COMMAND (STRING (VAR_REF (OFFSET asdf 8)))) (COMMAND (STRING (VAR_REF (! asdf *)))) (COMMAND (STRING (VAR_REF (! asdf @)))) (COMMAND (STRING (VAR_REF (# foo)))) (COMMAND (STRING (VAR_REF (REPLACE_FIRST replaice (STRING with) (STRING pattern))))) (COMMAND (STRING (VAR_REF (LAZY_REMOVE_AT_START asdf (STRING bar))))) (COMMAND (STRING (VAR_REF (REPLACE_AT_START asdf (STRING bar))))) (COMMAND (STRING (VAR_REF (LAZY_REMOVE_AT_END asdf (STRING bar))))) (COMMAND (STRING (VAR_REF (LAZY_REMOVE_AT_END asdf (STRING bar))))) (COMMAND (STRING (VAR_REF 1)) (STRING (VAR_REF @)) (STRING (VAR_REF *))) (COMMAND (STRING (VAR_REF ?))) (COMMAND (STRING (VAR_REF (REPLACE_ALL PV (STRING .) (STRING _))))) (COMMAND (STRING (VAR_REF (REPLACE_AT_START PV (STRING foo) (STRING bar))))) (COMMAND (STRING (VAR_REF (REPLACE_AT_END PV (STRING foo) (STRING bar))))) (COMMAND (VARIABLE_DEFINITIONS (= MY_PN (STRING (VAR_REF (REPLACE_FIRST PN (STRING asterisk -))))))) (| (COMMAND (STRING cat) (STRING asdf)) (COMMAND (STRING grep) (STRING three) (REDIR 2 >& (FILE_DESCRIPTOR 1)) (REDIR > (STRING / dev / null)))) (COMMAND (STRING echo) (STRING asdf) (REDIR >> (STRING APPEND))) (COMMAND (STRING echo) (STRING cat) (<<< (STRING word))))
diff --git a/bashast/features_script/features.sh.tokens b/bashast/features_script/features.sh.tokens
index f91800f..20562ed 100644
--- a/bashast/features_script/features.sh.tokens
+++ b/bashast/features_script/features.sh.tokens
@@ -22,7 +22,7 @@
22
23 COMMENT
24 COMMENTEOL
-25 FUNCTION BLANK NAME LPAREN RPAREN BLANK LBRACE EOL
+25 NAME BLANK NAME LPAREN RPAREN BLANK LBRACE EOL
26 BLANK NAME BLANK DQUOTE NAME BLANK NAME BLANK NAME BLANK NAME BLANK NAME BLANK NAME BLANK NAME COLON BLANK DOLLAR NAME DQUOTE EOL
27 BLANK NAME BLANK SINGLE_QUOTED_STRING_TOKEN EOL
28 BLANK NAME BLANK DOLLAR NAME EOL
@@ -35,7 +35,7 @@
35 BLANK LLPAREN BLANK DOLLAR LETTER PLUS MINUS DIGIT BLANK RPAREN RPAREN EOL
36 RBRACE EOL
37
-38 FUNCTION BLANK NAME LPAREN RPAREN BLANK LPAREN EOL
+38 NAME BLANK NAME LPAREN RPAREN BLANK LPAREN EOL
39 BLANK NAME EQUALS LPAREN LETTER BLANK LETTER BLANK LETTER BLANK LETTER RPAREN EOL
40 BLANK NAME BLANK DOLLAR LBRACE NAME LSQUARE DIGIT RSQUARE RBRACE EOL
41 BLANK NAME EQUALS LPAREN COMMAND_SUBSTITUTION_TICK BLANK LETTER BLANK LETTER BLANK LETTER RPAREN EOL
diff --git a/bashast/gunit/function.gunit b/bashast/gunit/function.gunit
index 06a34da..e0b23ef 100644
--- a/bashast/gunit/function.gunit
+++ b/bashast/gunit/function.gunit
@@ -21,24 +21,24 @@ gunit java_libbash;
command_atom:
"function quit {
exit
-}" -> (function (STRING quit) (CURRENT_SHELL (LIST (COMMAND (STRING exit)))))
+}" -> (FUNCTION (STRING quit) (CURRENT_SHELL (LIST (COMMAND (STRING exit)))))
"function quit{ exit; }" FAIL
"function quit { exit }" FAIL
-"function quit { exit; }" -> (function (STRING quit) (CURRENT_SHELL (LIST (COMMAND (STRING exit)))))
-"function foo() { :; }" -> (function (STRING foo) (CURRENT_SHELL (LIST (COMMAND (STRING :)))))
-"function foo(){ :; }" -> (function (STRING foo) (CURRENT_SHELL (LIST (COMMAND (STRING :)))))
-"foo() { :; }" -> (function (STRING foo) (CURRENT_SHELL (LIST (COMMAND (STRING :)))))
-"foo(){ :; }" -> (function (STRING foo) (CURRENT_SHELL (LIST (COMMAND (STRING :)))))
+"function quit { exit; }" -> (FUNCTION (STRING quit) (CURRENT_SHELL (LIST (COMMAND (STRING exit)))))
+"function foo() { :; }" -> (FUNCTION (STRING foo) (CURRENT_SHELL (LIST (COMMAND (STRING :)))))
+"function foo(){ :; }" -> (FUNCTION (STRING foo) (CURRENT_SHELL (LIST (COMMAND (STRING :)))))
+"foo() { :; }" -> (FUNCTION (STRING foo) (CURRENT_SHELL (LIST (COMMAND (STRING :)))))
+"foo(){ :; }" -> (FUNCTION (STRING foo) (CURRENT_SHELL (LIST (COMMAND (STRING :)))))
-"xorg-2_reconf_source() { :; }" -> (function (STRING xorg - 2 _reconf_source) (CURRENT_SHELL (LIST (COMMAND (STRING :)))))
+"xorg-2_reconf_source() { :; }" -> (FUNCTION (STRING xorg - 2 _reconf_source) (CURRENT_SHELL (LIST (COMMAND (STRING :)))))
-"function out() { function inner() { :; }; }" -> (function (STRING out) (CURRENT_SHELL (LIST (COMMAND (function (STRING inner) (CURRENT_SHELL (LIST (COMMAND (STRING :)))))))))
+"function out() { function inner() { :; }; }" -> (FUNCTION (STRING out) (CURRENT_SHELL (LIST (COMMAND (FUNCTION (STRING inner) (CURRENT_SHELL (LIST (COMMAND (STRING :)))))))))
command:
-"function quit { exit; } > /dev/null" -> (COMMAND (function (STRING quit) (CURRENT_SHELL (LIST (COMMAND (STRING exit))))) (REDIR > (STRING / dev / null)))
+"function quit { exit; } > /dev/null" -> (COMMAND (FUNCTION (STRING quit) (CURRENT_SHELL (LIST (COMMAND (STRING exit))))) (REDIR > (STRING / dev / null)))
"function quit {
# comment
- exit; } > /dev/null" -> (COMMAND (function (STRING quit) (CURRENT_SHELL (LIST (COMMAND (STRING exit))))) (REDIR > (STRING / dev / null)))
-"function help { echo hi; } 2> /dev/null" -> (COMMAND (function (STRING help) (CURRENT_SHELL (LIST (COMMAND (STRING echo) (STRING hi))))) (REDIR 2 > (STRING / dev / null)))
+ exit; } > /dev/null" -> (COMMAND (FUNCTION (STRING quit) (CURRENT_SHELL (LIST (COMMAND (STRING exit))))) (REDIR > (STRING / dev / null)))
+"function help { echo hi; } 2> /dev/null" -> (COMMAND (FUNCTION (STRING help) (CURRENT_SHELL (LIST (COMMAND (STRING echo) (STRING hi))))) (REDIR 2 > (STRING / dev / null)))
"function help { echo 3; } 2> /dev/null > output" OK
diff --git a/bashast/gunit/simp_prog.gunit b/bashast/gunit/simp_prog.gunit
index d36c5f6..e765ab0 100644
--- a/bashast/gunit/simp_prog.gunit
+++ b/bashast/gunit/simp_prog.gunit
@@ -35,4 +35,4 @@ hello () {
}
hello
quit
-echo foo" -> (LIST (COMMAND (function (STRING quit) (CURRENT_SHELL (LIST (COMMAND (STRING exit)))))) (COMMAND (function (STRING hello) (CURRENT_SHELL (LIST (COMMAND (STRING echo) (STRING Hello !)))))) (COMMAND (STRING hello)) (COMMAND (STRING quit)) (COMMAND (STRING echo) (STRING foo)))
+echo foo" -> (LIST (COMMAND (FUNCTION (STRING quit) (CURRENT_SHELL (LIST (COMMAND (STRING exit)))))) (COMMAND (FUNCTION (STRING hello) (CURRENT_SHELL (LIST (COMMAND (STRING echo) (STRING Hello !)))))) (COMMAND (STRING hello)) (COMMAND (STRING quit)) (COMMAND (STRING echo) (STRING foo)))