diff options
author | Mu Qiao <qiaomuf@gentoo.org> | 2011-06-22 21:25:48 +0800 |
---|---|---|
committer | Mu Qiao <qiaomuf@gentoo.org> | 2011-06-26 22:06:37 +0800 |
commit | ccec9a99b7f370c2b4d4ae872d97385848fb1845 (patch) | |
tree | 8c9b5ee7f7b46ebfbdbee2212e97dacb41e7192d /src | |
parent | Build: relax antlr timeout limit (diff) | |
download | libbash-ccec9a99b7f370c2b4d4ae872d97385848fb1845.tar.gz libbash-ccec9a99b7f370c2b4d4ae872d97385848fb1845.tar.bz2 libbash-ccec9a99b7f370c2b4d4ae872d97385848fb1845.zip |
Walker: make arithmetic expansion follow POSIX
POSIX requires signed long integer for arithmetic expansion. $? is
implemented in the interpreter class now because POSIX doesn't require
the type of $? to be long. It would cause conversion in many places if
we used long for $?.
Diffstat (limited to 'src')
-rw-r--r-- | src/builtins/inherit_builtin.cpp | 6 | ||||
-rw-r--r-- | src/core/bash_ast.cpp | 2 | ||||
-rw-r--r-- | src/core/bash_ast.h | 2 | ||||
-rw-r--r-- | src/core/interpreter.cpp | 4 | ||||
-rw-r--r-- | src/core/interpreter.h | 17 | ||||
-rw-r--r-- | src/core/symbols.hpp | 30 | ||||
-rw-r--r-- | src/core/tests/interpreter_test.cpp | 16 | ||||
-rw-r--r-- | src/core/tests/symbols_test.cpp | 14 |
8 files changed, 47 insertions, 44 deletions
diff --git a/src/builtins/inherit_builtin.cpp b/src/builtins/inherit_builtin.cpp index 54ba4ac..1490e5b 100644 --- a/src/builtins/inherit_builtin.cpp +++ b/src/builtins/inherit_builtin.cpp @@ -58,7 +58,7 @@ inline bool inherit_builtin::hasq(const std::string& value, const std::string& n // We do not support any QA warning int inherit_builtin::exec(const std::vector<std::string>& bash_args) { - _walker.set_value("ECLASS_DEPTH", _walker.resolve<int>("ECLASS_DEPTH") + 1); + _walker.set_value("ECLASS_DEPTH", _walker.resolve<long>("ECLASS_DEPTH") + 1); // find eclass directory std::string eclassdir; @@ -114,8 +114,8 @@ int inherit_builtin::exec(const std::vector<std::string>& bash_args) _walker.set_value("INHERITED", _walker.resolve<std::string>("INHERITED") + " " + *iter); } - _walker.set_value("ECLASS_DEPTH", _walker.resolve<int>("ECLASS_DEPTH") - 1); - if(_walker.resolve<int>("ECLASS_DEPTH") > 0) + _walker.set_value("ECLASS_DEPTH", _walker.resolve<long>("ECLASS_DEPTH") - 1); + if(_walker.resolve<long>("ECLASS_DEPTH") > 0) { _walker.set_value("ECLASS", PECLASS); } diff --git a/src/core/bash_ast.cpp b/src/core/bash_ast.cpp index 45cec7c..56aef8c 100644 --- a/src/core/bash_ast.cpp +++ b/src/core/bash_ast.cpp @@ -176,7 +176,7 @@ void bash_ast::walker_start(plibbashWalker tree_parser) tree_parser->start(tree_parser); } -int bash_ast::walker_arithmetics(plibbashWalker tree_parser) +long bash_ast::walker_arithmetics(plibbashWalker tree_parser) { return tree_parser->arithmetics(tree_parser); } diff --git a/src/core/bash_ast.h b/src/core/bash_ast.h index ae6bb0f..f79608d 100644 --- a/src/core/bash_ast.h +++ b/src/core/bash_ast.h @@ -75,7 +75,7 @@ public: static void walker_start(plibbashWalker tree_parser); - static int walker_arithmetics(plibbashWalker tree_parser); + static long walker_arithmetics(plibbashWalker tree_parser); static void call_function(plibbashWalker tree_parser, ANTLR3_MARKER index); diff --git a/src/core/interpreter.cpp b/src/core/interpreter.cpp index 267183a..ed9f626 100644 --- a/src/core/interpreter.cpp +++ b/src/core/interpreter.cpp @@ -118,7 +118,7 @@ interpreter::interpreter(): _out(&std::cout), _err(&std::cerr), _in(&std::cin), {'P', false}, {'T', false}, } - ) + ), status(0) { define("IFS", " \t\n"); // We do not support the options set by the shell itself (such as the -i option) @@ -430,7 +430,7 @@ void interpreter::set_additional_option(const std::string& name, bool value) iter->second = value; } -int interpreter::eval_arithmetic(const std::string& expression) +long interpreter::eval_arithmetic(const std::string& expression) { bash_ast ast(std::stringstream(expression), &bash_ast::parser_arithmetics); return ast.interpret_with(*this, &bash_ast::walker_arithmetics); diff --git a/src/core/interpreter.h b/src/core/interpreter.h index d44ede4..b0cfda5 100644 --- a/src/core/interpreter.h +++ b/src/core/interpreter.h @@ -73,6 +73,10 @@ class interpreter: public boost::noncopyable // as bash implementation. std::map<char, bool> options; + /// \var private::status + /// \brief the return status of the last command + int status; + /// \brief calculate the correct offset when offset < 0 and check whether /// the real offset is in legal range /// \param[in,out] a value/result argument referring to offset @@ -180,7 +184,7 @@ public: _out = &std::cout; } - /// \brief resolve string/int variable, local scope will be + /// \brief resolve string/long variable, local scope will be /// checked first, then global scope /// \param variable name /// \param array index, use index=0 if it's not an array @@ -245,17 +249,16 @@ public: /// \brief set the return status of the last command /// \param the value of the return status - void set_status(int status) + void set_status(int s) { - set_value("?", status); + status = s; } /// \brief get the return status of the last command /// \param the value of the return status - template <typename T=int> - T get_status(void) const + int get_status(void) const { - return resolve<T>("?"); + return status; } /// \brief unset a variable @@ -483,7 +486,7 @@ public: /// \brief evaluate arithmetic expression and return the result /// \param the arithmetic expression /// \return the evaluated result - int eval_arithmetic(const std::string& expression); + long eval_arithmetic(const std::string& expression); /// \brief perform expansion like ${var//foo/bar} /// \param the value to be expanded diff --git a/src/core/symbols.hpp b/src/core/symbols.hpp index a5e2e1d..8c6dec7 100644 --- a/src/core/symbols.hpp +++ b/src/core/symbols.hpp @@ -46,33 +46,33 @@ class converter: public boost::static_visitor<T> /// /// \class converter -/// \brief specialized converter for int +/// \brief specialized converter for long /// template<> -class converter<int>: public boost::static_visitor<int> +class converter<long>: public boost::static_visitor<long> { public: - /// \brief converter for int value + /// \brief converter for long value /// \param the value to be converted - /// \return the converted int - int operator() (const int value) const + /// \return the converted long + long operator() (const long value) const { return value; } /// \brief converter for string value /// \param the value to be converted - /// \return the converted int - int operator() (const std::string& value) const + /// \return the converted long + long operator() (const std::string& value) const { - int result = 0; + long result = 0; try { - result = boost::lexical_cast<int>(value); + result = boost::lexical_cast<long>(value); } catch(boost::bad_lexical_cast& e) { - std::cerr << "can't cast " << value << " to int" << std::endl; + std::cerr << "can't cast " << value << " to long" << std::endl; } return result; } @@ -87,10 +87,10 @@ class converter<std::string>: public boost::static_visitor<std::string> { public: - /// \brief converter for int value + /// \brief converter for long value /// \param the value to be converted /// \return the converted string - std::string operator() (const int value) const + std::string operator() (const long value) const { return boost::lexical_cast<std::string>(value); } @@ -115,17 +115,17 @@ class variable std::string name; /// \var private::value - /// \brief actual value of the variable. We put string in front of int + /// \brief actual value of the variable. We put string in front of long /// because we want "" as default string value; Otherwise we /// will get "0". - std::map<unsigned, boost::variant<std::string, int>> value; + std::map<unsigned, boost::variant<std::string, long>> value; /// \var private::readonly /// \brief whether the variable is readonly bool readonly; public: - typedef std::map<unsigned, boost::variant<std::string, int>>::size_type size_type; + typedef std::map<unsigned, boost::variant<std::string, long>>::size_type size_type; /// \brief retrieve variable name /// \return const string value of variable name diff --git a/src/core/tests/interpreter_test.cpp b/src/core/tests/interpreter_test.cpp index c449e3c..d20697b 100644 --- a/src/core/tests/interpreter_test.cpp +++ b/src/core/tests/interpreter_test.cpp @@ -31,9 +31,9 @@ TEST(interpreter, define_resolve_int) { interpreter walker; walker.define("aint", 4); - EXPECT_EQ(4, walker.resolve<int>("aint")); - EXPECT_EQ(0, walker.resolve<int>("undefined")); - EXPECT_EQ(0, walker.resolve<int>("")); + EXPECT_EQ(4, walker.resolve<long>("aint")); + EXPECT_EQ(0, walker.resolve<long>("undefined")); + EXPECT_EQ(0, walker.resolve<long>("")); } TEST(interpreter, define_resolve_string) @@ -57,7 +57,7 @@ TEST(interpreter, define_resolve_array) walker.define("partial", 10, false, 8); EXPECT_EQ(1, walker.get_array_length("partial")); - EXPECT_EQ(10, walker.resolve<int>("partial", 8)); + EXPECT_EQ(10, walker.resolve<long>("partial", 8)); EXPECT_EQ(0, walker.get_array_length("not exist")); } @@ -91,14 +91,14 @@ TEST(interpreter, set_int_value) interpreter walker; walker.define("aint", 4); EXPECT_EQ(10, walker.set_value("aint", 10)); - EXPECT_EQ(10, walker.resolve<int>("aint")); + EXPECT_EQ(10, walker.resolve<long>("aint")); EXPECT_EQ(10, walker.set_value("undefined", 10)); - EXPECT_EQ(10, walker.resolve<int>("undefined")); + EXPECT_EQ(10, walker.resolve<long>("undefined")); walker.define("aint_ro", 4, true); EXPECT_THROW(walker.set_value("aint_ro", 10), libbash::readonly_exception); - EXPECT_EQ(4, walker.resolve<int>("aint_ro")); + EXPECT_EQ(4, walker.resolve<long>("aint_ro")); } TEST(interpreter, set_string_value) @@ -138,7 +138,7 @@ TEST(interpreter, get_array_values) std::map<unsigned, std::string> values = {{0, "1"}, {1, "2"}, {2, "3"}}; walker.define("array", values); - std::vector<int> array_values; + std::vector<long> array_values; EXPECT_TRUE(walker.resolve_array("array", array_values)); EXPECT_EQ(1, array_values[0]); EXPECT_EQ(2, array_values[1]); diff --git a/src/core/tests/symbols_test.cpp b/src/core/tests/symbols_test.cpp index 1410a05..e5b4649 100644 --- a/src/core/tests/symbols_test.cpp +++ b/src/core/tests/symbols_test.cpp @@ -32,14 +32,14 @@ TEST(symbol_test, int_variable) // readonly integer variable ro_integer("integer", 10, true); EXPECT_STREQ("integer", ro_integer.get_name().c_str()); - EXPECT_EQ(10, ro_integer.get_value<int>()); + EXPECT_EQ(10, ro_integer.get_value<long>()); EXPECT_THROW(ro_integer.set_value(100), libbash::interpreter_exception); - EXPECT_EQ(10, ro_integer.get_value<int>()); + EXPECT_EQ(10, ro_integer.get_value<long>()); // normal only integer variable normal_integer("integer", 10); normal_integer.set_value(100); - EXPECT_EQ(100, normal_integer.get_value<int>()); + EXPECT_EQ(100, normal_integer.get_value<long>()); // get string value of an integer EXPECT_STREQ("100", normal_integer.get_value<string>().c_str()); @@ -61,9 +61,9 @@ TEST(symbol_test, string_variable) // string contains integer value variable int_string("string", "123"); - EXPECT_EQ(123, int_string.get_value<int>()); + EXPECT_EQ(123, int_string.get_value<long>()); int_string.set_value("abc"); - EXPECT_EQ(0, int_string.get_value<int>()); + EXPECT_EQ(0, int_string.get_value<long>()); } TEST(symbol_test, array_variable) @@ -92,7 +92,7 @@ TEST(symbol_test, array_variable) EXPECT_STREQ("5", normal_array.get_value<string>(4).c_str()); // get integer value - EXPECT_EQ(3, normal_array.get_value<int>(2)); + EXPECT_EQ(3, normal_array.get_value<long>(2)); } TEST(symbol_test, get_all_values) @@ -114,7 +114,7 @@ TEST(symbol_test, get_all_values) EXPECT_STREQ("1", string_values[0].c_str()); variable an_int("foo", 10); - vector<int> int_values; + vector<long> int_values; an_int.get_all_values(int_values); EXPECT_EQ(1, int_values.size()); EXPECT_EQ(10, int_values[0]); |