From 6d95304b292a398ddfd42a2ef1115cf8e94928b5 Mon Sep 17 00:00:00 2001 From: Mu Qiao Date: Mon, 26 Mar 2012 17:34:49 +0800 Subject: Walker: support appending array to array --- bashast/libbashWalker.g | 29 ++++++++++++++++++++++------- scripts/var_def.bash | 8 ++++++++ src/core/interpreter.h | 9 +++++++++ src/core/symbols.hpp | 5 +++++ src/core/tests/interpreter_test.cpp | 9 +++++++++ 5 files changed, 53 insertions(+), 7 deletions(-) diff --git a/bashast/libbashWalker.g b/bashast/libbashWalker.g index 5e3fd6e..5d5b557 100644 --- a/bashast/libbashWalker.g +++ b/bashast/libbashWalker.g @@ -217,19 +217,34 @@ var_def[bool local] else walker->set_value($name.libbash_value, $string_expr.libbash_value, $name.index); } - |^(EQUALS libbash_name=name_base ^(ARRAY ( - (expr=string_expr - |^(EQUALS value=arithmetics { - set_index(libbash_name, index, value); - } expr=string_expr)) - { values[index++] = expr.libbash_value; })* - )){ + |^(EQUALS libbash_name=name_base array_def_helper[libbash_name, values, index]){ if(local) walker->define_local(libbash_name, values); else walker->define(libbash_name, values); + } + |^(PLUS_ASSIGN libbash_name=name_base { + index = walker->get_max_index(libbash_name) + 1; + if(index == 1) // The variable is not defined + index = 0; + } array_def_helper[libbash_name, values, index]){ + if(local) + throw libbash::unsupported_exception("Appending array to local variable is not supported"); + for(auto iter = values.begin(); iter != values.end(); ++iter) + walker->set_value(libbash_name, iter->second, iter->first); }; +array_def_helper[const std::string& libbash_name, std::map& values, unsigned index] + :^(ARRAY ( + ( + expr=string_expr + |^(EQUALS value=arithmetics { + set_index(libbash_name, index, value); + } expr=string_expr) + ) + { values[index++] = expr.libbash_value; } + )*); + string_expr returns[std::string libbash_value, bool quoted] @init { $quoted = true; diff --git a/scripts/var_def.bash b/scripts/var_def.bash index e757b16..96747c0 100644 --- a/scripts/var_def.bash +++ b/scripts/var_def.bash @@ -88,3 +88,11 @@ function foo() { foo bar=@ echo $bar +ARRAY11=(1 2 3 [10]=15) +ARRAY11+=(1 [15]=20) +echo ${ARRAY11[@]} +ARRAY12+=(4 5 6) +echo ${ARRAY12[@]} +ARRAY13=() +ARRAY13+=(4 5 6) +echo ${ARRAY13[@]} diff --git a/src/core/interpreter.h b/src/core/interpreter.h index fcc3294..fbb9d48 100644 --- a/src/core/interpreter.h +++ b/src/core/interpreter.h @@ -461,6 +461,15 @@ public: /// \return the length of the array variable::size_type get_array_length(const std::string& name) const; + /// \brief get the max index of an array + /// \param name the name of the array + /// \return the max index of the array + variable::size_type get_max_index(const std::string& name) const + { + auto var = resolve_variable(name); + return var ? var->get_max_index() : 0; + } + /// \brief get all array elements concatenated by space /// \param name the name of the array /// \param[out] result the concatenated string diff --git a/src/core/symbols.hpp b/src/core/symbols.hpp index 8dd8cd3..e9cb019 100644 --- a/src/core/symbols.hpp +++ b/src/core/symbols.hpp @@ -215,6 +215,11 @@ public: return value.size(); } + size_type get_max_index() const + { + return value.size() == 0 ? 0 : value.rbegin()->first; + } + /// \brief check whether the value of the variable is null /// \return whether the value of the variable is null bool is_unset(const unsigned index=0) const diff --git a/src/core/tests/interpreter_test.cpp b/src/core/tests/interpreter_test.cpp index ecbcfd9..c3278d0 100644 --- a/src/core/tests/interpreter_test.cpp +++ b/src/core/tests/interpreter_test.cpp @@ -146,6 +146,15 @@ TEST(interpreter, get_array_values) EXPECT_FALSE(walker.resolve_array("undefined", array_values)); } +TEST(interpreter, get_max_index) +{ + interpreter walker; + std::map values = {{0, "1"}, {1, "2"}, {5, "3"}}; + walker.define("array", values); + + EXPECT_EQ(5, walker.get_max_index("array")); +} + TEST(interpreter, unset_arrays) { interpreter walker; -- cgit v1.2.3-65-gdbad