Gentoo Archives: gentoo-commits

From: "Petteri Räty" <betelgeuse@g.o>
To: gentoo-commits@l.g.o
Subject: [gentoo-commits] proj/libbash:master commit in: src/core/, src/core/tests/
Date: Tue, 12 Apr 2011 18:29:30
Message-Id: b37f97adcfaf9aea824aa5f1bacae4c326973434.betelgeuse@gentoo
1 commit: b37f97adcfaf9aea824aa5f1bacae4c326973434
2 Author: Mu Qiao <qiaomuf <AT> gentoo <DOT> org>
3 AuthorDate: Mon Apr 11 13:25:42 2011 +0000
4 Commit: Petteri Räty <betelgeuse <AT> gentoo <DOT> org>
5 CommitDate: Tue Apr 12 07:22:36 2011 +0000
6 URL: http://git.overlays.gentoo.org/gitweb/?p=proj/libbash.git;a=commit;h=b37f97ad
7
8 Implement array symbol
9
10 Bash uses normal variables and arrays interchangeably. So we use
11 an internal map no matter if it's an array or variable.
12
13 ---
14 src/core/interpreter.h | 12 ++++++---
15 src/core/symbols.hpp | 44 +++++++++++++++++++++++++++-------
16 src/core/tests/interpreter_test.cpp | 27 +++++++++++++++++++++
17 src/core/tests/symbols_test.cpp | 31 +++++++++++++++++++++++-
18 4 files changed, 100 insertions(+), 14 deletions(-)
19
20 diff --git a/src/core/interpreter.h b/src/core/interpreter.h
21 index 8fcab60..7155639 100644
22 --- a/src/core/interpreter.h
23 +++ b/src/core/interpreter.h
24 @@ -363,15 +363,16 @@ public:
25
26 /// \brief resolve any variable
27 /// \param variable name
28 + /// \param array index, use index=0 if it's not an array
29 /// \return the value of the variable, call default constructor if
30 // it's undefined
31 template <typename T>
32 - T resolve(const std::string& name)
33 + T resolve(const std::string& name, const unsigned index=0)
34 {
35 std::shared_ptr<variable> value = members.resolve(name);
36 if(!value)
37 return T();
38 - return value->get_value<T>();
39 + return value->get_value<T>(index);
40 }
41
42 /// \brief check whether the value of the variable is null, return true
43 @@ -399,15 +400,18 @@ public:
44 /// it's readonly, will define the variable if it doesn't exist
45 /// \param variable name
46 /// \param new value
47 + /// \param array index, use index=0 if it's not an array
48 /// \return the new value of the variable
49 template <typename T>
50 - const T& set_value(const std::string& name, const T& new_value)
51 + const T& set_value(const std::string& name,
52 + const T& new_value,
53 + const unsigned index=0)
54 {
55 std::shared_ptr<variable> value = members.resolve(name);
56 if(!value)
57 define(name, new_value, false);
58 else
59 - value->set_value(new_value);
60 + value->set_value(new_value, index);
61 return new_value;
62 }
63
64
65 diff --git a/src/core/symbols.hpp b/src/core/symbols.hpp
66 index 077065e..f645047 100644
67 --- a/src/core/symbols.hpp
68 +++ b/src/core/symbols.hpp
69 @@ -25,6 +25,7 @@
70 #ifndef LIBBASH_CORE_SYMBOLS_HPP_
71 #define LIBBASH_CORE_SYMBOLS_HPP_
72
73 +#include <map>
74 #include <memory>
75 #include <sstream>
76 #include <string>
77 @@ -115,8 +116,10 @@ class variable
78 std::string name;
79
80 /// \var private::value
81 - /// \brief actual value of the variable
82 - boost::variant<int, std::string> value;
83 + /// \brief actual value of the variable. We put string in front of int
84 + /// because we want "" as default string value; Otherwise we
85 + /// will get "0".
86 + std::map<int, boost::variant<std::string, int>> value;
87
88 /// \var private::readonly
89 /// \brief whether the variable is readonly
90 @@ -136,30 +139,43 @@ public:
91
92 template <typename T>
93 variable(const std::string& name,
94 - T v,
95 + const T& v,
96 bool ro=false,
97 bool is_null=false)
98 - : name(name), value(v), readonly(ro), null_value(is_null){}
99 + : name(name), readonly(ro), null_value(is_null)
100 + {
101 + value[0] = v;
102 + }
103
104 - /// \brief retrieve actual value of the variable
105 + /// \brief retrieve actual value of the variable, if index is out of bound,
106 + /// will return the default value of type T
107 /// \return the value of the variable
108 template<typename T>
109 - T get_value() const
110 + T get_value(const unsigned index=0) const
111 {
112 static converter<T> visitor;
113 - return boost::apply_visitor(visitor, value);
114 +
115 + auto iter = value.find(index);
116 + if(iter == value.end())
117 + return T{};
118 +
119 + return boost::apply_visitor(visitor, iter->second);
120 }
121
122 /// \brief set the value of the variable, raise exception if it's readonly
123 /// \param the new value to be set
124 + /// \param array index, use index=0 if it's not an array
125 /// \param whether to set the variable to null value, default is false
126 template <typename T>
127 - void set_value(T new_value, bool is_null=false)
128 + void set_value(const T& new_value,
129 + const unsigned index=0,
130 + bool is_null=false)
131 {
132 if(readonly)
133 throw interpreter_exception(get_name() + " is readonly variable");
134 +
135 null_value = is_null;
136 - value = new_value;
137 + value[index] = new_value;
138 }
139
140 /// \brief check whether the value of the variable is null
141 @@ -170,6 +186,16 @@ public:
142 }
143 };
144
145 +// specialization for arrays
146 +template <>
147 +inline variable::variable<>(const std::string& name,
148 + const std::map<int, std::string>& v,
149 + bool ro,
150 + bool is_null)
151 + : name(name), value(v.begin(), v.end()), readonly(ro), null_value(is_null)
152 +{
153 +}
154 +
155 ///
156 /// class scope
157 /// \brief implementation for symbol table
158
159 diff --git a/src/core/tests/interpreter_test.cpp b/src/core/tests/interpreter_test.cpp
160 index 6cc2df9..28f8d35 100644
161 --- a/src/core/tests/interpreter_test.cpp
162 +++ b/src/core/tests/interpreter_test.cpp
163 @@ -44,6 +44,17 @@ TEST(interpreter, define_resolve_string)
164 EXPECT_STREQ("", walker.resolve<string>("undefined").c_str());
165 }
166
167 +TEST(interpreter, define_resolve_array)
168 +{
169 + interpreter walker;
170 + std::map<int, std::string> values = {{0, "1"}, {1, "2"}, {2, "3"}};
171 + walker.define("array", values);
172 + EXPECT_STREQ("1", walker.resolve<string>("array", 0).c_str());
173 + EXPECT_STREQ("2", walker.resolve<string>("array", 1).c_str());
174 + EXPECT_STREQ("3", walker.resolve<string>("array", 2).c_str());
175 + EXPECT_STREQ("", walker.resolve<string>("undefined",100).c_str());
176 +}
177 +
178 TEST(interpreter, is_unset_or_null)
179 {
180 interpreter walker;
181 @@ -91,6 +102,22 @@ TEST(interpreter, set_string_value)
182 EXPECT_STREQ("hi", walker.resolve<string>("astring_ro").c_str());
183 }
184
185 +TEST(interpreter, set_array_value)
186 +{
187 + interpreter walker;
188 + std::map<int, std::string> values = {{0, "1"}, {1, "2"}, {2, "3"}};
189 + walker.define("array", values);
190 + EXPECT_STREQ("2", walker.set_value<string>("array", "2", 0).c_str());
191 + EXPECT_STREQ("2", walker.resolve<string>("array", 0).c_str());
192 + EXPECT_STREQ("out_of_bound", walker.set_value<string>("array", "out_of_bound", 10).c_str());
193 + EXPECT_STREQ("out_of_bound", walker.resolve<string>("array",10).c_str());
194 +
195 + walker.define("ro_array", values, true);
196 + EXPECT_THROW(walker.set_value<string>("ro_array", "hello", 1),
197 + interpreter_exception);
198 + EXPECT_STREQ("2", walker.resolve<string>("ro_array", 1).c_str());
199 +}
200 +
201 TEST(interperter, substring_expansion_exception)
202 {
203 interpreter walker;
204
205 diff --git a/src/core/tests/symbols_test.cpp b/src/core/tests/symbols_test.cpp
206 index 73a6a9c..2b7a65e 100644
207 --- a/src/core/tests/symbols_test.cpp
208 +++ b/src/core/tests/symbols_test.cpp
209 @@ -65,11 +65,40 @@ TEST(symbol_test, string_variable)
210 EXPECT_EQ(123, int_string.get_value<int>());
211 }
212
213 +TEST(symbol_test, array_variable)
214 +{
215 + map<int, string> values = {{0, "1"}, {1, "2"}, {2, "3"}};
216 +
217 + // readonly array
218 + variable ro_array("foo", values, true);
219 + EXPECT_STREQ("foo", ro_array.get_name().c_str());
220 + EXPECT_STREQ("1", ro_array.get_value<string>(0).c_str());
221 + EXPECT_STREQ("2", ro_array.get_value<string>(1).c_str());
222 + EXPECT_STREQ("3", ro_array.get_value<string>(2).c_str());
223 + EXPECT_THROW(ro_array.set_value("4", 0), interpreter_exception);
224 + EXPECT_STREQ("1", ro_array.get_value<string>(0).c_str());
225 +
226 + // out of bound
227 + EXPECT_STREQ("", ro_array.get_value<string>(100).c_str());
228 +
229 + // normal array
230 + variable normal_array("foo", values);
231 + normal_array.set_value("5", 4);
232 + EXPECT_STREQ("1", normal_array.get_value<string>(0).c_str());
233 + EXPECT_STREQ("2", normal_array.get_value<string>(1).c_str());
234 + EXPECT_STREQ("3", normal_array.get_value<string>(2).c_str());
235 + EXPECT_STREQ("", normal_array.get_value<string>(3).c_str());
236 + EXPECT_STREQ("5", normal_array.get_value<string>(4).c_str());
237 +
238 + // get integer value
239 + EXPECT_EQ(3, normal_array.get_value<int>(2));
240 +}
241 +
242 TEST(symbol_test, is_null)
243 {
244 variable var("foo", 10);
245 EXPECT_FALSE(var.is_null());
246 - var.set_value("bar", true);
247 + var.set_value("bar", 0, true);
248 EXPECT_TRUE(var.is_null());
249 EXPECT_TRUE(variable("foo", "", false, true).is_null());
250 }