1 |
commit: 45746a47c5205d0b4f3729ef9fa9373894733c8c |
2 |
Author: Mu Qiao <qiaomuf <AT> gentoo <DOT> org> |
3 |
AuthorDate: Thu May 5 13:26:54 2011 +0000 |
4 |
Commit: Petteri Räty <betelgeuse <AT> gentoo <DOT> org> |
5 |
CommitDate: Sat May 7 12:13:40 2011 +0000 |
6 |
URL: http://git.overlays.gentoo.org/gitweb/?p=proj/libbash.git;a=commit;h=45746a47 |
7 |
|
8 |
Walker: support defining local variables |
9 |
|
10 |
--- |
11 |
bashast/libbashWalker.g | 20 ++++++++++++++---- |
12 |
scripts/function_def.bash | 10 +++++++++ |
13 |
scripts/function_def.bash.result | 1 + |
14 |
src/core/interpreter.cpp | 40 +++++++++++++++++++++++++++++++++---- |
15 |
src/core/interpreter.h | 39 +++++++++++++++++++++--------------- |
16 |
5 files changed, 84 insertions(+), 26 deletions(-) |
17 |
|
18 |
diff --git a/bashast/libbashWalker.g b/bashast/libbashWalker.g |
19 |
index 064556a..1a305ef 100644 |
20 |
--- a/bashast/libbashWalker.g |
21 |
+++ b/bashast/libbashWalker.g |
22 |
@@ -91,7 +91,11 @@ start: list|EOF; |
23 |
|
24 |
list: ^(LIST (function_def|logic_command_list)+); |
25 |
|
26 |
-variable_definitions: ^(VARIABLE_DEFINITIONS var_def+); |
27 |
+variable_definitions |
28 |
+@declarations { |
29 |
+ bool local = false; |
30 |
+} |
31 |
+ :^(VARIABLE_DEFINITIONS (LOCAL { local = true; })? var_def[local]+); |
32 |
|
33 |
name_base returns[std::string libbash_value] |
34 |
:NAME { $libbash_value = walker->get_string($NAME); } |
35 |
@@ -115,13 +119,16 @@ options{ k=1; } |
36 |
:DIGIT { $libbash_value = walker->get_string($DIGIT); } |
37 |
|NUMBER { $libbash_value = walker->get_string($NUMBER); }; |
38 |
|
39 |
-var_def |
40 |
+var_def[bool local] |
41 |
@declarations { |
42 |
std::map<int, std::string> values; |
43 |
unsigned index = 0; |
44 |
} |
45 |
:^(EQUALS name string_expr?) { |
46 |
- walker->set_value($name.libbash_value, $string_expr.libbash_value, $name.index); |
47 |
+ if(local) |
48 |
+ walker->define_local($name.libbash_value, $string_expr.libbash_value, false, $name.index); |
49 |
+ else |
50 |
+ walker->set_value($name.libbash_value, $string_expr.libbash_value, $name.index); |
51 |
} |
52 |
|^(EQUALS libbash_name=name_base ^(ARRAY ( |
53 |
(expr=string_expr |
54 |
@@ -130,7 +137,10 @@ var_def |
55 |
} expr=string_expr)) |
56 |
{ values[index++] = expr.libbash_value; })* |
57 |
)){ |
58 |
- walker->define(libbash_name, values); |
59 |
+ if(local) |
60 |
+ walker->define_local(libbash_name, values); |
61 |
+ else |
62 |
+ walker->define(libbash_name, values); |
63 |
}; |
64 |
|
65 |
string_expr returns[std::string libbash_value, bool quoted] |
66 |
@@ -282,7 +292,7 @@ simple_command |
67 |
@declarations { |
68 |
std::vector<std::string> libbash_args; |
69 |
} |
70 |
- :^(COMMAND string_expr (argument[libbash_args])* var_def*) { |
71 |
+ :^(COMMAND string_expr (argument[libbash_args])* var_def[true]*) { |
72 |
if(walker->has_function($string_expr.libbash_value)) |
73 |
{ |
74 |
walker->set_status(walker->call($string_expr.libbash_value, |
75 |
|
76 |
diff --git a/scripts/function_def.bash b/scripts/function_def.bash |
77 |
index 194d030..cbce4cd 100644 |
78 |
--- a/scripts/function_def.bash |
79 |
+++ b/scripts/function_def.bash |
80 |
@@ -26,3 +26,13 @@ FOO001="4 5" |
81 |
ARRAY=(1 2 3) |
82 |
func_with_args ${ARRAY[@]} $FOO001 |
83 |
func_with_args 100 $ARG2 $ARG3 $ARG4 |
84 |
+ |
85 |
+func_nested1() { |
86 |
+ echo $foo_nested ${bar_nested[0]} |
87 |
+} |
88 |
+func_nested2() { |
89 |
+ local foo_nested=hi bar_nested=(1 2 |
90 |
+ 3) |
91 |
+ func_nested1 |
92 |
+} |
93 |
+func_nested2 |
94 |
|
95 |
diff --git a/scripts/function_def.bash.result b/scripts/function_def.bash.result |
96 |
index de9f3f8..bfc30b5 100644 |
97 |
--- a/scripts/function_def.bash.result |
98 |
+++ b/scripts/function_def.bash.result |
99 |
@@ -1,3 +1,4 @@ |
100 |
+hi 1 |
101 |
ARG1=100 |
102 |
ARG2=2 |
103 |
ARG3=3 |
104 |
|
105 |
diff --git a/src/core/interpreter.cpp b/src/core/interpreter.cpp |
106 |
index 5363636..aa6c4de 100644 |
107 |
--- a/src/core/interpreter.cpp |
108 |
+++ b/src/core/interpreter.cpp |
109 |
@@ -24,6 +24,8 @@ |
110 |
|
111 |
#include "core/interpreter.h" |
112 |
|
113 |
+#include <cctype> |
114 |
+ |
115 |
#include <functional> |
116 |
|
117 |
#include <boost/algorithm/string/classification.hpp> |
118 |
@@ -31,6 +33,7 @@ |
119 |
#include <boost/algorithm/string/replace.hpp> |
120 |
#include <boost/algorithm/string/split.hpp> |
121 |
#include <boost/algorithm/string/trim.hpp> |
122 |
+#include <boost/foreach.hpp> |
123 |
#include <boost/range/adaptor/map.hpp> |
124 |
#include <boost/range/algorithm/copy.hpp> |
125 |
|
126 |
@@ -49,6 +52,33 @@ std::string interpreter::get_string(pANTLR3_BASE_TREE node) |
127 |
token->stop - token->start + 1); |
128 |
} |
129 |
|
130 |
+std::shared_ptr<variable> interpreter::resolve_variable(const std::string& name) const |
131 |
+{ |
132 |
+ if(name.empty()) |
133 |
+ throw interpreter_exception("Variable name shouldn't be empty"); |
134 |
+ // positional parameter |
135 |
+ if(isdigit(name[0]) && !local_members.empty()) |
136 |
+ { |
137 |
+ auto iter_local = local_members.back().find(name); |
138 |
+ if(iter_local != local_members.back().end()) |
139 |
+ return iter_local->second; |
140 |
+ } |
141 |
+ else |
142 |
+ { |
143 |
+ BOOST_REVERSE_FOREACH(auto& frame, local_members) |
144 |
+ { |
145 |
+ auto iter_local = frame.find(name); |
146 |
+ if(iter_local != frame.end()) |
147 |
+ return iter_local->second; |
148 |
+ } |
149 |
+ } |
150 |
+ |
151 |
+ auto iter_global = members.find(name); |
152 |
+ if(iter_global == members.end()) |
153 |
+ return std::shared_ptr<variable>(); |
154 |
+ return iter_global->second; |
155 |
+} |
156 |
+ |
157 |
bool interpreter::is_unset_or_null(const std::string& name, |
158 |
const unsigned index) const |
159 |
{ |
160 |
@@ -155,13 +185,13 @@ void interpreter::split_word(const std::string& word, std::vector<std::string>& |
161 |
output.insert(output.end(), splitted_values.begin(), splitted_values.end()); |
162 |
} |
163 |
|
164 |
-inline void define_function_arguments(std::unique_ptr<scope>& current_stack, |
165 |
+inline void define_function_arguments(scope& current_stack, |
166 |
const std::vector<std::string>& arguments) |
167 |
{ |
168 |
for(auto i = 0u; i != arguments.size(); ++i) |
169 |
{ |
170 |
const std::string& name = boost::lexical_cast<std::string>(i + 1); |
171 |
- (*current_stack)[name] = std::shared_ptr<variable>(new variable(name, arguments[i])); |
172 |
+ current_stack[name].reset(new variable(name, arguments[i])); |
173 |
} |
174 |
} |
175 |
|
176 |
@@ -177,8 +207,8 @@ int interpreter::call(const std::string& name, |
177 |
func_index = iter->second; |
178 |
|
179 |
// Prepare function stack and arguments |
180 |
- local_members.push(std::unique_ptr<scope>(new scope)); |
181 |
- define_function_arguments(local_members.top(), arguments); |
182 |
+ local_members.push_back(scope()); |
183 |
+ define_function_arguments(local_members.back(), arguments); |
184 |
|
185 |
auto INPUT = ctx->pTreeParser->ctnstream; |
186 |
auto ISTREAM = INPUT->tnstream->istream; |
187 |
@@ -192,7 +222,7 @@ int interpreter::call(const std::string& name, |
188 |
ISTREAM->seek(ISTREAM, curr); |
189 |
|
190 |
// Clear function stack |
191 |
- local_members.pop(); |
192 |
+ local_members.pop_back(); |
193 |
|
194 |
return 0; |
195 |
} |
196 |
|
197 |
diff --git a/src/core/interpreter.h b/src/core/interpreter.h |
198 |
index 35ae8ac..7673479 100644 |
199 |
--- a/src/core/interpreter.h |
200 |
+++ b/src/core/interpreter.h |
201 |
@@ -29,7 +29,6 @@ |
202 |
|
203 |
#include <functional> |
204 |
#include <memory> |
205 |
-#include <stack> |
206 |
#include <string> |
207 |
|
208 |
#include <antlr3basetree.h> |
209 |
@@ -60,7 +59,7 @@ class interpreter |
210 |
/// \var private::local_members |
211 |
/// \brief local scope for function arguments, execution environment and |
212 |
/// local variables |
213 |
- std::stack<std::unique_ptr<scope>> local_members; |
214 |
+ std::vector<scope> local_members; |
215 |
|
216 |
std::ostream* out; |
217 |
|
218 |
@@ -83,6 +82,8 @@ class interpreter |
219 |
const std::string& delim, |
220 |
std::string& result) const; |
221 |
|
222 |
+ std::shared_ptr<variable> resolve_variable(const std::string&) const; |
223 |
+ |
224 |
public: |
225 |
|
226 |
interpreter(): out(&std::cout), err(&std::cerr), in(&std::cin) |
227 |
@@ -401,17 +402,11 @@ public: |
228 |
template <typename T> |
229 |
T resolve(const std::string& name, const unsigned index=0) const |
230 |
{ |
231 |
- if(!local_members.empty()) |
232 |
- { |
233 |
- auto iter_local = local_members.top()->find(name); |
234 |
- if(iter_local != local_members.top()->end()) |
235 |
- return iter_local->second->get_value<T>(index); |
236 |
- } |
237 |
- |
238 |
- auto iter_global = members.find(name); |
239 |
- if(iter_global == members.end()) |
240 |
- return T(); |
241 |
- return iter_global->second->get_value<T>(index); |
242 |
+ auto var = resolve_variable(name); |
243 |
+ if(var) |
244 |
+ return var->get_value<T>(index); |
245 |
+ else |
246 |
+ return T{}; |
247 |
} |
248 |
|
249 |
/// \brief resolve array variable |
250 |
@@ -495,9 +490,21 @@ public: |
251 |
bool readonly=false, |
252 |
const unsigned index=0) |
253 |
{ |
254 |
- std::shared_ptr<variable> target( |
255 |
- new variable(name, value, readonly, index)); |
256 |
- members[name] = target; |
257 |
+ members[name].reset(new variable(name, value, readonly, index)); |
258 |
+ } |
259 |
+ |
260 |
+ /// \brief define a new local variable |
261 |
+ /// \param the name of the variable |
262 |
+ /// \param the value of the variable |
263 |
+ /// \param whether it's readonly, default is false |
264 |
+ /// \param whether it's null, default is false |
265 |
+ template <typename T> |
266 |
+ void define_local(const std::string& name, |
267 |
+ const T& value, |
268 |
+ bool readonly=false, |
269 |
+ const unsigned index=0) |
270 |
+ { |
271 |
+ local_members.back()[name].reset(new variable(name, value, readonly, index)); |
272 |
} |
273 |
|
274 |
/// \brief define a new function |