diff options
author | 2012-06-19 17:46:40 +0100 | |
---|---|---|
committer | 2012-07-20 09:20:22 +0800 | |
commit | f9501f5d7ad82d273cab44cd96114d644fb5772d (patch) | |
tree | 8a0639ad40b65f460cdb7409ea94ffc52d7fd67b | |
parent | Replace boost::scoped_ptr with std::unique_ptr (diff) | |
download | libbash-f9501f5d7ad82d273cab44cd96114d644fb5772d.tar.gz libbash-f9501f5d7ad82d273cab44cd96114d644fb5772d.tar.bz2 libbash-f9501f5d7ad82d273cab44cd96114d644fb5772d.zip |
Builtin: Support variable declarations in declare
-rw-r--r-- | bashast/bashast.g | 5 | ||||
-rw-r--r-- | bashast/libbashWalker.g | 5 | ||||
-rw-r--r-- | scripts/command_execution.bash | 3 | ||||
-rw-r--r-- | scripts/var_def.bash | 7 | ||||
-rw-r--r-- | src/builtins/declare_builtin.cpp | 144 | ||||
-rw-r--r-- | src/builtins/tests/declare_tests.cpp | 35 |
6 files changed, 123 insertions, 76 deletions
diff --git a/bashast/bashast.g b/bashast/bashast.g index e2702d0..2d425ce 100644 --- a/bashast/bashast.g +++ b/bashast/bashast.g @@ -398,6 +398,8 @@ command_atom -> ^(STRING EXPORT) ^(STRING builtin_variable_definition_item) | (LOCAL) => LOCAL BLANK builtin_variable_definition_item -> ^(STRING LOCAL) ^(STRING builtin_variable_definition_item) + | (DECLARE) => DECLARE BLANK builtin_variable_definition_item + -> ^(STRING DECLARE) ^(STRING builtin_variable_definition_item) | command_name ( (BLANK? parens) => BLANK? parens wspace? compound_command @@ -782,7 +784,7 @@ string_part ns_string_part : num|name|escaped_character |OTHER|EQUALS|PCT|PCTPCT|PLUS|MINUS|DOT|DOTDOT|COLON - |TILDE|LSQUARE|RSQUARE|CARET|POUND|COMMA|EXPORT|LOCAL|AT + |TILDE|LSQUARE|RSQUARE|CARET|POUND|COMMA|EXPORT|LOCAL|DECLARE|AT // Escaped characters |ESC_RPAREN|ESC_LPAREN|ESC_DOLLAR|ESC_GT|ESC_LT|ESC_TICK|ESC_DQUOTE // The following is for filename expansion @@ -1151,6 +1153,7 @@ QMARK : '?'; LOCAL : 'local'; EXPORT : 'export'; +DECLARE : 'declare'; LOGICAND : '&&'; LOGICOR : '||'; diff --git a/bashast/libbashWalker.g b/bashast/libbashWalker.g index 648dd53..42a8917 100644 --- a/bashast/libbashWalker.g +++ b/bashast/libbashWalker.g @@ -637,7 +637,8 @@ simple_command std::vector<std::string> libbash_args; bool split; } - :string_expr{ split = ($string_expr.libbash_value != "local" && $string_expr.libbash_value != "export"); } + :string_expr{ split = ($string_expr.libbash_value != "local" && $string_expr.libbash_value != "export" + && $string_expr.libbash_value != "declare"); } (argument[libbash_args, split])* execute_command[$string_expr.libbash_value, libbash_args]; execute_command[std::string& name, std::vector<std::string>& libbash_args] @@ -649,7 +650,7 @@ execute_command[std::string& name, std::vector<std::string>& libbash_args] bool redirection = false; } @init { - if(name != "local" && name != "set") + if(name != "local" && name != "set" && name != "declare") current_scope.reset(new interpreter::local_scope(*walker)); } :var_def[true]* (redirect[out, err, in]{ redirection = true; })* { diff --git a/scripts/command_execution.bash b/scripts/command_execution.bash index 4c04908..901a9bb 100644 --- a/scripts/command_execution.bash +++ b/scripts/command_execution.bash @@ -93,3 +93,6 @@ echo "${!#// /_}" echo "${!1// /_}" echo "${!variable// /$'\n'}" eval abc+=\( \"\$@\" \) +declare MOZILLA_FIVE_HOME="/usr/share/${PN}" +declare foo=23 empty bar=42 +echo $MOZILLA_FIVE_HOME $foo $lol $bar diff --git a/scripts/var_def.bash b/scripts/var_def.bash index 96747c0..b0224f1 100644 --- a/scripts/var_def.bash +++ b/scripts/var_def.bash @@ -17,6 +17,8 @@ IUSE="" echo $IUSE RDEPEND="dev-db/sqlite:3" echo $RDEPEND +declare RDEPEND +echo $RDEPEND DEPEND="${RDEPEND} echo $DEPEND dev-util/pkgconfig" @@ -26,6 +28,7 @@ PATCH=("1.patch" 2.patch) echo ${PATCH[@]} ARRAY01=(1 2 3 [5]=4 5) echo ${ARRAY01[@]} +declare ARRAY02 ARRAY02=(1 2 3) echo ${ARRAY02[@]} ARRAY02[2]=4 @@ -96,3 +99,7 @@ echo ${ARRAY12[@]} ARRAY13=() ARRAY13+=(4 5 6) echo ${ARRAY13[@]} +declare num=42 +echo $num +unset num +echo $num diff --git a/src/builtins/declare_builtin.cpp b/src/builtins/declare_builtin.cpp index db955c4..81877b5 100644 --- a/src/builtins/declare_builtin.cpp +++ b/src/builtins/declare_builtin.cpp @@ -25,6 +25,10 @@ #include <algorithm> #include <iostream> +#include <boost/algorithm/string/classification.hpp> +#include <boost/algorithm/string/split.hpp> + +#include "core/bash_ast.h" #include "core/interpreter.h" #include "exceptions.h" @@ -35,80 +39,88 @@ int declare_builtin::exec(const std::vector<std::string>& bash_args) throw libbash::illegal_argument_exception("declare: arguments required"); return 1; } - else if(bash_args[0].size() != 2) - { - throw libbash::unsupported_exception("declare: multiple arguments are not supported"); - return 1; - } - - if(bash_args[0][0] != '-' && bash_args[0][0] != '+') - { - throw libbash::illegal_argument_exception("declare: invalid option"); - return 1; - } int result = 0; - switch(bash_args[0][1]) + + std::vector<std::string> tokens; + boost::split(tokens, bash_args[0], boost::is_any_of(" ")); + + if(tokens[0][0] == '-' || tokens[0][0] == '+') { - case 'F': - if(bash_args[0][0] == '+') - return 0; - if(bash_args.size() > 1) - { - for(auto iter = bash_args.begin() + 1; iter != bash_args.end(); ++iter) - { - if(_walker.has_function(*iter)) - *_out_stream << *iter << std::endl; - else - result = 1; - } - } - else - { - std::vector<std::string> functions; - - _walker.get_all_function_names(functions); - sort(functions.begin(), functions.end()); - - for(auto iter = functions.begin(); iter != functions.end(); ++iter) - *_out_stream << "declare -f " << *iter << std::endl; - } - return result; - case 'p': - if(bash_args.size() > 1) - { - for(auto iter = bash_args.begin() + 1; iter != bash_args.end(); ++iter) + if(tokens[0].size() > 2) + throw libbash::unsupported_exception("declare: " + tokens[0] + " is not supported yet"); + + switch(tokens[0][1]) + { + case 'F': + if(tokens[0][0] == '+') + return 0; + if(tokens.size() > 1) { - // We do not print the type of the variable for now - if(!_walker.is_unset(*iter)) + for(auto iter = tokens.begin() + 1; iter != tokens.end(); ++iter) { - *_out_stream << "declare -- " << *iter << "=\"" << _walker.resolve<std::string>(*iter) << "\"" << std::endl; + if(_walker.has_function(*iter)) + *_out_stream << *iter << std::endl; + else + result = 1; } - else + } + else + { + std::vector<std::string> functions; + + _walker.get_all_function_names(functions); + sort(functions.begin(), functions.end()); + + for(auto iter = functions.begin(); iter != functions.end(); ++iter) + *_out_stream << "declare -f " << *iter << std::endl; + } + return result; + case 'p': + if(tokens.size() > 1) + { + for(auto iter = tokens.begin() + 1; iter != tokens.end(); ++iter) { - *_out_stream << "-bash: declare: " << *iter << ": not found" << std::endl; - result = 1; + // We do not print the type of the variable for now + if(!_walker.is_unset(*iter)) + { + *_out_stream << "declare -- " << *iter << "=\"" << _walker.resolve<std::string>(*iter) << "\"" << std::endl; + } + else + { + *_out_stream << "-bash: declare: " << *iter << ": not found" << std::endl; + result = 1; + } } } - } - else - { - throw libbash::unsupported_exception("We do not support declare -p without arguments for now"); - } - return result; - case 'a': - case 'A': - case 'f': - case 'i': - case 'l': - case 'r': - case 't': - case 'u': - case 'x': - throw libbash::unsupported_exception("declare " + bash_args[0] + " is not supported yet"); - return 1; - default: - throw libbash::illegal_argument_exception("declare: unrecognized option: " + bash_args[0]); - return 1; + else + { + throw libbash::unsupported_exception("We do not support declare -p without arguments for now"); + } + return result; + case 'a': + case 'i': + case 'A': + case 'f': + case 'l': + case 'r': + case 't': + case 'u': + case 'x': + throw libbash::unsupported_exception("declare " + tokens[0] + " is not supported yet"); + return 1; + default: + throw libbash::illegal_argument_exception("declare: unrecognized option: " + tokens[0]); + return 1; + } } + + std::stringstream script; + for(auto iter = bash_args.begin(); iter != bash_args.end(); ++iter) + script << *iter + " "; + + bash_ast ast(script, std::bind(&bash_ast::parser_builtin_variable_definitions, std::placeholders::_1, false)); + ast.interpret_with(_walker); + + return result; } diff --git a/src/builtins/tests/declare_tests.cpp b/src/builtins/tests/declare_tests.cpp index 19347ac..eec5e41 100644 --- a/src/builtins/tests/declare_tests.cpp +++ b/src/builtins/tests/declare_tests.cpp @@ -55,11 +55,32 @@ namespace TEST(declare_builtin_test, invalid_arguments) { test_declare<libbash::illegal_argument_exception>("declare: arguments required", {}); - test_declare<libbash::unsupported_exception>("declare: multiple arguments are not supported", {"-ap"}); - test_declare<libbash::illegal_argument_exception>("declare: invalid option", {"_a"}); + test_declare<libbash::unsupported_exception>("declare: -ap is not supported yet", {"-ap"}); test_declare<libbash::illegal_argument_exception>("declare: unrecognized option: -L", {"-L"}); } +TEST(declare_built_test, declarations) +{ + interpreter walker; + + EXPECT_EQ(0, cppbash_builtin::exec("declare", {"var"}, cout, cerr, cin, walker)); + + EXPECT_EQ(0, cppbash_builtin::exec("declare", {"foo1=bar"}, cout, cerr, cin, walker)); + EXPECT_STREQ("bar", walker.resolve<std::string>("foo1").c_str()); + + walker.define("foo2", "bar"); + EXPECT_EQ(0, cppbash_builtin::exec("declare", {"foo2"}, cout, cerr, cin, walker)); + EXPECT_STREQ("bar", walker.resolve<std::string>("foo2").c_str()); + + EXPECT_EQ(0, cppbash_builtin::exec("declare", {"var1=foo var2 var3=bar"}, cout, cerr, cin, walker)); + EXPECT_STREQ("foo", walker.resolve<std::string>("var1").c_str()); + EXPECT_STREQ("", walker.resolve<std::string>("var2").c_str()); + EXPECT_STREQ("bar", walker.resolve<std::string>("var3").c_str()); + + EXPECT_EQ(0, cppbash_builtin::exec("declare", {"var=\"foo bar\""}, cout, cerr, cin, walker)); + EXPECT_STREQ("foo bar", walker.resolve<std::string>("var").c_str()); +} + TEST(declare_builtin_test, _F) { stringstream expression("function foo() { :; }; function bar() { :; }"); @@ -68,15 +89,15 @@ TEST(declare_builtin_test, _F) ast.interpret_with(walker); stringstream test_output1; - EXPECT_EQ(0, cppbash_builtin::exec("declare", {"-F", "foo"}, test_output1, cerr, cin, walker)); + EXPECT_EQ(0, cppbash_builtin::exec("declare", {"-F foo"}, test_output1, cerr, cin, walker)); EXPECT_EQ("foo\n", test_output1.str()); stringstream test_output2; - EXPECT_EQ(1, cppbash_builtin::exec("declare", {"-F", "foo", "bar", "test"}, test_output2, cerr, cin, walker)); + EXPECT_EQ(1, cppbash_builtin::exec("declare", {"-F foo bar test"}, test_output2, cerr, cin, walker)); EXPECT_EQ("foo\nbar\n", test_output2.str()); stringstream test_output3; - EXPECT_EQ(0, cppbash_builtin::exec("declare", {"+F", "foo", "bar", "test"}, test_output3, cerr, cin, walker)); + EXPECT_EQ(0, cppbash_builtin::exec("declare", {"+F foo bar test"}, test_output3, cerr, cin, walker)); EXPECT_EQ("", test_output3.str()); stringstream test_output4; @@ -90,11 +111,11 @@ TEST(declare_built_test, _p) walker.define("foo", "bar"); stringstream test_output1; - EXPECT_EQ(0, cppbash_builtin::exec("declare", {"-p", "foo"}, test_output1, cerr, cin, walker)); + EXPECT_EQ(0, cppbash_builtin::exec("declare", {"-p foo"}, test_output1, cerr, cin, walker)); EXPECT_EQ("declare -- foo=\"bar\"\n", test_output1.str()); stringstream test_output2; - EXPECT_EQ(1, cppbash_builtin::exec("declare", {"-p", "bar", "test"}, test_output2, cerr, cin, walker)); + EXPECT_EQ(1, cppbash_builtin::exec("declare", {"-p bar test"}, test_output2, cerr, cin, walker)); EXPECT_EQ("-bash: declare: bar: not found\n-bash: declare: test: not found\n", test_output2.str()); } |