1 |
commit: be5289bca55b033742300ed0f5f69121b2bb76c4 |
2 |
Author: Mu Qiao <qiaomuf <AT> gentoo <DOT> org> |
3 |
AuthorDate: Thu Apr 21 11:58:16 2011 +0000 |
4 |
Commit: Petteri Räty <betelgeuse <AT> gentoo <DOT> org> |
5 |
CommitDate: Thu Apr 28 02:57:53 2011 +0000 |
6 |
URL: http://git.overlays.gentoo.org/gitweb/?p=proj/libbash.git;a=commit;h=be5289bc |
7 |
|
8 |
Core: support unsetting variables, fix is_null |
9 |
|
10 |
Empty variable values are all treated as null value. This simplifies |
11 |
the previous code and fixes some logic errors. |
12 |
|
13 |
--- |
14 |
bashast/libbashWalker.g | 5 +-- |
15 |
scripts/var_def.bash.result | 4 +- |
16 |
src/core/interpreter.cpp | 21 ++++++++++++++++++ |
17 |
src/core/interpreter.h | 19 +++++++++++----- |
18 |
src/core/symbols.hpp | 40 +++++++++++++++++++++++++--------- |
19 |
src/core/tests/interpreter_test.cpp | 29 ++++++++++++++++++++++++- |
20 |
src/core/tests/symbols_test.cpp | 12 ++++++++- |
21 |
7 files changed, 105 insertions(+), 25 deletions(-) |
22 |
|
23 |
diff --git a/bashast/libbashWalker.g b/bashast/libbashWalker.g |
24 |
index e278d1b..203cd28 100644 |
25 |
--- a/bashast/libbashWalker.g |
26 |
+++ b/bashast/libbashWalker.g |
27 |
@@ -119,10 +119,9 @@ var_def |
28 |
@declarations { |
29 |
std::map<int, std::string> values; |
30 |
unsigned index = 0; |
31 |
- bool is_null = true; |
32 |
} |
33 |
- :^(EQUALS name (string_expr { is_null = false; })?) { |
34 |
- walker->set_value($name.libbash_value, $string_expr.libbash_value, $name.index, is_null); |
35 |
+ :^(EQUALS name string_expr?) { |
36 |
+ walker->set_value($name.libbash_value, $string_expr.libbash_value, $name.index); |
37 |
} |
38 |
|^(EQUALS libbash_name=name_base ^(ARRAY ( |
39 |
(expr=string_expr |
40 |
|
41 |
diff --git a/scripts/var_def.bash.result b/scripts/var_def.bash.result |
42 |
index e840ebe..1b9e287 100644 |
43 |
--- a/scripts/var_def.bash.result |
44 |
+++ b/scripts/var_def.bash.result |
45 |
@@ -5,8 +5,8 @@ $- has not been implemented yet |
46 |
$! has not been implemented yet |
47 |
ARRAY01=1 2 3 4 5 |
48 |
ARRAY02=1 2 4 5 |
49 |
-ARRAY03=2 3 |
50 |
-ARRAY04=2 3 |
51 |
+ARRAY03= 2 3 |
52 |
+ARRAY04= 2 3 |
53 |
ARRAY05=1 2 3 4 5 |
54 |
ARRAY06=1 2 3 4 5 |
55 |
ARRAY07=1 2 3 4 5 |
56 |
|
57 |
diff --git a/src/core/interpreter.cpp b/src/core/interpreter.cpp |
58 |
index 9548e8a..f0bf61e 100644 |
59 |
--- a/src/core/interpreter.cpp |
60 |
+++ b/src/core/interpreter.cpp |
61 |
@@ -178,3 +178,24 @@ void interpreter::get_all_function_names(std::vector<std::string>& function_name |
62 |
{ |
63 |
boost::copy(functions | boost::adaptors::map_keys, back_inserter(function_names)); |
64 |
} |
65 |
+ |
66 |
+void interpreter::unset(const std::string& name) |
67 |
+{ |
68 |
+ auto iter = members.find(name); |
69 |
+ if(iter == members.end()) |
70 |
+ return; |
71 |
+ else if(iter->second->is_readonly()) |
72 |
+ throw interpreter_exception("Can't unset readonly variable " + name); |
73 |
+ else |
74 |
+ members.erase(name); |
75 |
+} |
76 |
+ |
77 |
+void interpreter::unset(const std::string& name, |
78 |
+ const unsigned index) |
79 |
+{ |
80 |
+ auto iter = members.find(name); |
81 |
+ if(iter == members.end()) |
82 |
+ return; |
83 |
+ else |
84 |
+ iter->second->unset_value(index); |
85 |
+} |
86 |
|
87 |
diff --git a/src/core/interpreter.h b/src/core/interpreter.h |
88 |
index e471b94..dc446fc 100644 |
89 |
--- a/src/core/interpreter.h |
90 |
+++ b/src/core/interpreter.h |
91 |
@@ -468,14 +468,13 @@ public: |
92 |
template <typename T> |
93 |
const T& set_value(const std::string& name, |
94 |
const T& new_value, |
95 |
- const unsigned index=0, |
96 |
- bool is_null=false) |
97 |
+ const unsigned index=0) |
98 |
{ |
99 |
auto i = members.find(name); |
100 |
if(i == members.end()) |
101 |
- define(name, new_value, false, is_null, index); |
102 |
+ define(name, new_value, false, index); |
103 |
else |
104 |
- i->second->set_value(new_value, index, is_null); |
105 |
+ i->second->set_value(new_value, index); |
106 |
return new_value; |
107 |
} |
108 |
|
109 |
@@ -494,6 +493,15 @@ public: |
110 |
return resolve<T>("?"); |
111 |
} |
112 |
|
113 |
+ /// \brief unset a variable |
114 |
+ /// \param the name of the variable |
115 |
+ void unset(const std::string& name); |
116 |
+ |
117 |
+ /// \brief unset a array member |
118 |
+ /// \param the name of the array |
119 |
+ /// \param the index of the member |
120 |
+ void unset(const std::string& name, const unsigned index); |
121 |
+ |
122 |
/// \brief define a new global variable |
123 |
/// \param the name of the variable |
124 |
/// \param the value of the variable |
125 |
@@ -503,11 +511,10 @@ public: |
126 |
void define(const std::string& name, |
127 |
const T& value, |
128 |
bool readonly=false, |
129 |
- bool is_null=false, |
130 |
const unsigned index=0) |
131 |
{ |
132 |
std::shared_ptr<variable> target( |
133 |
- new variable(name, value, readonly, is_null, index)); |
134 |
+ new variable(name, value, readonly, index)); |
135 |
members[name] = target; |
136 |
} |
137 |
|
138 |
|
139 |
diff --git a/src/core/symbols.hpp b/src/core/symbols.hpp |
140 |
index b11d338..89fd657 100644 |
141 |
--- a/src/core/symbols.hpp |
142 |
+++ b/src/core/symbols.hpp |
143 |
@@ -137,12 +137,10 @@ public: |
144 |
variable(const std::string& name, |
145 |
const T& v, |
146 |
bool ro=false, |
147 |
- bool is_null=false, |
148 |
const unsigned index=0) |
149 |
: name(name), readonly(ro) |
150 |
{ |
151 |
- if(!is_null) |
152 |
- value[index] = v; |
153 |
+ value[index] = v; |
154 |
} |
155 |
|
156 |
/// \brief retrieve actual value of the variable, if index is out of bound, |
157 |
@@ -182,16 +180,22 @@ public: |
158 |
/// \param whether to set the variable to null value, default is false |
159 |
template <typename T> |
160 |
void set_value(const T& new_value, |
161 |
- const unsigned index=0, |
162 |
- bool is_null=false) |
163 |
+ const unsigned index=0) |
164 |
{ |
165 |
if(readonly) |
166 |
throw interpreter_exception(get_name() + " is readonly variable"); |
167 |
|
168 |
- if(is_null) |
169 |
- value.erase(index); |
170 |
- else |
171 |
- value[index] = new_value; |
172 |
+ value[index] = new_value; |
173 |
+ } |
174 |
+ |
175 |
+ /// \brief unset the variable, only used for array variable |
176 |
+ /// \param the index to be unset |
177 |
+ void unset_value(const unsigned index) |
178 |
+ { |
179 |
+ if(readonly) |
180 |
+ throw interpreter_exception(get_name() + " is readonly variable"); |
181 |
+ |
182 |
+ value.erase(index); |
183 |
} |
184 |
|
185 |
/// \brief get the length of a variable |
186 |
@@ -211,10 +215,24 @@ public: |
187 |
|
188 |
/// \brief check whether the value of the variable is null |
189 |
/// \return whether the value of the variable is null |
190 |
- bool is_null(const unsigned index=0) const |
191 |
+ bool is_unset(const unsigned index=0) const |
192 |
{ |
193 |
return value.find(index) == value.end(); |
194 |
} |
195 |
+ |
196 |
+ /// \brief check whether the value of the variable is unset |
197 |
+ /// \return whether the value of the variable is unset |
198 |
+ bool is_null(const unsigned index=0) const |
199 |
+ { |
200 |
+ return get_value<std::string>(index) == ""; |
201 |
+ } |
202 |
+ |
203 |
+ /// \brief check whether the value of the variable is readonly |
204 |
+ /// \return whether the value of the variable is readonly |
205 |
+ bool is_readonly() const |
206 |
+ { |
207 |
+ return readonly; |
208 |
+ } |
209 |
}; |
210 |
|
211 |
// specialization for arrays |
212 |
@@ -222,7 +240,7 @@ template <> |
213 |
inline variable::variable<>(const std::string& name, |
214 |
const std::map<int, std::string>& v, |
215 |
bool ro, |
216 |
- bool, unsigned) |
217 |
+ unsigned) |
218 |
: name(name), value(v.begin(), v.end()), readonly(ro) |
219 |
{ |
220 |
} |
221 |
|
222 |
diff --git a/src/core/tests/interpreter_test.cpp b/src/core/tests/interpreter_test.cpp |
223 |
index 2e92a22..54f25b0 100644 |
224 |
--- a/src/core/tests/interpreter_test.cpp |
225 |
+++ b/src/core/tests/interpreter_test.cpp |
226 |
@@ -54,7 +54,7 @@ TEST(interpreter, define_resolve_array) |
227 |
EXPECT_STREQ("3", walker.resolve<string>("array", 2).c_str()); |
228 |
EXPECT_STREQ("", walker.resolve<string>("undefined",100).c_str()); |
229 |
|
230 |
- walker.define("partial", 10, false, false, 8); |
231 |
+ walker.define("partial", 10, false, 8); |
232 |
EXPECT_EQ(1, walker.get_array_length("partial")); |
233 |
EXPECT_EQ(10, walker.resolve<int>("partial", 8)); |
234 |
} |
235 |
@@ -142,6 +142,33 @@ TEST(interpreter, get_array_values) |
236 |
EXPECT_EQ(3, array_values[2]); |
237 |
} |
238 |
|
239 |
+TEST(interpreter, unset_values) |
240 |
+{ |
241 |
+ interpreter walker; |
242 |
+ std::map<int, std::string> values = {{0, "1"}, {1, "2"}, {2, "3"}}; |
243 |
+ walker.define("array", values); |
244 |
+ walker.define("ro_array", values, true); |
245 |
+ walker.define("var", "123"); |
246 |
+ walker.define("ro_var", "123", true); |
247 |
+ |
248 |
+ EXPECT_STREQ("2", walker.resolve<string>("array", 1).c_str()); |
249 |
+ walker.unset("array", 1); |
250 |
+ EXPECT_STREQ("", walker.resolve<string>("array", 1).c_str()); |
251 |
+ walker.unset("array"); |
252 |
+ EXPECT_STREQ("", walker.resolve<string>("array", 0).c_str()); |
253 |
+ EXPECT_STREQ("", walker.resolve<string>("array", 1).c_str()); |
254 |
+ EXPECT_STREQ("", walker.resolve<string>("array", 2).c_str()); |
255 |
+ |
256 |
+ EXPECT_THROW(walker.unset("ro_array", 1), interpreter_exception); |
257 |
+ EXPECT_THROW(walker.unset("ro_array"), interpreter_exception); |
258 |
+ |
259 |
+ EXPECT_STREQ("123", walker.resolve<string>("var").c_str()); |
260 |
+ walker.unset("var"); |
261 |
+ EXPECT_STREQ("", walker.resolve<string>("var").c_str()); |
262 |
+ |
263 |
+ EXPECT_THROW(walker.unset("ro_var"), interpreter_exception); |
264 |
+} |
265 |
+ |
266 |
TEST(interperter, substring_expansion_exception) |
267 |
{ |
268 |
interpreter walker; |
269 |
|
270 |
diff --git a/src/core/tests/symbols_test.cpp b/src/core/tests/symbols_test.cpp |
271 |
index d614947..f151318 100644 |
272 |
--- a/src/core/tests/symbols_test.cpp |
273 |
+++ b/src/core/tests/symbols_test.cpp |
274 |
@@ -122,9 +122,17 @@ TEST(symbol_test, is_null) |
275 |
{ |
276 |
variable var("foo", 10); |
277 |
EXPECT_FALSE(var.is_null()); |
278 |
- var.set_value("bar", 0, true); |
279 |
+ var.set_value(""); |
280 |
EXPECT_TRUE(var.is_null()); |
281 |
- EXPECT_TRUE(variable("foo", "", false, true).is_null()); |
282 |
+ EXPECT_TRUE(variable("foo", "").is_null()); |
283 |
+} |
284 |
+ |
285 |
+TEST(symbol_test, is_unset) |
286 |
+{ |
287 |
+ map<int, string> values = {{0, "1"}, {1, "2"}, {2, "3"}}; |
288 |
+ variable array("foo", values); |
289 |
+ array.unset_value(1); |
290 |
+ EXPECT_TRUE(array.is_unset(1)); |
291 |
} |
292 |
|
293 |
TEST(symbol_test, get_length) |