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: Fri, 27 May 2011 23:03:53
Message-Id: a6e8bcfd05d72ca16ea786aa78106111b7a4d15e.betelgeuse@gentoo
1 commit: a6e8bcfd05d72ca16ea786aa78106111b7a4d15e
2 Author: Mu Qiao <qiaomuf <AT> gentoo <DOT> org>
3 AuthorDate: Thu May 26 10:42:50 2011 +0000
4 Commit: Petteri Räty <betelgeuse <AT> gentoo <DOT> org>
5 CommitDate: Fri May 27 08:45:41 2011 +0000
6 URL: http://git.overlays.gentoo.org/gitweb/?p=proj/libbash.git;a=commit;h=a6e8bcfd
7
8 Core: adjust interpreter to support unset
9
10 We didn't not handle local variables and the interface was not
11 helpful. Now the implementation is adjusted to support unset
12 built-in. As we don't support read only functions, unsetting
13 functions will always return true.
14
15 ---
16 Makefile.am | 1 +
17 src/core/interpreter.cpp | 60 ++++++++++++++++++++++++++--------
18 src/core/interpreter.h | 4 ++
19 src/core/tests/interpreter_test.cpp | 59 +++++++++++++++++++++++++++++-----
20 src/core/unset_exception.h | 44 +++++++++++++++++++++++++
21 5 files changed, 145 insertions(+), 23 deletions(-)
22
23 diff --git a/Makefile.am b/Makefile.am
24 index 86c2583..3b72d46 100644
25 --- a/Makefile.am
26 +++ b/Makefile.am
27 @@ -193,6 +193,7 @@ libcppbash_la_SOURCES = src/common.h \
28 $(GENERATED_PARSER_C) \
29 $(GENERATED_PARSER_H) \
30 src/core/interpreter_exception.h \
31 + src/core/unset_exception.h \
32 src/core/interpreter.cpp \
33 src/core/interpreter.h \
34 src/core/symbols.hpp \
35
36 diff --git a/src/core/interpreter.cpp b/src/core/interpreter.cpp
37 index 2337e87..41bc7b5 100644
38 --- a/src/core/interpreter.cpp
39 +++ b/src/core/interpreter.cpp
40 @@ -22,8 +22,6 @@
41 /// \brief implementations for bash interpreter (visitor pattern).
42 ///
43
44 -#include "core/interpreter.h"
45 -
46 #include <cctype>
47
48 #include <functional>
49 @@ -37,8 +35,11 @@
50 #include <boost/range/adaptor/map.hpp>
51 #include <boost/range/algorithm/copy.hpp>
52
53 +#include "core/unset_exception.h"
54 #include "libbashWalker.h"
55
56 +#include "core/interpreter.h"
57 +
58 interpreter::interpreter(): out(&std::cout), err(&std::cerr), in(&std::cin), bash_options(
59 {
60 {"autocd", false},
61 @@ -341,25 +342,56 @@ void interpreter::get_all_function_names(std::vector<std::string>& function_name
62 boost::copy(functions | boost::adaptors::map_keys, back_inserter(function_names));
63 }
64
65 +namespace
66 +{
67 + void check_unset_positional(const std::string& name)
68 + {
69 + // Unsetting positional parameters is not allowed
70 + if(isdigit(name[0]))
71 + throw unset_exception("unset: not a valid identifier");
72 + }
73 +}
74 +
75 void interpreter::unset(const std::string& name)
76 {
77 - auto iter = members.find(name);
78 - if(iter == members.end())
79 - return;
80 - else if(iter->second->is_readonly())
81 - throw interpreter_exception("Can't unset readonly variable " + name);
82 - else
83 - members.erase(name);
84 + check_unset_positional(name);
85 +
86 + auto unsetter = [&](scope& frame) -> bool {
87 + auto iter_local = frame.find(name);
88 + if(iter_local != frame.end())
89 + {
90 + if(iter_local->second->is_readonly())
91 + throw unset_exception("unset a readonly variable");
92 + frame.erase(iter_local);
93 + return true;
94 + }
95 + return false;
96 + };
97 +
98 + if(std::none_of(local_members.rbegin(), local_members.rend(), unsetter))
99 + unsetter(members);
100 +}
101 +
102 +// We need to return false when unsetting readonly functions in future
103 +void interpreter::unset_function(const std::string& name)
104 +{
105 + auto function = functions.find(name);
106 + if(function != functions.end())
107 + functions.erase(name);
108 }
109
110 void interpreter::unset(const std::string& name,
111 const unsigned index)
112 {
113 - auto iter = members.find(name);
114 - if(iter == members.end())
115 - return;
116 - else
117 - iter->second->unset_value(index);
118 + check_unset_positional(name);
119 +
120 + auto var = resolve_variable(name);
121 + if(var)
122 + {
123 + if(var->is_readonly())
124 + throw unset_exception("unset a readonly variable");
125 + var->unset_value(index);
126 + }
127 }
128
129 bool interpreter::get_option(const std::string& name) const
130
131 diff --git a/src/core/interpreter.h b/src/core/interpreter.h
132 index f35b8ff..3420ee4 100644
133 --- a/src/core/interpreter.h
134 +++ b/src/core/interpreter.h
135 @@ -502,6 +502,10 @@ public:
136 /// \param the name of the variable
137 void unset(const std::string& name);
138
139 + /// \brief unset a function
140 + /// \param the name of the function
141 + void unset_function(const std::string& name);
142 +
143 /// \brief unset a array member
144 /// \param the name of the array
145 /// \param the index of the member
146
147 diff --git a/src/core/tests/interpreter_test.cpp b/src/core/tests/interpreter_test.cpp
148 index ab24449..d64866f 100644
149 --- a/src/core/tests/interpreter_test.cpp
150 +++ b/src/core/tests/interpreter_test.cpp
151 @@ -25,6 +25,7 @@
152 #include <gtest/gtest.h>
153
154 #include "core/interpreter.h"
155 +#include "core/unset_exception.h"
156
157 using namespace std;
158
159 @@ -143,31 +144,71 @@ TEST(interpreter, get_array_values)
160 EXPECT_FALSE(walker.resolve_array("undefined", array_values));
161 }
162
163 -TEST(interpreter, unset_values)
164 +TEST(interpreter, unset_arrays)
165 {
166 interpreter walker;
167 std::map<int, std::string> values = {{0, "1"}, {1, "2"}, {2, "3"}};
168 walker.define("array", values);
169 walker.define("ro_array", values, true);
170 - walker.define("var", "123");
171 - walker.define("ro_var", "123", true);
172 -
173 + interpreter::local_scope temp_scope(walker);
174 + values[0] = "local";
175 + walker.define_local("array", values);
176 + walker.define_local("ro_local_array", values, true);
177 +
178 + // unset arrays
179 + EXPECT_STREQ("local", walker.resolve<string>("array", 0).c_str());
180 + // unset local
181 + walker.unset("array", 0);
182 + EXPECT_STREQ("", walker.resolve<string>("array", 0).c_str());
183 + // unset local
184 + walker.unset("array");
185 + // resolve to global
186 + EXPECT_STREQ("1", walker.resolve<string>("array", 0).c_str());
187 EXPECT_STREQ("2", walker.resolve<string>("array", 1).c_str());
188 - walker.unset("array", 1);
189 - EXPECT_STREQ("", walker.resolve<string>("array", 1).c_str());
190 + EXPECT_STREQ("3", walker.resolve<string>("array", 2).c_str());
191 + // unset global
192 walker.unset("array");
193 EXPECT_STREQ("", walker.resolve<string>("array", 0).c_str());
194 EXPECT_STREQ("", walker.resolve<string>("array", 1).c_str());
195 EXPECT_STREQ("", walker.resolve<string>("array", 2).c_str());
196 + walker.unset("array");
197 +
198 + EXPECT_THROW(walker.unset("ro_array", 1), unset_exception);
199 + EXPECT_THROW(walker.unset("ro_local_array", 1), unset_exception);
200 + EXPECT_THROW(walker.unset("ro_array"), unset_exception);
201 + EXPECT_THROW(walker.unset("ro_local_array"), unset_exception);
202 +
203 + EXPECT_THROW(walker.unset("1", 1), interpreter_exception);
204 +}
205
206 - EXPECT_THROW(walker.unset("ro_array", 1), interpreter_exception);
207 - EXPECT_THROW(walker.unset("ro_array"), interpreter_exception);
208 +TEST(interpreter, unset_variables)
209 +{
210 + interpreter walker;
211 + walker.define("var", "123");
212 + walker.define("ro_var", "123", true);
213 + interpreter::local_scope temp_scope(walker);
214 + walker.define_local("var", 456);
215 + walker.define_local("ro_local_var", 456, true);
216
217 + EXPECT_STREQ("456", walker.resolve<string>("var").c_str());
218 + walker.unset("var");
219 EXPECT_STREQ("123", walker.resolve<string>("var").c_str());
220 walker.unset("var");
221 EXPECT_STREQ("", walker.resolve<string>("var").c_str());
222 + walker.unset("var");
223 +
224 + EXPECT_THROW(walker.unset("ro_var"), unset_exception);
225 + EXPECT_THROW(walker.unset("ro_local_var"), unset_exception);
226 + EXPECT_THROW(walker.unset("1"), interpreter_exception);
227 +}
228
229 - EXPECT_THROW(walker.unset("ro_var"), interpreter_exception);
230 +TEST(interpreter, unset_functions)
231 +{
232 + interpreter walker;
233 + walker.define_function("foo", 0);
234 + EXPECT_TRUE(walker.has_function("foo"));
235 + walker.unset_function("foo");
236 + EXPECT_FALSE(walker.has_function("foo"));
237 }
238
239 TEST(interperter, substring_expansion_exception)
240
241 diff --git a/src/core/unset_exception.h b/src/core/unset_exception.h
242 new file mode 100644
243 index 0000000..7ee6c03
244 --- /dev/null
245 +++ b/src/core/unset_exception.h
246 @@ -0,0 +1,44 @@
247 +/*
248 + Please use git log for copyright holder and year information
249 +
250 + This file is part of libbash.
251 +
252 + libbash is free software: you can redistribute it and/or modify
253 + it under the terms of the GNU General Public License as published by
254 + the Free Software Foundation, either version 2 of the License, or
255 + (at your option) any later version.
256 +
257 + libbash is distributed in the hope that it will be useful,
258 + but WITHOUT ANY WARRANTY; without even the implied warranty of
259 + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
260 + GNU General Public License for more details.
261 +
262 + You should have received a copy of the GNU General Public License
263 + along with libbash. If not, see <http://www.gnu.org/licenses/>.
264 +*/
265 +///
266 +/// \file unset_exception.h
267 +/// \author Mu Qiao
268 +/// \brief implementation for unset_exception
269 +///
270 +
271 +#ifndef LIBBASH_CORE_UNSET_EXCEPTION_H_
272 +#define LIBBASH_CORE_UNSET_EXCEPTION_H_
273 +
274 +#include <stdexcept>
275 +#include <string>
276 +
277 +#include "interpreter_exception.h"
278 +
279 +///
280 +/// \class unset_exception
281 +/// \brief exception for unsetting variables
282 +///
283 +class unset_exception: public interpreter_exception
284 +{
285 +public:
286 + explicit unset_exception(const std::string& err_msg):
287 + interpreter_exception(err_msg){}
288 +};
289 +
290 +#endif