aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile.am4
-rw-r--r--bashast/bashast.g25
-rw-r--r--bashast/features_script/features.sh.ast2
-rw-r--r--bashast/gunit/compound.gunit34
-rw-r--r--bashast/gunit/cond_main.gunit5
-rw-r--r--bashast/gunit/expansions.gunit3
-rw-r--r--bashast/gunit/pipeline.gunit2
-rw-r--r--bashast/libbashWalker.g286
-rw-r--r--scripts/compound_command.bash112
-rw-r--r--scripts/compound_command.bash.result34
-rw-r--r--scripts/test_expr.bash26
-rw-r--r--scripts/test_expr.bash.result9
-rw-r--r--scripts/var_def.bash6
-rw-r--r--scripts/var_def.bash.result6
-rw-r--r--src/core/interpreter.cpp10
-rw-r--r--src/core/interpreter.h17
-rw-r--r--src/core/tests/interpreter_test.cpp14
-rwxr-xr-xtest/script_compiler.sh2
-rw-r--r--utils/variable_printer.cpp8
19 files changed, 533 insertions, 72 deletions
diff --git a/Makefile.am b/Makefile.am
index b4f6488..7202cef 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -52,12 +52,16 @@ BASH_TESTS = scripts/var_def.bash \
scripts/command_execution.bash \
scripts/function_def.bash \
scripts/arithmetic_assignment.bash \
+ scripts/compound_command.bash \
+ scripts/test_expr.bash \
scripts/binary_arithmetic.bash
BASH_RESULT = scripts/var_def.bash.result \
scripts/var_expansion.bash.result \
scripts/command_execution.bash.result \
scripts/function_def.bash.result \
scripts/arithmetic_assignment.bash.result \
+ scripts/compound_command.bash.result \
+ scripts/test_expr.bash.result \
scripts/binary_arithmetic.bash.result
EBUILD_LOG_COMPILER = $(srcdir)/test/ebuild_compiler.sh
diff --git a/bashast/bashast.g b/bashast/bashast.g
index f6e50b3..3a84d29 100644
--- a/bashast/bashast.g
+++ b/bashast/bashast.g
@@ -33,13 +33,16 @@ tokens{
EMPTY_BRACE_EXPANSION_ATOM;
COMMAND_SUB;
CASE_PATTERN;
+ CASE_COMMAND;
SUBSHELL;
CURRENT_SHELL;
COMPOUND_ARITH;
COMPOUND_COND;
+ CFOR;
FOR_INIT;
FOR_COND;
FOR_MOD;
+ IF_STATEMENT;
FNAME;
OP;
PRE_INCR;
@@ -93,6 +96,8 @@ tokens{
// Avoid ambiguity (being a sign or an operator)
PLUS_SIGN;
MINUS_SIGN;
+ // Operators
+ NOT_EQUALS;
}
start : (flcomment)? EOL* clist BLANK* (SEMIC|AMP|EOL)? -> clist;
@@ -186,12 +191,12 @@ compound_command
//Expressions allowed inside a compound command
for_expr: FOR BLANK+ name (wspace IN (BLANK+ fname)+)? semiel DO wspace* clist semiel DONE -> ^(FOR name (fname+)? clist)
| FOR BLANK* LLPAREN EOL? (BLANK* init=arithmetic BLANK*|BLANK+)? (SEMIC (BLANK? fcond=arithmetic BLANK*|BLANK+)? SEMIC|DOUBLE_SEMIC) (BLANK* mod=arithmetic)? wspace* RRPAREN semiel DO wspace clist semiel DONE
- -> ^(FOR ^(FOR_INIT $init)? ^(FOR_COND $fcond)? ^(FOR_MOD $mod)? clist)
+ -> ^(CFOR ^(FOR_INIT $init)? ^(FOR_COND $fcond)? clist ^(FOR_MOD $mod)?)
;
sel_expr: SELECT BLANK+ name (wspace IN BLANK+ word)? semiel DO wspace* clist semiel DONE -> ^(SELECT name (word)? clist)
;
if_expr : IF wspace+ ag=clist semiel THEN wspace+ iflist=clist semiel EOL* (elif_expr)* (ELSE wspace+ else_list=clist semiel EOL*)? FI
- -> ^(IF $ag $iflist (elif_expr)* ^($else_list)?)
+ -> ^(IF_STATEMENT ^(IF $ag $iflist) (elif_expr)* ^(ELSE $else_list)?)
;
elif_expr
: ELIF BLANK+ ag=clist semiel THEN wspace+ iflist=clist semiel -> ^(IF["if"] $ag $iflist);
@@ -208,7 +213,7 @@ case_body
: case_stmt (wspace* DOUBLE_SEMIC case_stmt)* wspace* DOUBLE_SEMIC? wspace* -> case_stmt*;
case_stmt
: wspace* (LPAREN BLANK*)? case_pattern (BLANK* PIPE BLANK? case_pattern)* BLANK* RPAREN (wspace* clist)?
- -> ^(CASE_PATTERN case_pattern+ clist?);
+ -> ^(CASE_PATTERN case_pattern+ (CASE_COMMAND clist)?);
case_pattern
: command_sub
| fname
@@ -334,7 +339,7 @@ builtin_cond_primary
| builtin_cond_unary
| fname;
builtin_cond_binary
- : cond_part BLANK!* binary_string_op_builtin^ BLANK!? cond_part;
+ : cond_part BLANK!* binary_string_op_builtin^ BLANK!* cond_part;
builtin_cond_unary
: uop^ BLANK!+ cond_part;
keyword_cond
@@ -354,8 +359,9 @@ binary_str_op_keyword
| GREATER_THAN;
binary_string_op_builtin
: bop
+ | EQUALS EQUALS -> EQUALS
| EQUALS
- | BANG EQUALS -> OP["!="]
+ | BANG EQUALS -> NOT_EQUALS
| ESC_LT
| ESC_GT;
bop : MINUS! NAME^;
@@ -364,11 +370,7 @@ unary_cond
uop : MINUS! LETTER;
//Allowable parts of conditions
cond_part: brace_expansion
- | var_ref
- | res_word_str -> ^(STRING res_word_str)
- | num
- | fname
- | arithmetic;
+ | fname;
//Rules for whitespace/line endings
wspace : BLANK+|EOL+;
semiel : BLANK* (SEMIC|EOL) BLANK*;
@@ -651,8 +653,7 @@ COLON : ':';
QMARK : '?';
//Operators for conditional statements
TEST_EXPR : 'test';
-LOGICAND
- : '&&';
+LOGICAND : '&&';
LOGICOR : '||';
//Tokens for strings
CONTINUE_LINE
diff --git a/bashast/features_script/features.sh.ast b/bashast/features_script/features.sh.ast
index 59e7eed..b9b6c62 100644
--- a/bashast/features_script/features.sh.ast
+++ b/bashast/features_script/features.sh.ast
@@ -1 +1 @@
-(LIST (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)))))) (function (STRING do_some_arith) (CURRENT_SHELL (LIST (COMPOUND_ARITH (* 5 4)) (COMPOUND_ARITH (** 5 4)) (COMPOUND_ARITH (+ (VAR_REF (VAR_REF failedtests)) (/ 5 4))) (COMPOUND_ARITH (+ (VAR_REF (VAR_REF z)) (MINUS_SIGN 3)))))) (function (STRING arrays) (SUBSHELL (LIST (VARIABLE_DEFINITIONS (= asdf (ARRAY (STRING a) (STRING b) (STRING c) (STRING d)))) (COMMAND (STRING echo) (STRING (VAR_REF (asdf 3)))) (VARIABLE_DEFINITIONS (= foo (ARRAY (STRING (COMMAND_SUB (LIST (COMMAND (STRING echo) (STRING 6))))) (STRING b) (STRING c) (STRING d)))) (VARIABLE_DEFINITIONS (= (arr (VAR_REF foo)) (STRING 3))) (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 (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 (LIST (COMMAND (STRING echo) (STRING foobar)))))) (| (COMMAND (STRING ls)) (COMMAND (STRING grep) (STRING gunit) (REDIR >> (STRING filelist)))) (case (COMMAND_SUB (LIST (COMMAND (STRING echo) (STRING asdf)))) (CASE_PATTERN (STRING gz) (LIST (COMMAND (STRING echo) (STRING yay)))) (CASE_PATTERN (STRING bzip) (LIST (COMMAND (STRING echo) (STRING three)))) (CASE_PATTERN (STRING *) (LIST (COMMAND (STRING echo) (STRING woo))))) (for each (STRING (COMMAND_SUB (LIST (| (COMMAND (STRING ls)) (COMMAND (STRING grep) (STRING log)))))) (LIST (COMMAND (STRING echo) (STRING (VAR_REF each))) (COMMAND (STRING cat) (STRING each)))) (for (FOR_INIT (+ 5 3)) (FOR_COND (+ 6 2)) (FOR_MOD (+ 3 1)) (LIST (COMMAND (STRING echo) (STRING yay)))) (select each (COMMAND_SUB (LIST (| (COMMAND (STRING ls)) (COMMAND (STRING grep) (STRING output))))) (LIST (COMMAND (STRING echo) (STRING asdf) (STRING 2) (REDIR > (STRING / dev / null))))) (if (LIST (COMMAND (STRING echo) (STRING yay2))) (LIST (COMMAND (STRING echo) (STRING yay)))) (until (LIST (COMPOUND_COND (KEYWORD_TEST (a (STRING this / is . afile))))) (LIST (COMMAND (STRING touch) (STRING this / is . afile)))) (while (LIST (COMPOUND_COND (BUILTIN_TEST (n (STRING foobar))))) (LIST (COMMAND (STRING echo) (STRING (DOUBLE_QUOTED_STRING file found))))) (if (LIST (COMPOUND_COND (BUILTIN_TEST (eq 5 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))) (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))))) (VARIABLE_DEFINITIONS (= MY_PN (STRING (VAR_REF (REPLACE_FIRST PN (STRING asterisk -)))))) (| (COMMAND (STRING cat) (STRING asdf)) (COMMAND (STRING grep) (STRING three) (STRING 2) (REDIR >& 1) (REDIR > (STRING / dev / null)))) (COMMAND (STRING echo) (STRING asdf) (REDIR >> (STRING APPEND))) (COMMAND (STRING echo) (STRING cat) (<<< (STRING word))))
+(LIST (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)))))) (function (STRING do_some_arith) (CURRENT_SHELL (LIST (COMPOUND_ARITH (* 5 4)) (COMPOUND_ARITH (** 5 4)) (COMPOUND_ARITH (+ (VAR_REF (VAR_REF failedtests)) (/ 5 4))) (COMPOUND_ARITH (+ (VAR_REF (VAR_REF z)) (MINUS_SIGN 3)))))) (function (STRING arrays) (SUBSHELL (LIST (VARIABLE_DEFINITIONS (= asdf (ARRAY (STRING a) (STRING b) (STRING c) (STRING d)))) (COMMAND (STRING echo) (STRING (VAR_REF (asdf 3)))) (VARIABLE_DEFINITIONS (= foo (ARRAY (STRING (COMMAND_SUB (LIST (COMMAND (STRING echo) (STRING 6))))) (STRING b) (STRING c) (STRING d)))) (VARIABLE_DEFINITIONS (= (arr (VAR_REF foo)) (STRING 3))) (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 (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 (LIST (COMMAND (STRING echo) (STRING foobar)))))) (| (COMMAND (STRING ls)) (COMMAND (STRING grep) (STRING gunit) (REDIR >> (STRING filelist)))) (case (COMMAND_SUB (LIST (COMMAND (STRING echo) (STRING asdf)))) (CASE_PATTERN (STRING gz) CASE_COMMAND (LIST (COMMAND (STRING echo) (STRING yay)))) (CASE_PATTERN (STRING bzip) CASE_COMMAND (LIST (COMMAND (STRING echo) (STRING three)))) (CASE_PATTERN (STRING *) CASE_COMMAND (LIST (COMMAND (STRING echo) (STRING woo))))) (for each (STRING (COMMAND_SUB (LIST (| (COMMAND (STRING ls)) (COMMAND (STRING grep) (STRING log)))))) (LIST (COMMAND (STRING echo) (STRING (VAR_REF each))) (COMMAND (STRING cat) (STRING each)))) (CFOR (FOR_INIT (+ 5 3)) (FOR_COND (+ 6 2)) (LIST (COMMAND (STRING echo) (STRING yay))) (FOR_MOD (+ 3 1))) (select each (COMMAND_SUB (LIST (| (COMMAND (STRING ls)) (COMMAND (STRING grep) (STRING output))))) (LIST (COMMAND (STRING echo) (STRING asdf) (STRING 2) (REDIR > (STRING / dev / null))))) (IF_STATEMENT (if (LIST (COMMAND (STRING echo) (STRING yay2))) (LIST (COMMAND (STRING echo) (STRING yay))))) (until (LIST (COMPOUND_COND (KEYWORD_TEST (a (STRING this / is . afile))))) (LIST (COMMAND (STRING touch) (STRING this / is . afile)))) (while (LIST (COMPOUND_COND (BUILTIN_TEST (n (STRING foobar))))) (LIST (COMMAND (STRING echo) (STRING (DOUBLE_QUOTED_STRING file found))))) (IF_STATEMENT (if (LIST (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))) (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))))) (VARIABLE_DEFINITIONS (= MY_PN (STRING (VAR_REF (REPLACE_FIRST PN (STRING asterisk -)))))) (| (COMMAND (STRING cat) (STRING asdf)) (COMMAND (STRING grep) (STRING three) (STRING 2) (REDIR >& 1) (REDIR > (STRING / dev / null)))) (COMMAND (STRING echo) (STRING asdf) (REDIR >> (STRING APPEND))) (COMMAND (STRING echo) (STRING cat) (<<< (STRING word))))
diff --git a/bashast/gunit/compound.gunit b/bashast/gunit/compound.gunit
index f999b44..398bb3d 100644
--- a/bashast/gunit/compound.gunit
+++ b/bashast/gunit/compound.gunit
@@ -65,7 +65,7 @@ echo three
;;
*) echo woo
;;
-esac" -> (case (COMMAND_SUB (LIST (COMMAND (STRING echo) (STRING asdf)))) (CASE_PATTERN (STRING gz) (LIST (COMMAND (STRING echo) (STRING yay)))) (CASE_PATTERN (STRING bzip) (LIST (COMMAND (STRING echo) (STRING three)))) (CASE_PATTERN (STRING *) (LIST (COMMAND (STRING echo) (STRING woo)))))
+esac" -> (case (COMMAND_SUB (LIST (COMMAND (STRING echo) (STRING asdf)))) (CASE_PATTERN (STRING gz) CASE_COMMAND (LIST (COMMAND (STRING echo) (STRING yay)))) (CASE_PATTERN (STRING bzip) CASE_COMMAND (LIST (COMMAND (STRING echo) (STRING three)))) (CASE_PATTERN (STRING *) CASE_COMMAND (LIST (COMMAND (STRING echo) (STRING woo)))))
"case `echo asdf` in
gz)
@@ -75,10 +75,10 @@ esac" -> (case (COMMAND_SUB (LIST (COMMAND (STRING echo) (STRING asdf)))) (CASE_
echo three
;;
*) echo woo
-esac" -> (case (COMMAND_SUB (LIST (COMMAND (STRING echo) (STRING asdf)))) (CASE_PATTERN (STRING gz) (LIST (COMMAND (STRING echo) (STRING yay)))) (CASE_PATTERN (STRING bzip) (LIST (COMMAND (STRING echo) (STRING three)))) (CASE_PATTERN (STRING *) (LIST (COMMAND (STRING echo) (STRING woo)))))
+esac" -> (case (COMMAND_SUB (LIST (COMMAND (STRING echo) (STRING asdf)))) (CASE_PATTERN (STRING gz) CASE_COMMAND (LIST (COMMAND (STRING echo) (STRING yay)))) (CASE_PATTERN (STRING bzip) CASE_COMMAND (LIST (COMMAND (STRING echo) (STRING three)))) (CASE_PATTERN (STRING *) CASE_COMMAND (LIST (COMMAND (STRING echo) (STRING woo)))))
"case `echo asdf` in gz|asdf) echo yay ;; bzip) echo three ;; *) echo woo esac" FAIL
-"case `echo asdf` in gz|asdf) echo yay ;; bzip) echo three ;; *) echo woo ;; esac" -> (case (COMMAND_SUB (LIST (COMMAND (STRING echo) (STRING asdf)))) (CASE_PATTERN (STRING gz) (STRING asdf) (LIST (COMMAND (STRING echo) (STRING yay)))) (CASE_PATTERN (STRING bzip) (LIST (COMMAND (STRING echo) (STRING three)))) (CASE_PATTERN (STRING *) (LIST (COMMAND (STRING echo) (STRING woo)))))
+"case `echo asdf` in gz|asdf) echo yay ;; bzip) echo three ;; *) echo woo ;; esac" -> (case (COMMAND_SUB (LIST (COMMAND (STRING echo) (STRING asdf)))) (CASE_PATTERN (STRING gz) (STRING asdf) CASE_COMMAND (LIST (COMMAND (STRING echo) (STRING yay)))) (CASE_PATTERN (STRING bzip) CASE_COMMAND (LIST (COMMAND (STRING echo) (STRING three)))) (CASE_PATTERN (STRING *) CASE_COMMAND (LIST (COMMAND (STRING echo) (STRING woo)))))
for_expr:
"for each in `ls |grep log`; do
@@ -89,10 +89,10 @@ done" -> (for each (STRING (COMMAND_SUB (LIST (| (COMMAND (STRING ls)) (COMMAND
"for i in foo$var bar; do echo $i; done" -> (for i (STRING foo (VAR_REF var)) (STRING bar) (LIST (COMMAND (STRING echo) (STRING (VAR_REF i)))))
"for each in `ls |grep log`; do echo file done" FAIL
-"for ((5+3;5+3;5+3)); do echo yay; done" -> (for (FOR_INIT (+ 5 3)) (FOR_COND (+ 5 3)) (FOR_MOD (+ 5 3)) (LIST (COMMAND (STRING echo) (STRING yay))))
-"for ((5+3; ;5+3)); do echo yay; done" -> (for (FOR_INIT (+ 5 3)) (FOR_MOD (+ 5 3)) (LIST (COMMAND (STRING echo) (STRING yay))))
-"for ((;5+3 ;5+3)); do echo yay; done" -> (for (FOR_COND (+ 5 3)) (FOR_MOD (+ 5 3)) (LIST (COMMAND (STRING echo) (STRING yay))))
-"for ((5+3;;5+3)); do echo yay; done" -> (for (FOR_INIT (+ 5 3)) (FOR_MOD (+ 5 3)) (LIST (COMMAND (STRING echo) (STRING yay))))
+"for ((5+3;5+3;5+3)); do echo yay; done" -> (CFOR (FOR_INIT (+ 5 3)) (FOR_COND (+ 5 3)) (LIST (COMMAND (STRING echo) (STRING yay))) (FOR_MOD (+ 5 3)))
+"for ((5+3; ;5+3)); do echo yay; done" -> (CFOR (FOR_INIT (+ 5 3)) (LIST (COMMAND (STRING echo) (STRING yay))) (FOR_MOD (+ 5 3)))
+"for ((;5+3 ;5+3)); do echo yay; done" -> (CFOR (FOR_COND (+ 5 3)) (LIST (COMMAND (STRING echo) (STRING yay))) (FOR_MOD (+ 5 3)))
+"for ((5+3;;5+3)); do echo yay; done" -> (CFOR (FOR_INIT (+ 5 3)) (LIST (COMMAND (STRING echo) (STRING yay))) (FOR_MOD (+ 5 3)))
sel_expr:
@@ -105,15 +105,15 @@ sel_expr:
if_expr:
"if echo yay2; then
echo yay
-fi" -> (if (LIST (COMMAND (STRING echo) (STRING yay2))) (LIST (COMMAND (STRING echo) (STRING yay))))
-"if echo yay2; then echo yay ;fi" -> (if (LIST (COMMAND (STRING echo) (STRING yay2))) (LIST (COMMAND (STRING echo) (STRING yay))))
+fi" -> (IF_STATEMENT (if (LIST (COMMAND (STRING echo) (STRING yay2))) (LIST (COMMAND (STRING echo) (STRING yay)))))
+"if echo yay2; then echo yay ;fi" -> (IF_STATEMENT (if (LIST (COMMAND (STRING echo) (STRING yay2))) (LIST (COMMAND (STRING echo) (STRING yay)))))
"if echo yay2 then echo yay; fi" FAIL
"if echo yay2; then
echo yay
elif echo yay3; then
echo boo
-fi" -> (if (LIST (COMMAND (STRING echo) (STRING yay2))) (LIST (COMMAND (STRING echo) (STRING yay))) (if (LIST (COMMAND (STRING echo) (STRING yay3))) (LIST (COMMAND (STRING echo) (STRING boo)))))
+fi" -> (IF_STATEMENT (if (LIST (COMMAND (STRING echo) (STRING yay2))) (LIST (COMMAND (STRING echo) (STRING yay)))) (if (LIST (COMMAND (STRING echo) (STRING yay3))) (LIST (COMMAND (STRING echo) (STRING boo)))))
"if echo yay2; then
echo yay
@@ -121,7 +121,7 @@ elif echo yay3; then
echo boo
elif echo yay4; then echo hurrah
else echo darn
-fi" -> (if (LIST (COMMAND (STRING echo) (STRING yay2))) (LIST (COMMAND (STRING echo) (STRING yay))) (if (LIST (COMMAND (STRING echo) (STRING yay3))) (LIST (COMMAND (STRING echo) (STRING boo)))) (if (LIST (COMMAND (STRING echo) (STRING yay4))) (LIST (COMMAND (STRING echo) (STRING hurrah)))) (LIST (COMMAND (STRING echo) (STRING darn))))
+fi" -> (IF_STATEMENT (if (LIST (COMMAND (STRING echo) (STRING yay2))) (LIST (COMMAND (STRING echo) (STRING yay)))) (if (LIST (COMMAND (STRING echo) (STRING yay3))) (LIST (COMMAND (STRING echo) (STRING boo)))) (if (LIST (COMMAND (STRING echo) (STRING yay4))) (LIST (COMMAND (STRING echo) (STRING hurrah)))) (else (LIST (COMMAND (STRING echo) (STRING darn)))))
while_expr:
"while echo true; do
@@ -147,20 +147,20 @@ case_expr:
echo \"Usage: $0 start|stop\" >&2
exit 3
;;
-esac" -> (case (STRING (DOUBLE_QUOTED_STRING (VAR_REF 1))) (CASE_PATTERN (STRING *) (LIST (COMMAND (STRING echo) (STRING (DOUBLE_QUOTED_STRING Usage : (VAR_REF 0) start | stop)) (REDIR >& 2)) (COMMAND (STRING exit) (STRING 3)))))
+esac" -> (case (STRING (DOUBLE_QUOTED_STRING (VAR_REF 1))) (CASE_PATTERN (STRING *) CASE_COMMAND (LIST (COMMAND (STRING echo) (STRING (DOUBLE_QUOTED_STRING Usage : (VAR_REF 0) start | stop)) (REDIR >& 2)) (COMMAND (STRING exit) (STRING 3)))))
"case $asdf in
a)
echo \"yay\"
;;
-esac" -> (case (VAR_REF asdf) (CASE_PATTERN (STRING a) (LIST (COMMAND (STRING echo) (STRING (DOUBLE_QUOTED_STRING yay))))))
+esac" -> (case (VAR_REF asdf) (CASE_PATTERN (STRING a) CASE_COMMAND (LIST (COMMAND (STRING echo) (STRING (DOUBLE_QUOTED_STRING yay))))))
"case asdf in
asdf)
echo \"yay\"
;;
-esac" -> (case (STRING asdf) (CASE_PATTERN (STRING asdf) (LIST (COMMAND (STRING echo) (STRING (DOUBLE_QUOTED_STRING yay))))))
-"case 1 in 1) echo yay ;; esac" -> (case 1 (CASE_PATTERN (STRING 1) (LIST (COMMAND (STRING echo) (STRING yay)))))
-"case /usr/bin in 1) echo yay ;; esac" -> (case (STRING / usr / bin) (CASE_PATTERN (STRING 1) (LIST (COMMAND (STRING echo) (STRING yay)))))
+esac" -> (case (STRING asdf) (CASE_PATTERN (STRING asdf) CASE_COMMAND (LIST (COMMAND (STRING echo) (STRING (DOUBLE_QUOTED_STRING yay))))))
+"case 1 in 1) echo yay ;; esac" -> (case 1 (CASE_PATTERN (STRING 1) CASE_COMMAND (LIST (COMMAND (STRING echo) (STRING yay)))))
+"case /usr/bin in 1) echo yay ;; esac" -> (case (STRING / usr / bin) (CASE_PATTERN (STRING 1) CASE_COMMAND (LIST (COMMAND (STRING echo) (STRING yay)))))
"case \"$1\" in
stop)
;;
@@ -168,4 +168,4 @@ stop)
echo \"Usage: $0 start|stop\" >&2
exit 3
;;
-esac" -> (case (STRING (DOUBLE_QUOTED_STRING (VAR_REF 1))) (CASE_PATTERN (STRING stop)) (CASE_PATTERN (STRING *) (LIST (COMMAND (STRING echo) (STRING (DOUBLE_QUOTED_STRING Usage : (VAR_REF 0) start | stop)) (REDIR >& 2)) (COMMAND (STRING exit) (STRING 3)))))
+esac" -> (case (STRING (DOUBLE_QUOTED_STRING (VAR_REF 1))) (CASE_PATTERN (STRING stop)) (CASE_PATTERN (STRING *) CASE_COMMAND (LIST (COMMAND (STRING echo) (STRING (DOUBLE_QUOTED_STRING Usage : (VAR_REF 0) start | stop)) (REDIR >& 2)) (COMMAND (STRING exit) (STRING 3)))))
diff --git a/bashast/gunit/cond_main.gunit b/bashast/gunit/cond_main.gunit
index b40322d..78ebbf9 100644
--- a/bashast/gunit/cond_main.gunit
+++ b/bashast/gunit/cond_main.gunit
@@ -21,7 +21,10 @@ gunit bashast;
cond_expr:
"[[ -a this/is.afile ]]" -> (KEYWORD_TEST (a (STRING this / is . afile)))
"[ -n \"yar53\" ]" -> (BUILTIN_TEST (n (STRING (DOUBLE_QUOTED_STRING yar53))))
-"test 5 -eq 6" -> (BUILTIN_TEST (eq 5 6))
+"test 5 -eq 6" -> (BUILTIN_TEST (eq (STRING 5) (STRING 6)))
"[[ \"asdf\" != \"boo\" && -a filename ]]" -> (KEYWORD_TEST (&& (!= (STRING (DOUBLE_QUOTED_STRING asdf)) (STRING (DOUBLE_QUOTED_STRING boo))) (a (STRING filename))))
"[[ true ]]" -> (KEYWORD_TEST (STRING true))
"[[ true && (false || three) ]]" -> (KEYWORD_TEST (&& (STRING true) (|| (STRING false) (STRING three))))
+"[ a = b ]" -> (BUILTIN_TEST (= (STRING a) (STRING b)))
+"[ a == b ]" -> (BUILTIN_TEST (= (STRING a) (STRING b)))
+"[ a != b ]" -> (BUILTIN_TEST (NOT_EQUALS (STRING a) (STRING b)))
diff --git a/bashast/gunit/expansions.gunit b/bashast/gunit/expansions.gunit
index 17436e8..c4af25b 100644
--- a/bashast/gunit/expansions.gunit
+++ b/bashast/gunit/expansions.gunit
@@ -22,7 +22,8 @@ clist:
"echo a{b,c,d}" -> (LIST (COMMAND (STRING echo) (STRING a (BRACE_EXP (STRING b) (STRING c) (STRING d)))))
"((5+5))" -> (LIST (COMPOUND_ARITH (+ 5 5)))
"(( 4 + asdf ))" -> (LIST (COMPOUND_ARITH (+ 4 (VAR_REF asdf))))
-"[[ while=while ]] && echo true" -> (LIST (&& (COMPOUND_COND (KEYWORD_TEST (= (STRING while) (STRING while)))) (COMMAND (STRING echo) (STRING true))))
+"[[ while=while ]] && echo true" -> (LIST (&& (COMPOUND_COND (KEYWORD_TEST (STRING while = while))) (COMMAND (STRING echo) (STRING true))))
+"[[ while = while ]] && echo true" -> (LIST (&& (COMPOUND_COND (KEYWORD_TEST (= (STRING while) (STRING while)))) (COMMAND (STRING echo) (STRING true))))
"for each in `ls |grep output`; do
echo $each
done" -> (LIST (for each (STRING (COMMAND_SUB (LIST (| (COMMAND (STRING ls)) (COMMAND (STRING grep) (STRING output)))))) (LIST (COMMAND (STRING echo) (STRING (VAR_REF each))))))
diff --git a/bashast/gunit/pipeline.gunit b/bashast/gunit/pipeline.gunit
index f922ca5..8101566 100644
--- a/bashast/gunit/pipeline.gunit
+++ b/bashast/gunit/pipeline.gunit
@@ -28,5 +28,5 @@ pipeline:
"time -p cat file |grep search >> log" -> (| (COMMAND (STRING cat) (STRING file) (time -p)) (COMMAND (STRING grep) (STRING search) (REDIR >> (STRING log))))
"if time cat; then
echo \"three\"
-fi" -> (if (LIST (COMMAND (STRING cat) time)) (LIST (COMMAND (STRING echo) (STRING (DOUBLE_QUOTED_STRING three)))))
+fi" -> (IF_STATEMENT (if (LIST (COMMAND (STRING cat) time)) (LIST (COMMAND (STRING echo) (STRING (DOUBLE_QUOTED_STRING three))))))
"i=1 j=2" -> (VARIABLE_DEFINITIONS (= i (STRING 1)) (= j (STRING 2)))
diff --git a/bashast/libbashWalker.g b/bashast/libbashWalker.g
index b6123d9..b8fd25a 100644
--- a/bashast/libbashWalker.g
+++ b/bashast/libbashWalker.g
@@ -64,26 +64,28 @@ options
index = value;
}
- // Recursively count number of nodes of curr
- static int count_nodes(pANTLR3_BASE_TREE_ADAPTOR adaptor, pANTLR3_BASE_TREE curr)
+ // seek to LT(2) and consume
+ static void seek_to_next_tree(plibbashWalker ctx)
{
- int child_count = adaptor->getChildCount(adaptor, curr);
- if(child_count == 0)
- {
- // Leaf node
- return 1;
- }
- else
+ // We start from LA(1)
+ int index = 1;
+ // Current depth of the tree we are traversing
+ int depth = 1;
+
+ for(index = 1; depth != 0; ++index)
{
- int result = 0;
- // Count every child
- for(int i = 0; i != child_count; ++i)
- result += count_nodes(adaptor, (pANTLR3_BASE_TREE)(adaptor->getChild(adaptor, curr, i)));
- // Add itself, DOWN and UP
- return result + 3;
+ // Go one level done if we encounter DOWN
+ if(LA(index) == DOWN)
+ ++depth;
+ // Go one level up if we encounter UP. When depth==0, we finishe one node
+ else if(LA(index) == UP)
+ --depth;
}
- }
+ // Seek to the correct offset and consume.
+ SEEK(INDEX() + index - 3);
+ CONSUME();
+ }
}
start: list|EOF;
@@ -265,11 +267,18 @@ var_ref [bool double_quoted] returns[std::string libbash_value]
else
walker->get_all_elements(libbash_string, $libbash_value);
}
+ |^(VAR_REF TIMES) { std::cerr << "$* has not been implemented yet" << std::endl; }
+ |^(VAR_REF AT) { std::cerr << "$@ has not been implemented yet" << std::endl; }
+ |^(VAR_REF POUND) { std::cerr << "$# has not been implemented yet" << std::endl; }
+ |^(VAR_REF QMARK) { $libbash_value = walker->get_status<std::string>(); }
+ |^(VAR_REF MINUS) { std::cerr << "$- has not been implemented yet" << std::endl; }
+ |^(VAR_REF BANG) { std::cerr << "$! has not been implemented yet" << std::endl; }
|^(VAR_REF libbash_string=var_expansion) { $libbash_value = libbash_string; };
command
:variable_definitions
- |simple_command;
+ |simple_command
+ |compound_command;
simple_command
@declarations {
@@ -277,28 +286,29 @@ simple_command
}
:^(COMMAND string_expr (argument[libbash_args])* var_def*) {
if(walker->has_function($string_expr.libbash_value))
- walker->call($string_expr.libbash_value,
- libbash_args,
- ctx,
- compound_command);
+ {
+ walker->set_status(walker->call($string_expr.libbash_value,
+ libbash_args,
+ ctx,
+ compound_command));
+ }
else if(cppbash_builtin::is_builtin($string_expr.libbash_value))
- walker->execute_builtin($string_expr.libbash_value, libbash_args);
+ {
+ walker->set_status(walker->execute_builtin($string_expr.libbash_value, libbash_args));
+ }
else
+ {
std::cerr << $string_expr.libbash_value << " is not supported yet" << std::endl;
+ walker->set_status(1);
+ }
};
argument[std::vector<std::string>& args]
: string_expr {
if($string_expr.quoted)
- {
args.push_back($string_expr.libbash_value);
- }
else
- {
- std::vector<std::string> arguments;
- walker->split_word($string_expr.libbash_value, arguments);
- args.insert(args.end(), arguments.begin(), arguments.end());
- }
+ walker->split_word($string_expr.libbash_value, args);
};
logic_command_list
@@ -308,7 +318,216 @@ logic_command_list
command_list: ^(LIST logic_command_list+);
-compound_command: ^(CURRENT_SHELL command_list);
+compound_command
+ : ^(CURRENT_SHELL command_list)
+ | ^(COMPOUND_COND cond_expr)
+ | for_expr
+ | while_expr
+ | if_expr
+ | case_expr;
+
+cond_expr
+ :^(BUILTIN_TEST status=builtin_condition) { walker->set_status(!status); };
+
+builtin_condition returns[bool status]
+ :^(NEGATION l=builtin_condition) { $status = !l; }
+ |s=builtin_condition_primary { $status = s; };
+
+builtin_condition_primary returns[bool status]
+ :^(NAME string_expr string_expr) { throw interpreter_exception(walker->get_string($NAME) + "(NAME) is not supported for now");}
+ |^(EQUALS l=string_expr r=string_expr) { $status = (l.libbash_value == r.libbash_value); }
+ |^(NOT_EQUALS l=string_expr r=string_expr) { $status = (l.libbash_value != r.libbash_value); }
+ |^(ESC_LT l=string_expr r=string_expr) { $status = (l.libbash_value < r.libbash_value); }
+ |^(ESC_GT l=string_expr r=string_expr) { $status = (l.libbash_value > r.libbash_value); }
+ |^(LETTER l=string_expr) { throw interpreter_exception(walker->get_string($LETTER) + "(LETTER) is not supported for now");}
+ |string_expr { $status = ($string_expr.libbash_value.size() != 0); };
+
+for_expr
+@declarations {
+ ANTLR3_MARKER commands_index;
+ std::vector<std::string> splitted_values;
+
+ ANTLR3_MARKER condition_index;
+}
+ :^(FOR libbash_string=name_base
+ // Empty value as $@ is not supported currently
+ (string_expr
+ {
+ // Word splitting happens here
+ if($string_expr.quoted)
+ splitted_values.push_back($string_expr.libbash_value);
+ else
+ walker->split_word($string_expr.libbash_value, splitted_values);
+ }
+ )+
+ {
+ commands_index = INDEX();
+ for(auto iter = splitted_values.begin(); iter != splitted_values.end(); ++iter)
+ {
+ SEEK(commands_index);
+ walker->set_value(libbash_string, *iter);
+ command_list(ctx);
+ }
+ })
+ |^(CFOR {
+ // omit the first DOWN token for for_INIT
+ SEEK(INDEX() + 1);
+
+ if(LA(1) == FOR_INIT)
+ for_initilization(ctx);
+
+ condition_index = INDEX();
+ bool has_condition = (LA(1) != FOR_COND);
+ while(has_condition || for_condition(ctx))
+ {
+ command_list(ctx);
+ if(LA(1) == FOR_MOD)
+ for_modification(ctx);
+ SEEK(condition_index);
+ }
+
+ // Get out of the loop
+ // We are standing right after for_condition, we need to skip the command_list and optional for_modification
+ seek_to_next_tree(ctx);
+ if(LA(1) == FOR_MOD)
+ seek_to_next_tree(ctx);
+
+ // omit the last UP token
+ SEEK(INDEX() + 1);
+ });
+
+for_initilization
+ :^(FOR_INIT arithmetics);
+
+for_condition returns[int libbash_value]
+ :^(FOR_COND condition=arithmetics) { libbash_value = condition; };
+
+for_modification
+ :^(FOR_MOD arithmetics);
+
+while_expr
+@declarations {
+ ANTLR3_MARKER command_index;
+ bool negate;
+}
+ :^((WHILE { negate = false; } | UNTIL { negate = true; }) {
+ // omit the first DOWN token
+ SEEK(INDEX() + 1);
+
+ command_index = INDEX();
+ while(true)
+ {
+ command_list(ctx);
+ if(walker->get_status() == (negate? 0 : 1))
+ break;
+ command_list(ctx);
+ SEEK(command_index);
+ }
+ // Skip the body and get out
+ seek_to_next_tree(ctx);
+
+ // omit the last UP token
+ SEEK(INDEX() + 1);
+ });
+
+if_expr
+@declarations {
+ bool matched = false;
+}
+ :^(IF_STATEMENT {
+ // omit the first DOWN token
+ SEEK(INDEX() + 1);
+
+ while(LA(1) == IF)
+ {
+ if(matched)
+ seek_to_next_tree(ctx);
+ else
+ matched = elif_expr(ctx);
+ }
+
+ if(LA(1) == ELSE)
+ {
+ if(matched == false)
+ {
+ // omit the ELSE DOWN tokens
+ SEEK(INDEX() + 2);
+
+ command_list(ctx);
+
+ // omit the last UP token
+ SEEK(INDEX() + 1);
+ }
+ else
+ {
+ seek_to_next_tree(ctx);
+ }
+ }
+
+ // omit the last UP token
+ SEEK(INDEX() + 1);
+ });
+
+elif_expr returns[bool matched]
+ :^(IF {
+ // omit the first DOWN token
+ SEEK(INDEX() + 1);
+
+ command_list(ctx);
+ if(walker->get_status() == 0)
+ {
+ $matched=true;
+ command_list(ctx);
+ }
+ else
+ {
+ $matched=false;
+ seek_to_next_tree(ctx);
+ }
+
+ // omit the last UP token
+ SEEK(INDEX() + 1);
+ });
+
+case_expr
+ :^(CASE libbash_string=word (matched=case_clause[libbash_string]{
+ if(matched)
+ {
+ while(LA(1) == CASE_PATTERN)
+ seek_to_next_tree(ctx);
+ }
+ })*);
+
+case_clause[const std::string& target] returns[bool matched]
+@declarations {
+ std::vector<std::string> patterns;
+}
+ :^(CASE_PATTERN (libbash_string=case_pattern { patterns.push_back(libbash_string); })+ {
+ if(LA(1) == CASE_COMMAND)
+ {
+ // omit CASE_COMMAND
+ SEEK(INDEX() + 1);
+ matched = false;
+ for(auto iter = patterns.begin(); iter != patterns.end(); ++iter)
+ {
+ // pattern matching should happen here in future
+ if(*iter == "*" || *iter == target)
+ {
+ command_list(ctx);
+ $matched = true;
+ }
+ else
+ {
+ seek_to_next_tree(ctx);
+ }
+ }
+ }
+ });
+
+case_pattern returns[std::string libbash_value]
+ :libbash_string=command_substitution { $libbash_value = libbash_string; }
+ |string_expr { $libbash_value = $string_expr.libbash_value; }
+ |TIMES { $libbash_value = "*"; };
command_substitution returns[std::string libbash_value]
@declarations {
@@ -324,11 +543,8 @@ function_def returns[int placeholder]
:^(FUNCTION ^(STRING name) {
// Define the function with current index
walker->define_function($name.libbash_value, INDEX());
- // Skip the AST for function body, minus one is needed to make the offset right.
- // LT(1) is the function body. It should match the compound_command rule.
- SEEK(INDEX() + count_nodes(ADAPTOR, LT(1)) - 1);
- // After seeking ahead, we need to call CONSUME to eat all the nodes we've skipped.
- CONSUME();
+ // Skip the AST for function body
+ seek_to_next_tree(ctx);
});
// Only used in arithmetic expansion
diff --git a/scripts/compound_command.bash b/scripts/compound_command.bash
new file mode 100644
index 0000000..6365fbe
--- /dev/null
+++ b/scripts/compound_command.bash
@@ -0,0 +1,112 @@
+for file in " foo bar "
+do
+ echo $file
+done
+
+for foo in abc def ghi
+do
+ echo $foo
+done
+
+for (( i=1; i<4; ++i ))
+do
+ echo $i
+done
+
+for ((;i<10;))
+do
+ echo $((++i))
+done
+
+for ((;i<0;))
+do
+ echo "Shouldn't print this"
+done
+
+i=0;
+while [ $i != 4 ]
+do
+ i=$(( i + 1 ))
+ echo $i
+done
+
+while [ $i \< 0 ]
+do
+ echo "Shouldn't print this"
+done
+
+i=0;
+until [ $i == 4 ]
+do
+ i=$(( i + 1 ))
+ echo $i
+done
+
+until [ $i \> 0 ]
+do
+ echo "Shouldn't print this"
+done
+
+a=1
+b=2
+if [ $a == $b ]
+then
+ echo "Shouldn't print this"
+fi
+if [ $a != $b ]
+then
+ echo $a
+fi
+
+if [ $a == $b ]
+then
+ echo "Shouldn't print this"
+elif [ $a != $b ]
+then
+ echo $b
+fi
+
+if [ $a == $b ]
+then
+ echo "Shouldn't print this"
+else
+ echo $a
+fi
+
+if [ $a == $b ]
+then
+ echo "Shouldn't print this"
+elif [ $a == $b ]
+then
+ echo "Shouldn't print this"
+else
+ echo $a
+fi
+
+target=123
+case $target in
+ bcd)
+ echo "Shouldn't print this"
+ ;;
+ abc)
+ echo "Shouldn't print this"
+ ;;
+ 123)
+ echo yep
+ ;;
+ 123)
+ echo "Shouldn't print this"
+ ;;
+esac
+case $target in
+ bcd)
+ echo "Shouldn't print this"
+ ;;
+ abc)
+ echo "Shouldn't print this"
+ ;;
+ *)
+ echo "default"
+ ;;
+esac
+echo "case end"
diff --git a/scripts/compound_command.bash.result b/scripts/compound_command.bash.result
new file mode 100644
index 0000000..69d693d
--- /dev/null
+++ b/scripts/compound_command.bash.result
@@ -0,0 +1,34 @@
+foo bar
+abc
+def
+ghi
+1
+2
+3
+5
+6
+7
+8
+9
+10
+1
+2
+3
+4
+1
+2
+3
+4
+1
+2
+1
+1
+yep
+default
+case end
+a=1
+b=2
+file= foo bar
+foo=ghi
+i=4
+target=123
diff --git a/scripts/test_expr.bash b/scripts/test_expr.bash
new file mode 100644
index 0000000..95acd36
--- /dev/null
+++ b/scripts/test_expr.bash
@@ -0,0 +1,26 @@
+[ a = b ]
+echo $? # 1
+test a = a
+echo $? # 0
+#[ ]
+#echo $? # 1
+[ abc ]
+echo $? # 0
+[ ! abc ]
+echo $? # 1
+#[ ! ]
+#echo $?
+#[ abc -a bcd ]
+#echo $?
+#[ abc -o bcd ]
+#echo $?
+test abc == abd
+echo $? # 1
+[ abc != bcd ]
+echo $? # 0
+[ abc != abc ]
+echo $? # 1
+[ abc \> bcd ]
+echo $? # 1
+[ abc \< bcd ]
+echo $? # 0
diff --git a/scripts/test_expr.bash.result b/scripts/test_expr.bash.result
new file mode 100644
index 0000000..ff52ae4
--- /dev/null
+++ b/scripts/test_expr.bash.result
@@ -0,0 +1,9 @@
+1
+0
+0
+1
+1
+0
+1
+1
+0
diff --git a/scripts/var_def.bash b/scripts/var_def.bash
index 56f8f8d..9b27dc3 100644
--- a/scripts/var_def.bash
+++ b/scripts/var_def.bash
@@ -35,3 +35,9 @@ ARRAY10="${ARRAY05[*]}"
FOO001="networkmanager"
FOO002="0.8.2"
FOO003=${FOO001}-${FOO002}
+FOO004=$*
+FOO004=$@
+FOO004=$#
+FOO004=$?
+FOO004=$-
+FOO004=$!
diff --git a/scripts/var_def.bash.result b/scripts/var_def.bash.result
index 292b9c7..e840ebe 100644
--- a/scripts/var_def.bash.result
+++ b/scripts/var_def.bash.result
@@ -1,3 +1,8 @@
+$* has not been implemented yet
+$@ has not been implemented yet
+$# has not been implemented yet
+$- has not been implemented yet
+$! has not been implemented yet
ARRAY01=1 2 3 4 5
ARRAY02=1 2 4 5
ARRAY03=2 3
@@ -18,6 +23,7 @@ EMPTY_ARRAY=
FOO001=networkmanager
FOO002=0.8.2
FOO003=networkmanager-0.8.2
+FOO004=
HOMEPAGE=http://sunpinyin.googlecode.com
IUSE=
KEYWORDS=~amd64 ~x86
diff --git a/src/core/interpreter.cpp b/src/core/interpreter.cpp
index c156123..9548e8a 100644
--- a/src/core/interpreter.cpp
+++ b/src/core/interpreter.cpp
@@ -71,7 +71,15 @@ void interpreter::get_all_elements_IFS_joined(const std::string& name,
void interpreter::split_word(const std::string& word, std::vector<std::string>& output)
{
const std::string& delimeter = resolve<std::string>("IFS");
- boost::split(output, word, boost::is_any_of(delimeter), boost::token_compress_on);
+ std::string trimmed(word);
+ boost::trim_if(trimmed, boost::is_any_of(delimeter));
+
+ if(trimmed == "")
+ return;
+
+ std::vector<std::string> splitted_values;
+ boost::split(splitted_values, trimmed, boost::is_any_of(delimeter), boost::token_compress_on);
+ output.insert(output.end(), splitted_values.begin(), splitted_values.end());
}
inline void define_function_arguments(std::unique_ptr<scope>& current_stack,
diff --git a/src/core/interpreter.h b/src/core/interpreter.h
index 4f69c62..f2dfbeb 100644
--- a/src/core/interpreter.h
+++ b/src/core/interpreter.h
@@ -478,6 +478,21 @@ public:
return new_value;
}
+ /// \brief set the return status of the last command
+ /// \param the value of the return status
+ void set_status(int status)
+ {
+ set_value("?", status);
+ }
+
+ /// \brief get the return status of the last command
+ /// \param the value of the return status
+ template <typename T=int>
+ T get_status(void)
+ {
+ return resolve<T>("?");
+ }
+
/// \brief define a new global variable
/// \param the name of the variable
/// \param the value of the variable
@@ -649,7 +664,7 @@ public:
/// \brief implementation of word splitting
/// \param the value of the word
- //. \param[out] the splitted result
+ //. \param[out] the splitted result will be appended to output
void split_word(const std::string& word, std::vector<std::string>& output);
/// \brief perform expansion like ${var//foo/bar}
diff --git a/src/core/tests/interpreter_test.cpp b/src/core/tests/interpreter_test.cpp
index ce9d4ad..2e92a22 100644
--- a/src/core/tests/interpreter_test.cpp
+++ b/src/core/tests/interpreter_test.cpp
@@ -147,3 +147,17 @@ TEST(interperter, substring_expansion_exception)
interpreter walker;
EXPECT_THROW(walker.do_substring_expansion("", 0, -1, 0), interpreter_exception);
}
+
+TEST(interpreter, word_split)
+{
+ interpreter walker;
+ std::vector<std::string> splitted_values;
+ walker.split_word(" \n\t", splitted_values);
+ EXPECT_EQ(0, splitted_values.size());
+
+ splitted_values.clear();
+ walker.split_word(" \tfoo\n bar \n", splitted_values);
+ EXPECT_EQ(2, splitted_values.size());
+ EXPECT_STREQ("foo", splitted_values[0].c_str());
+ EXPECT_STREQ("bar", splitted_values[1].c_str());
+}
diff --git a/test/script_compiler.sh b/test/script_compiler.sh
index d409673..021855e 100755
--- a/test/script_compiler.sh
+++ b/test/script_compiler.sh
@@ -4,7 +4,7 @@ declare -i error=0
for script in $@
do
- ./variable_printer $script | diff -u $script.result -
+ ./variable_printer $script 2>&1 | diff -u $script.result -
error+=$?
done
diff --git a/utils/variable_printer.cpp b/utils/variable_printer.cpp
index 192b3db..f06281b 100644
--- a/utils/variable_printer.cpp
+++ b/utils/variable_printer.cpp
@@ -32,6 +32,11 @@
#include "libbash.h"
+static const std::vector<std::string> special_variables
+{
+ "IFS", "?"
+};
+
int main(int argc, char** argv)
{
if(argc != 2)
@@ -46,7 +51,8 @@ int main(int argc, char** argv)
std::map<std::string, std::vector<std::string>> sorted(variables.begin(), variables.end());
// Currently we don't need internal variables
- sorted.erase("IFS");
+ for(auto iter = special_variables.begin(); iter != special_variables.end(); ++iter)
+ sorted.erase(*iter);
using namespace boost::spirit::karma;
std::cout << format((string << '=' << -(string % ' ')) % eol, sorted) << std::endl;