* [gentoo-commits] proj/libbash:master commit in: scripts/, src/core/, bashast/, src/core/tests/
@ 2012-06-03 9:08 Petteri Räty
0 siblings, 0 replies; 7+ messages in thread
From: Petteri Räty @ 2012-06-03 9:08 UTC (permalink / raw
To: gentoo-commits
commit: 6d95304b292a398ddfd42a2ef1115cf8e94928b5
Author: Mu Qiao <qiaomuf <AT> gentoo <DOT> org>
AuthorDate: Mon Mar 26 09:34:49 2012 +0000
Commit: Petteri Räty <betelgeuse <AT> gentoo <DOT> org>
CommitDate: Mon Mar 26 12:04:42 2012 +0000
URL: http://git.overlays.gentoo.org/gitweb/?p=proj/libbash.git;a=commit;h=6d95304b
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<unsigned, std::string>& 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<unsigned, std::string> 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;
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [gentoo-commits] proj/libbash:master commit in: scripts/, src/core/, bashast/, src/core/tests/
@ 2011-06-03 12:43 Petteri Räty
0 siblings, 0 replies; 7+ messages in thread
From: Petteri Räty @ 2011-06-03 12:43 UTC (permalink / raw
To: gentoo-commits
commit: 7404d1ac1630b41a94edcfe791dcda1473d11437
Author: Mu Qiao <qiaomuf <AT> gentoo <DOT> org>
AuthorDate: Wed Jun 1 10:17:57 2011 +0000
Commit: Petteri Räty <betelgeuse <AT> gentoo <DOT> org>
CommitDate: Wed Jun 1 13:27:34 2011 +0000
URL: http://git.overlays.gentoo.org/gitweb/?p=proj/libbash.git;a=commit;h=7404d1ac
Core: support arithmetic expression in keyword test
---
bashast/libbashWalker.g | 2 +-
scripts/test_expr.bash | 4 ++
scripts/test_expr.bash.result | 1 +
src/core/bash_condition.cpp | 17 +++++----
src/core/bash_condition.h | 5 ++-
src/core/interpreter.cpp | 7 ++++
src/core/interpreter.h | 5 +++
src/core/tests/bash_condition_test.cpp | 62 ++++++++++++++++++--------------
8 files changed, 67 insertions(+), 36 deletions(-)
diff --git a/bashast/libbashWalker.g b/bashast/libbashWalker.g
index a55e0b2..ec3897d 100644
--- a/bashast/libbashWalker.g
+++ b/bashast/libbashWalker.g
@@ -556,7 +556,7 @@ common_condition returns[bool status]
}
// -eq, -ne, -lt, -le, -gt, or -ge for arithmetic. -nt -ot -ef for files
:^(NAME left_str=string_expr right_str=string_expr) {
- $status = internal::test_binary(walker->get_string($NAME), left_str.libbash_value, right_str.libbash_value);
+ $status = internal::test_binary(walker->get_string($NAME), left_str.libbash_value, right_str.libbash_value, *walker);
}
// -o for shell option, -z -n for string, -abcdefghkprstuwxOGLSN for files
|^(op=LETTER string_expr) {
diff --git a/scripts/test_expr.bash b/scripts/test_expr.bash
index 79398dd..1fa00b4 100644
--- a/scripts/test_expr.bash
+++ b/scripts/test_expr.bash
@@ -44,3 +44,7 @@ echo $? # 0
[[ "abc def xyz" != *"defg"* ]] && echo "true14"
shopt -s extglob
[[ "123" == *([[:digit:]]) ]] && echo "true15"
+i=2
+[[ i++ -gt 2 ]] && echo wrong
+[[ i++ -gt 2 ]] && echo true16
+unset i
diff --git a/scripts/test_expr.bash.result b/scripts/test_expr.bash.result
index 653200b..e883295 100644
--- a/scripts/test_expr.bash.result
+++ b/scripts/test_expr.bash.result
@@ -22,3 +22,4 @@ true12
true13
true14
true15
+true16
diff --git a/src/core/bash_condition.cpp b/src/core/bash_condition.cpp
index 48b523e..1e44299 100644
--- a/src/core/bash_condition.cpp
+++ b/src/core/bash_condition.cpp
@@ -27,6 +27,8 @@
#include <sys/stat.h>
#include <unistd.h>
+#include "core/bash_ast.h"
+#include "core/interpreter.h"
#include "core/interpreter_exception.h"
#include "core/bash_condition.h"
@@ -147,7 +149,8 @@ namespace
bool internal::test_binary(const std::string& op,
const std::string& lhs,
- const std::string& rhs)
+ const std::string& rhs,
+ interpreter& walker)
{
if(op.size() != 2)
throw interpreter_exception("Unrecognized operator " + op);
@@ -163,17 +166,17 @@ bool internal::test_binary(const std::string& op,
// We do not support arithmetic expressions inside keyword test for now.
// So the operands can only be raw integers.
else if(op == "eq")
- return boost::lexical_cast<int>(lhs) == boost::lexical_cast<int>(rhs);
+ return walker.eval_arithmetic(lhs) == walker.eval_arithmetic(rhs);
else if(op == "ne")
- return boost::lexical_cast<int>(lhs) != boost::lexical_cast<int>(rhs);
+ return walker.eval_arithmetic(lhs) != walker.eval_arithmetic(rhs);
else if(op == "lt")
- return boost::lexical_cast<int>(lhs) < boost::lexical_cast<int>(rhs);
+ return walker.eval_arithmetic(lhs) < walker.eval_arithmetic(rhs);
else if(op == "le")
- return boost::lexical_cast<int>(lhs) <= boost::lexical_cast<int>(rhs);
+ return walker.eval_arithmetic(lhs) <= walker.eval_arithmetic(rhs);
else if(op == "gt")
- return boost::lexical_cast<int>(lhs) > boost::lexical_cast<int>(rhs);
+ return walker.eval_arithmetic(lhs) > walker.eval_arithmetic(rhs);
else if(op == "ge")
- return boost::lexical_cast<int>(lhs) >= boost::lexical_cast<int>(rhs);
+ return walker.eval_arithmetic(lhs) >= walker.eval_arithmetic(rhs);
else
throw interpreter_exception("Unrecognized operator " + op);
}
diff --git a/src/core/bash_condition.h b/src/core/bash_condition.h
index 8723c28..2df1ec7 100644
--- a/src/core/bash_condition.h
+++ b/src/core/bash_condition.h
@@ -26,13 +26,16 @@
#include <string>
+class interpreter;
+
namespace internal
{
bool test_unary(char op, const std::string& target);
bool test_binary(const std::string& op,
const std::string& lhs,
- const std::string& rhs);
+ const std::string& rhs,
+ interpreter& walker);
}
#endif
diff --git a/src/core/interpreter.cpp b/src/core/interpreter.cpp
index fc12a7a..83fd29a 100644
--- a/src/core/interpreter.cpp
+++ b/src/core/interpreter.cpp
@@ -35,6 +35,7 @@
#include <boost/range/adaptor/map.hpp>
#include <boost/range/algorithm/copy.hpp>
+#include "core/bash_ast.h"
#include "core/unset_exception.h"
#include "libbashWalker.h"
@@ -412,3 +413,9 @@ void interpreter::set_option(const std::string& name, bool value)
iter->second = value;
}
+
+int interpreter::eval_arithmetic(const std::string& expression)
+{
+ bash_ast ast(std::stringstream(expression), &bash_ast::parser_arithmetics);
+ return ast.interpret_with(*this, &bash_ast::walker_arithmetics);
+}
diff --git a/src/core/interpreter.h b/src/core/interpreter.h
index 3420ee4..dc2a9bc 100644
--- a/src/core/interpreter.h
+++ b/src/core/interpreter.h
@@ -675,6 +675,11 @@ public:
/// \return zero unless the name is not a valid shell option
void set_option(const std::string& name, bool value);
+ /// \brief evaluate arithmetic expression and return the result
+ /// \param the arithmetic expression
+ /// \return the evaluated result
+ int eval_arithmetic(const std::string& expression);
+
/// \brief perform expansion like ${var//foo/bar}
/// \param the value to be expanded
/// \param the pattern used to match the value
diff --git a/src/core/tests/bash_condition_test.cpp b/src/core/tests/bash_condition_test.cpp
index de56fee..18a4e18 100644
--- a/src/core/tests/bash_condition_test.cpp
+++ b/src/core/tests/bash_condition_test.cpp
@@ -31,6 +31,7 @@
#include <gtest/gtest.h>
#include "core/bash_condition.h"
+#include "core/interpreter.h"
#include "core/interpreter_exception.h"
namespace
@@ -140,45 +141,52 @@ TEST(bash_condition, string_unary_operator)
TEST_F(file_test, binary_operator)
{
- EXPECT_TRUE(internal::test_binary("nt", negative, positive));
- EXPECT_FALSE(internal::test_binary("ot", negative, positive));
+ interpreter walker;
+ EXPECT_TRUE(internal::test_binary("nt", negative, positive, walker));
+ EXPECT_FALSE(internal::test_binary("ot", negative, positive, walker));
- EXPECT_TRUE(internal::test_binary("ot", positive, negative));
- EXPECT_FALSE(internal::test_binary("nt", positive, negative));
+ EXPECT_TRUE(internal::test_binary("ot", positive, negative, walker));
+ EXPECT_FALSE(internal::test_binary("nt", positive, negative, walker));
- EXPECT_FALSE(internal::test_binary("ot", positive, positive));
- EXPECT_FALSE(internal::test_binary("nt", positive, positive));
+ EXPECT_FALSE(internal::test_binary("ot", positive, positive, walker));
+ EXPECT_FALSE(internal::test_binary("nt", positive, positive, walker));
- EXPECT_TRUE(internal::test_binary("ef", positive, positive));
- EXPECT_FALSE(internal::test_binary("ef", positive, negative));
- EXPECT_FALSE(internal::test_binary("ef", "not exist", negative));
+ EXPECT_TRUE(internal::test_binary("ef", positive, positive, walker));
+ EXPECT_FALSE(internal::test_binary("ef", positive, negative, walker));
+ EXPECT_FALSE(internal::test_binary("ef", "not exist", negative, walker));
- EXPECT_THROW(internal::test_binary("efd", positive, negative), interpreter_exception);
+ EXPECT_THROW(internal::test_binary("efd", positive, negative, walker), interpreter_exception);
}
TEST(bash_condition, arithmetic_operator)
{
- EXPECT_TRUE(internal::test_binary("eq", "1", "1"));
- EXPECT_FALSE(internal::test_binary("eq", "2", "1"));
+ interpreter walker;
+ walker.define("foo", 1);
- EXPECT_TRUE(internal::test_binary("ne", "2", "1"));
- EXPECT_FALSE(internal::test_binary("ne", "1", "1"));
+ EXPECT_TRUE(internal::test_binary("eq", "1", "1", walker));
+ EXPECT_FALSE(internal::test_binary("eq", "2", "1", walker));
- EXPECT_TRUE(internal::test_binary("lt", "0", "1"));
- EXPECT_FALSE(internal::test_binary("lt", "1", "1"));
- EXPECT_FALSE(internal::test_binary("lt", "2", "1"));
+ EXPECT_TRUE(internal::test_binary("ne", "2", "1", walker));
+ EXPECT_FALSE(internal::test_binary("ne", "1", "1", walker));
- EXPECT_TRUE(internal::test_binary("le", "0", "1"));
- EXPECT_TRUE(internal::test_binary("le", "1", "1"));
- EXPECT_FALSE(internal::test_binary("le", "2", "1"));
+ EXPECT_TRUE(internal::test_binary("lt", "0", "1", walker));
+ EXPECT_FALSE(internal::test_binary("lt", "1", "1", walker));
+ EXPECT_FALSE(internal::test_binary("lt", "2", "1", walker));
- EXPECT_TRUE(internal::test_binary("gt", "1", "0"));
- EXPECT_FALSE(internal::test_binary("gt", "1", "1"));
- EXPECT_FALSE(internal::test_binary("gt", "0", "1"));
+ EXPECT_TRUE(internal::test_binary("le", "0", "1", walker));
+ EXPECT_TRUE(internal::test_binary("le", "1", "1", walker));
+ EXPECT_FALSE(internal::test_binary("le", "2", "1", walker));
- EXPECT_TRUE(internal::test_binary("ge", "1", "1"));
- EXPECT_TRUE(internal::test_binary("ge", "2", "1"));
- EXPECT_FALSE(internal::test_binary("ge", "0", "1"));
+ EXPECT_TRUE(internal::test_binary("gt", "1", "0", walker));
+ EXPECT_FALSE(internal::test_binary("gt", "1", "1", walker));
+ EXPECT_FALSE(internal::test_binary("gt", "0", "1", walker));
- EXPECT_FALSE(internal::test_binary("ge", "blah", "1"));
+ EXPECT_TRUE(internal::test_binary("ge", "1", "1", walker));
+ EXPECT_TRUE(internal::test_binary("ge", "2", "1", walker));
+ EXPECT_FALSE(internal::test_binary("ge", "0", "1", walker));
+
+ EXPECT_FALSE(internal::test_binary("ge", "blah", "1", walker));
+
+ EXPECT_FALSE(internal::test_binary("ge", "foo++", "2", walker));
+ EXPECT_TRUE(internal::test_binary("ge", "foo++", "2", walker));
}
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [gentoo-commits] proj/libbash:master commit in: scripts/, src/core/, bashast/, src/core/tests/
@ 2011-05-23 14:34 Petteri Räty
0 siblings, 0 replies; 7+ messages in thread
From: Petteri Räty @ 2011-05-23 14:34 UTC (permalink / raw
To: gentoo-commits
commit: 1b777e0ff35171fc0778e051c55e782d5eb4a0ad
Author: Mu Qiao <qiaomuf <AT> gentoo <DOT> org>
AuthorDate: Sat May 21 05:04:53 2011 +0000
Commit: Petteri Räty <betelgeuse <AT> gentoo <DOT> org>
CommitDate: Mon May 23 15:04:45 2011 +0000
URL: http://git.overlays.gentoo.org/gitweb/?p=proj/libbash.git;a=commit;h=1b777e0f
Walker: support ${*:x:y} expansion
We don't support $0 for now so ${*:0:x} will give you a wrong script
name.
---
bashast/bashast.g | 8 +++---
bashast/libbashWalker.g | 3 +-
scripts/var_expansion.bash | 9 +++++++
scripts/var_expansion.bash.result | 6 ++++
src/core/interpreter.cpp | 49 +++++++++++++++++++++++++++++++------
src/core/interpreter.h | 10 +++++--
src/core/symbols.hpp | 5 +---
src/core/tests/symbols_test.cpp | 5 ++-
8 files changed, 73 insertions(+), 22 deletions(-)
diff --git a/bashast/bashast.g b/bashast/bashast.g
index 404de43..693ee96 100644
--- a/bashast/bashast.g
+++ b/bashast/bashast.g
@@ -280,9 +280,7 @@ var_exp : var_name (
| LSQUARE (op=TIMES|op=AT) RSQUARE -> ^(LIST_EXPAND var_name_for_bang $op)
| -> ^(VAR_REF var_name_for_bang)
)
- | var_size_ref
- | TIMES
- | AT;
+ | var_size_ref;
parameter_delete_operator
: POUND -> LAZY_REMOVE_AT_START
| POUNDPOUND -> REPLACE_AT_START
@@ -312,7 +310,9 @@ parameter_replace_operator
//either directly or through array
var_name
: num
- | var_name_no_digit;
+ | var_name_no_digit
+ | TIMES
+ | AT;
//Inside arithmetic we can't allow digits
var_name_no_digit
: name^ LSQUARE! (AT|TIMES|explicit_arithmetic) RSQUARE!
diff --git a/bashast/libbashWalker.g b/bashast/libbashWalker.g
index 07d0f84..55aab88 100644
--- a/bashast/libbashWalker.g
+++ b/bashast/libbashWalker.g
@@ -327,7 +327,8 @@ var_name returns[std::string libbash_value, unsigned index]
|name {
$libbash_value = $name.libbash_value;
$index = $name.index;
- };
+ }
+ |TIMES { $libbash_value = "*"; };
var_expansion returns[std::string libbash_value]
@declarations {
diff --git a/scripts/var_expansion.bash b/scripts/var_expansion.bash
index 8db702d..8fcb943 100644
--- a/scripts/var_expansion.bash
+++ b/scripts/var_expansion.bash
@@ -82,3 +82,12 @@ FOO080=${FOO039/@([a-c]|[k-m])}
FOO081=${FOO039//@([a-c]|[k-m])}
target="abc123abc"
FOO082="${target##+(ab[c])*([[:digit:]])}"
+function positional_parameter_test(){
+ FOO083=${*}
+ FOO084=${*:1}
+ FOO085=${*:1:2}
+ FOO086=${*: -1}
+ FOO087=${*: -2:5}
+ FOO088=${*:0}
+}
+positional_parameter_test 1 2 3 4 5
diff --git a/scripts/var_expansion.bash.result b/scripts/var_expansion.bash.result
index c01e769..5ec7c65 100644
--- a/scripts/var_expansion.bash.result
+++ b/scripts/var_expansion.bash.result
@@ -83,4 +83,10 @@ FOO079=H Wrd
FOO080=Helo World
FOO081=Heo Word
FOO082=abc
+FOO083=1 2 3 4 5
+FOO084=1 2 3 4 5
+FOO085=1 2
+FOO086=5
+FOO087=4 5
+FOO088=filename 1 2 3 4 5
target=abc123abc
diff --git a/src/core/interpreter.cpp b/src/core/interpreter.cpp
index 80bc8be..7e7de9c 100644
--- a/src/core/interpreter.cpp
+++ b/src/core/interpreter.cpp
@@ -89,14 +89,49 @@ bool interpreter::is_unset_or_null(const std::string& name,
return i->second->is_null(index);
}
+// This method temporarily supports array offset expansion for $* and $@.
+// That logic will be refactored and applied to normal array variables in future.
+std::string interpreter::get_substring(const std::string& name,
+ int offset,
+ int length,
+ const unsigned index) const
+{
+ if(name != "*" && name != "@")
+ {
+ std::string value = resolve<std::string>(name, index);
+ if(!get_real_offset(offset, value.size()))
+ return "";
+ return value.substr(offset, length);
+ }
+ else
+ {
+ std::vector<std::string> array;
+ // ${*:1} has the same content as ${*}, ${*:0} contains current script name as the first element
+ if(offset > 0)
+ offset--;
+ else if(offset == 0)
+ // Need to replace this with the real script name
+ array.push_back("filename");
+ if(resolve_array(name, array) && get_real_offset(offset, array.size()))
+ {
+ int max_length = array.size() - offset;
+ if(length == -1 || length > max_length)
+ length = max_length;
+ return boost::algorithm::join(
+ std::vector<std::string>(array.begin() + offset,
+ array.begin() + offset + length),
+ resolve<std::string>("IFS").substr(0, 1));
+ }
+ else
+ return "";
+ }
+}
+
const std::string interpreter::do_substring_expansion(const std::string& name,
int offset,
const unsigned index) const
{
- std::string value = resolve<std::string>(name, index);
- if(!get_real_offset(offset, value))
- return "";
- return value.substr(offset);
+ return get_substring(name, offset, -1, index);
}
const std::string interpreter::do_substring_expansion(const std::string& name,
@@ -106,10 +141,8 @@ const std::string interpreter::do_substring_expansion(const std::string& name,
{
if(length < 0)
throw interpreter_exception("length of substring expression should be greater or equal to zero");
- std::string value = resolve<std::string>(name, index);
- if(!get_real_offset(offset, value))
- return "";
- return value.substr(offset, length);
+
+ return get_substring(name, offset, length, index);
}
std::string interpreter::do_replace_expansion(const std::string& name,
diff --git a/src/core/interpreter.h b/src/core/interpreter.h
index aa13b4e..4c6f69c 100644
--- a/src/core/interpreter.h
+++ b/src/core/interpreter.h
@@ -73,10 +73,10 @@ class interpreter
/// \param[in,out] a value/result argument referring to offset
/// \param[in] the original string
/// \return whether the real offset is in legal range
- bool get_real_offset(int& offset, const std::string& str) const
+ bool get_real_offset(int& offset, const int size) const
{
- offset = (offset >= 0? offset : str.size() + offset);
- return !(offset < 0 || offset >= static_cast<int>(str.size()));
+ offset = (offset >= 0? offset : size + offset);
+ return !(offset < 0 || offset >= size);
}
void get_all_elements_joined(const std::string& name,
@@ -88,6 +88,10 @@ class interpreter
void define_function_arguments(scope& current_stack,
const std::vector<std::string>& arguments);
+ std::string get_substring(const std::string& name,
+ int offset,
+ int length,
+ const unsigned index) const;
public:
///
diff --git a/src/core/symbols.hpp b/src/core/symbols.hpp
index 2d6b6a5..8ceb25a 100644
--- a/src/core/symbols.hpp
+++ b/src/core/symbols.hpp
@@ -159,15 +159,12 @@ public:
}
/// \brief retrieve all values of the array
- /// \param[out] vector that stores all array values, values in the arrays will
- /// be cleared first
+ /// \param[out] vector that stores all array values
template<typename T>
void get_all_values(std::vector<T>& all_values) const
{
static converter<T> visitor;
- all_values.clear();
-
for(auto iter = value.begin(); iter != value.end(); ++iter)
all_values.push_back(
boost::apply_visitor(visitor, iter->second));
diff --git a/src/core/tests/symbols_test.cpp b/src/core/tests/symbols_test.cpp
index 5853a4f..358f5b6 100644
--- a/src/core/tests/symbols_test.cpp
+++ b/src/core/tests/symbols_test.cpp
@@ -109,9 +109,10 @@ TEST(symbol_test, get_all_values)
EXPECT_STREQ("3", string_values[2].c_str());
variable a_string("foo", 10);
+ // Won't clear the original vector
a_string.get_all_values(string_values);
- EXPECT_EQ(1, string_values.size());
- EXPECT_STREQ("10", string_values[0].c_str());
+ EXPECT_EQ(4, string_values.size());
+ EXPECT_STREQ("1", string_values[0].c_str());
variable an_int("foo", 10);
vector<int> int_values;
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [gentoo-commits] proj/libbash:master commit in: scripts/, src/core/, bashast/, src/core/tests/
@ 2011-05-22 21:00 Petteri Räty
0 siblings, 0 replies; 7+ messages in thread
From: Petteri Räty @ 2011-05-22 21:00 UTC (permalink / raw
To: gentoo-commits
commit: 13f7e362484d1f486bd51be08e99da397fba2d4f
Author: Mu Qiao <qiaomuf <AT> gentoo <DOT> org>
AuthorDate: Wed May 18 07:47:35 2011 +0000
Commit: Petteri Räty <betelgeuse <AT> gentoo <DOT> org>
CommitDate: Sun May 22 16:16:34 2011 +0000
URL: http://git.overlays.gentoo.org/gitweb/?p=proj/libbash.git;a=commit;h=13f7e362
Walker: support binary operators in keyword test
We do not support arithmetic expressions inside keyword test for
now.
---
bashast/libbashWalker.g | 4 +-
scripts/test_expr.bash | 2 +
scripts/test_expr.bash.result | 2 +
src/core/bash_condition.cpp | 69 ++++++++++++++++++++++++++++++++
src/core/bash_condition.h | 4 ++
src/core/tests/bash_condition_test.cpp | 42 +++++++++++++++++++-
6 files changed, 121 insertions(+), 2 deletions(-)
diff --git a/bashast/libbashWalker.g b/bashast/libbashWalker.g
index 737c7a7..1ae6616 100644
--- a/bashast/libbashWalker.g
+++ b/bashast/libbashWalker.g
@@ -509,7 +509,9 @@ cond_expr
common_condition returns[bool status]
// -eq, -ne, -lt, -le, -gt, or -ge for arithmetic. -nt -ot -ef for files
- :^(NAME left_str=string_expr right_str=string_expr)
+ :^(NAME left_str=string_expr right_str=string_expr) {
+ $status = internal::test_binary(walker->get_string($NAME), left_str.libbash_value, right_str.libbash_value);
+ }
// -o for shell option, -z -n for string, -abcdefghkprstuwxOGLSN for files
|^(op=LETTER string_expr) {
$status = internal::test_unary(*reinterpret_cast<const char *>(op->getToken(op)->start),
diff --git a/scripts/test_expr.bash b/scripts/test_expr.bash
index 91c24fd..f89287b 100644
--- a/scripts/test_expr.bash
+++ b/scripts/test_expr.bash
@@ -36,3 +36,5 @@ echo $? # 0
# abc=bcd is treated as a simple string
[[ abc=bcd && abc == abc ]] || echo wrong
[[ -a "/" ]] && echo "true10"
+[[ . -ef . ]] && echo "true11"
+[[ 2 -ge 2 ]] && echo "true12"
diff --git a/scripts/test_expr.bash.result b/scripts/test_expr.bash.result
index 4be03db..d045597 100644
--- a/scripts/test_expr.bash.result
+++ b/scripts/test_expr.bash.result
@@ -17,3 +17,5 @@ true7
true8
true9
true10
+true11
+true12
diff --git a/src/core/bash_condition.cpp b/src/core/bash_condition.cpp
index 61a5826..48b523e 100644
--- a/src/core/bash_condition.cpp
+++ b/src/core/bash_condition.cpp
@@ -113,3 +113,72 @@ bool internal::test_unary(char op, const std::string& target)
return test_file_stat(op, target);
}
}
+
+namespace
+{
+ bool file_comp(char op,
+ const std::string& lhs,
+ const std::string& rhs)
+ {
+ struct stat lst, rst;
+ int lstatus, rstatus;
+
+ lstatus = stat(lhs.c_str(), &lst);
+ rstatus = stat(rhs.c_str(), &rst);
+ if(op == 'e' && (lstatus < 0 || rstatus < 0))
+ return false;
+
+ switch(op)
+ {
+ case 'n':
+ /* -nt */
+ return ((lstatus > rstatus) || (lstatus == 0 && lst.st_mtime > rst.st_mtime));
+ case 'o':
+ /* -ot */
+ return ((lstatus < rstatus) || (rstatus == 0 && lst.st_mtime < rst.st_mtime));
+ case 'e':
+ /* -ef */
+ return (lst.st_dev == rst.st_dev && lst.st_ino == rst.st_ino);
+ default:
+ throw interpreter_exception(std::string("Unrecognized option for file test ") + op);
+ }
+ }
+}
+
+bool internal::test_binary(const std::string& op,
+ const std::string& lhs,
+ const std::string& rhs)
+{
+ if(op.size() != 2)
+ throw interpreter_exception("Unrecognized operator " + op);
+
+ try
+ {
+ if(op == "nt")
+ return file_comp('n', lhs, rhs);
+ else if(op == "ot")
+ return file_comp('o', lhs, rhs);
+ else if(op == "ef")
+ return file_comp('e', lhs, rhs);
+ // We do not support arithmetic expressions inside keyword test for now.
+ // So the operands can only be raw integers.
+ else if(op == "eq")
+ return boost::lexical_cast<int>(lhs) == boost::lexical_cast<int>(rhs);
+ else if(op == "ne")
+ return boost::lexical_cast<int>(lhs) != boost::lexical_cast<int>(rhs);
+ else if(op == "lt")
+ return boost::lexical_cast<int>(lhs) < boost::lexical_cast<int>(rhs);
+ else if(op == "le")
+ return boost::lexical_cast<int>(lhs) <= boost::lexical_cast<int>(rhs);
+ else if(op == "gt")
+ return boost::lexical_cast<int>(lhs) > boost::lexical_cast<int>(rhs);
+ else if(op == "ge")
+ return boost::lexical_cast<int>(lhs) >= boost::lexical_cast<int>(rhs);
+ else
+ throw interpreter_exception("Unrecognized operator " + op);
+ }
+ catch(boost::bad_lexical_cast& e)
+ {
+ return false;
+ }
+}
diff --git a/src/core/bash_condition.h b/src/core/bash_condition.h
index 4e9cfa3..8723c28 100644
--- a/src/core/bash_condition.h
+++ b/src/core/bash_condition.h
@@ -29,6 +29,10 @@
namespace internal
{
bool test_unary(char op, const std::string& target);
+
+ bool test_binary(const std::string& op,
+ const std::string& lhs,
+ const std::string& rhs);
}
#endif
diff --git a/src/core/tests/bash_condition_test.cpp b/src/core/tests/bash_condition_test.cpp
index 8bcf4b3..57ab4e9 100644
--- a/src/core/tests/bash_condition_test.cpp
+++ b/src/core/tests/bash_condition_test.cpp
@@ -63,7 +63,7 @@ namespace
) << "Can't create " << positive << " for test";
set_time(positive, 0, 0);
EXPECT_NE(-1, creat(negative.c_str(), 0)) << "Can't create " << negative << " for test";
- set_time(negative, 1, 0);
+ set_time(negative, 2, 1);
EXPECT_EQ(0, symlink(positive.c_str(), test_link.c_str()));
EXPECT_EQ(0, mkfifo(test_fifo.c_str(), 0));
}
@@ -137,3 +137,43 @@ TEST(bash_condition, string_unary_operator)
EXPECT_THROW(internal::test_unary('o', "extglob"), interpreter_exception);
}
+
+TEST_F(file_test, binary_operator)
+{
+ EXPECT_TRUE(internal::test_binary("nt", negative, positive));
+ EXPECT_FALSE(internal::test_binary("ot", negative, positive));
+
+ EXPECT_TRUE(internal::test_binary("ot", positive, negative));
+ EXPECT_FALSE(internal::test_binary("nt", positive, negative));
+
+ EXPECT_FALSE(internal::test_binary("ot", positive, positive));
+ EXPECT_FALSE(internal::test_binary("nt", positive, positive));
+
+ EXPECT_TRUE(internal::test_binary("ef", positive, positive));
+ EXPECT_FALSE(internal::test_binary("ef", positive, negative));
+}
+
+TEST(bash_condition, arithmetic_operator)
+{
+ EXPECT_TRUE(internal::test_binary("eq", "1", "1"));
+ EXPECT_FALSE(internal::test_binary("eq", "2", "1"));
+
+ EXPECT_TRUE(internal::test_binary("ne", "2", "1"));
+ EXPECT_FALSE(internal::test_binary("ne", "1", "1"));
+
+ EXPECT_TRUE(internal::test_binary("lt", "0", "1"));
+ EXPECT_FALSE(internal::test_binary("lt", "1", "1"));
+ EXPECT_FALSE(internal::test_binary("lt", "2", "1"));
+
+ EXPECT_TRUE(internal::test_binary("le", "0", "1"));
+ EXPECT_TRUE(internal::test_binary("le", "1", "1"));
+ EXPECT_FALSE(internal::test_binary("le", "2", "1"));
+
+ EXPECT_TRUE(internal::test_binary("gt", "1", "0"));
+ EXPECT_FALSE(internal::test_binary("gt", "1", "1"));
+ EXPECT_FALSE(internal::test_binary("gt", "0", "1"));
+
+ EXPECT_TRUE(internal::test_binary("ge", "1", "1"));
+ EXPECT_TRUE(internal::test_binary("ge", "2", "1"));
+ EXPECT_FALSE(internal::test_binary("ge", "0", "1"));
+}
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [gentoo-commits] proj/libbash:master commit in: scripts/, src/core/, bashast/, src/core/tests/
@ 2011-04-28 6:19 Petteri Räty
0 siblings, 0 replies; 7+ messages in thread
From: Petteri Räty @ 2011-04-28 6:19 UTC (permalink / raw
To: gentoo-commits
commit: be5289bca55b033742300ed0f5f69121b2bb76c4
Author: Mu Qiao <qiaomuf <AT> gentoo <DOT> org>
AuthorDate: Thu Apr 21 11:58:16 2011 +0000
Commit: Petteri Räty <betelgeuse <AT> gentoo <DOT> org>
CommitDate: Thu Apr 28 02:57:53 2011 +0000
URL: http://git.overlays.gentoo.org/gitweb/?p=proj/libbash.git;a=commit;h=be5289bc
Core: support unsetting variables, fix is_null
Empty variable values are all treated as null value. This simplifies
the previous code and fixes some logic errors.
---
bashast/libbashWalker.g | 5 +--
scripts/var_def.bash.result | 4 +-
src/core/interpreter.cpp | 21 ++++++++++++++++++
src/core/interpreter.h | 19 +++++++++++-----
src/core/symbols.hpp | 40 +++++++++++++++++++++++++---------
src/core/tests/interpreter_test.cpp | 29 ++++++++++++++++++++++++-
src/core/tests/symbols_test.cpp | 12 ++++++++-
7 files changed, 105 insertions(+), 25 deletions(-)
diff --git a/bashast/libbashWalker.g b/bashast/libbashWalker.g
index e278d1b..203cd28 100644
--- a/bashast/libbashWalker.g
+++ b/bashast/libbashWalker.g
@@ -119,10 +119,9 @@ var_def
@declarations {
std::map<int, std::string> values;
unsigned index = 0;
- bool is_null = true;
}
- :^(EQUALS name (string_expr { is_null = false; })?) {
- walker->set_value($name.libbash_value, $string_expr.libbash_value, $name.index, is_null);
+ :^(EQUALS name string_expr?) {
+ walker->set_value($name.libbash_value, $string_expr.libbash_value, $name.index);
}
|^(EQUALS libbash_name=name_base ^(ARRAY (
(expr=string_expr
diff --git a/scripts/var_def.bash.result b/scripts/var_def.bash.result
index e840ebe..1b9e287 100644
--- a/scripts/var_def.bash.result
+++ b/scripts/var_def.bash.result
@@ -5,8 +5,8 @@ $- has not been implemented yet
$! has not been implemented yet
ARRAY01=1 2 3 4 5
ARRAY02=1 2 4 5
-ARRAY03=2 3
-ARRAY04=2 3
+ARRAY03= 2 3
+ARRAY04= 2 3
ARRAY05=1 2 3 4 5
ARRAY06=1 2 3 4 5
ARRAY07=1 2 3 4 5
diff --git a/src/core/interpreter.cpp b/src/core/interpreter.cpp
index 9548e8a..f0bf61e 100644
--- a/src/core/interpreter.cpp
+++ b/src/core/interpreter.cpp
@@ -178,3 +178,24 @@ void interpreter::get_all_function_names(std::vector<std::string>& function_name
{
boost::copy(functions | boost::adaptors::map_keys, back_inserter(function_names));
}
+
+void interpreter::unset(const std::string& name)
+{
+ auto iter = members.find(name);
+ if(iter == members.end())
+ return;
+ else if(iter->second->is_readonly())
+ throw interpreter_exception("Can't unset readonly variable " + name);
+ else
+ members.erase(name);
+}
+
+void interpreter::unset(const std::string& name,
+ const unsigned index)
+{
+ auto iter = members.find(name);
+ if(iter == members.end())
+ return;
+ else
+ iter->second->unset_value(index);
+}
diff --git a/src/core/interpreter.h b/src/core/interpreter.h
index e471b94..dc446fc 100644
--- a/src/core/interpreter.h
+++ b/src/core/interpreter.h
@@ -468,14 +468,13 @@ public:
template <typename T>
const T& set_value(const std::string& name,
const T& new_value,
- const unsigned index=0,
- bool is_null=false)
+ const unsigned index=0)
{
auto i = members.find(name);
if(i == members.end())
- define(name, new_value, false, is_null, index);
+ define(name, new_value, false, index);
else
- i->second->set_value(new_value, index, is_null);
+ i->second->set_value(new_value, index);
return new_value;
}
@@ -494,6 +493,15 @@ public:
return resolve<T>("?");
}
+ /// \brief unset a variable
+ /// \param the name of the variable
+ void unset(const std::string& name);
+
+ /// \brief unset a array member
+ /// \param the name of the array
+ /// \param the index of the member
+ void unset(const std::string& name, const unsigned index);
+
/// \brief define a new global variable
/// \param the name of the variable
/// \param the value of the variable
@@ -503,11 +511,10 @@ public:
void define(const std::string& name,
const T& value,
bool readonly=false,
- bool is_null=false,
const unsigned index=0)
{
std::shared_ptr<variable> target(
- new variable(name, value, readonly, is_null, index));
+ new variable(name, value, readonly, index));
members[name] = target;
}
diff --git a/src/core/symbols.hpp b/src/core/symbols.hpp
index b11d338..89fd657 100644
--- a/src/core/symbols.hpp
+++ b/src/core/symbols.hpp
@@ -137,12 +137,10 @@ public:
variable(const std::string& name,
const T& v,
bool ro=false,
- bool is_null=false,
const unsigned index=0)
: name(name), readonly(ro)
{
- if(!is_null)
- value[index] = v;
+ value[index] = v;
}
/// \brief retrieve actual value of the variable, if index is out of bound,
@@ -182,16 +180,22 @@ public:
/// \param whether to set the variable to null value, default is false
template <typename T>
void set_value(const T& new_value,
- const unsigned index=0,
- bool is_null=false)
+ const unsigned index=0)
{
if(readonly)
throw interpreter_exception(get_name() + " is readonly variable");
- if(is_null)
- value.erase(index);
- else
- value[index] = new_value;
+ value[index] = new_value;
+ }
+
+ /// \brief unset the variable, only used for array variable
+ /// \param the index to be unset
+ void unset_value(const unsigned index)
+ {
+ if(readonly)
+ throw interpreter_exception(get_name() + " is readonly variable");
+
+ value.erase(index);
}
/// \brief get the length of a variable
@@ -211,10 +215,24 @@ public:
/// \brief check whether the value of the variable is null
/// \return whether the value of the variable is null
- bool is_null(const unsigned index=0) const
+ bool is_unset(const unsigned index=0) const
{
return value.find(index) == value.end();
}
+
+ /// \brief check whether the value of the variable is unset
+ /// \return whether the value of the variable is unset
+ bool is_null(const unsigned index=0) const
+ {
+ return get_value<std::string>(index) == "";
+ }
+
+ /// \brief check whether the value of the variable is readonly
+ /// \return whether the value of the variable is readonly
+ bool is_readonly() const
+ {
+ return readonly;
+ }
};
// specialization for arrays
@@ -222,7 +240,7 @@ template <>
inline variable::variable<>(const std::string& name,
const std::map<int, std::string>& v,
bool ro,
- bool, unsigned)
+ unsigned)
: name(name), value(v.begin(), v.end()), readonly(ro)
{
}
diff --git a/src/core/tests/interpreter_test.cpp b/src/core/tests/interpreter_test.cpp
index 2e92a22..54f25b0 100644
--- a/src/core/tests/interpreter_test.cpp
+++ b/src/core/tests/interpreter_test.cpp
@@ -54,7 +54,7 @@ TEST(interpreter, define_resolve_array)
EXPECT_STREQ("3", walker.resolve<string>("array", 2).c_str());
EXPECT_STREQ("", walker.resolve<string>("undefined",100).c_str());
- walker.define("partial", 10, false, false, 8);
+ walker.define("partial", 10, false, 8);
EXPECT_EQ(1, walker.get_array_length("partial"));
EXPECT_EQ(10, walker.resolve<int>("partial", 8));
}
@@ -142,6 +142,33 @@ TEST(interpreter, get_array_values)
EXPECT_EQ(3, array_values[2]);
}
+TEST(interpreter, unset_values)
+{
+ interpreter walker;
+ std::map<int, std::string> values = {{0, "1"}, {1, "2"}, {2, "3"}};
+ walker.define("array", values);
+ walker.define("ro_array", values, true);
+ walker.define("var", "123");
+ walker.define("ro_var", "123", true);
+
+ EXPECT_STREQ("2", walker.resolve<string>("array", 1).c_str());
+ walker.unset("array", 1);
+ EXPECT_STREQ("", walker.resolve<string>("array", 1).c_str());
+ walker.unset("array");
+ EXPECT_STREQ("", walker.resolve<string>("array", 0).c_str());
+ EXPECT_STREQ("", walker.resolve<string>("array", 1).c_str());
+ EXPECT_STREQ("", walker.resolve<string>("array", 2).c_str());
+
+ EXPECT_THROW(walker.unset("ro_array", 1), interpreter_exception);
+ EXPECT_THROW(walker.unset("ro_array"), interpreter_exception);
+
+ EXPECT_STREQ("123", walker.resolve<string>("var").c_str());
+ walker.unset("var");
+ EXPECT_STREQ("", walker.resolve<string>("var").c_str());
+
+ EXPECT_THROW(walker.unset("ro_var"), interpreter_exception);
+}
+
TEST(interperter, substring_expansion_exception)
{
interpreter walker;
diff --git a/src/core/tests/symbols_test.cpp b/src/core/tests/symbols_test.cpp
index d614947..f151318 100644
--- a/src/core/tests/symbols_test.cpp
+++ b/src/core/tests/symbols_test.cpp
@@ -122,9 +122,17 @@ TEST(symbol_test, is_null)
{
variable var("foo", 10);
EXPECT_FALSE(var.is_null());
- var.set_value("bar", 0, true);
+ var.set_value("");
EXPECT_TRUE(var.is_null());
- EXPECT_TRUE(variable("foo", "", false, true).is_null());
+ EXPECT_TRUE(variable("foo", "").is_null());
+}
+
+TEST(symbol_test, is_unset)
+{
+ map<int, string> values = {{0, "1"}, {1, "2"}, {2, "3"}};
+ variable array("foo", values);
+ array.unset_value(1);
+ EXPECT_TRUE(array.is_unset(1));
}
TEST(symbol_test, get_length)
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [gentoo-commits] proj/libbash:master commit in: scripts/, src/core/, bashast/, src/core/tests/
@ 2011-04-14 4:50 Petteri Räty
0 siblings, 0 replies; 7+ messages in thread
From: Petteri Räty @ 2011-04-14 4:50 UTC (permalink / raw
To: gentoo-commits
commit: 60fe984fb2c868848a8fb71fe2272a24a78d350a
Author: Mu Qiao <qiaomuf <AT> gentoo <DOT> org>
AuthorDate: Tue Apr 12 13:44:06 2011 +0000
Commit: Petteri Räty <betelgeuse <AT> gentoo <DOT> org>
CommitDate: Wed Apr 13 02:46:03 2011 +0000
URL: http://git.overlays.gentoo.org/gitweb/?p=proj/libbash.git;a=commit;h=60fe984f
Implement array element reference for variable expansion
---
bashast/libbashWalker.g | 21 +++++++++++------
scripts/var_expansion.ebuild | 13 +++++++++++
scripts/var_expansion.ebuild.result | 14 ++++++++++++
src/core/interpreter.h | 41 ++++++++++++++++++++++++----------
src/core/symbols.hpp | 23 +++++++++----------
src/core/tests/interpreter_test.cpp | 13 ++++++++--
6 files changed, 90 insertions(+), 35 deletions(-)
diff --git a/bashast/libbashWalker.g b/bashast/libbashWalker.g
index 45034c2..ddeffa0 100644
--- a/bashast/libbashWalker.g
+++ b/bashast/libbashWalker.g
@@ -116,23 +116,28 @@ var_name returns[std::string libbash_value, unsigned index]
var_expansion returns[std::string libbash_value]:
^(USE_DEFAULT var_name libbash_word=word) {
- libbash_value = walker->do_default_expansion($var_name.libbash_value, libbash_word);
+ libbash_value = walker->do_default_expansion($var_name.libbash_value, libbash_word, $var_name.index);
}
|^(ASSIGN_DEFAULT var_name libbash_word=word) {
- libbash_value = walker->do_assign_expansion($var_name.libbash_value, libbash_word);
+ libbash_value = walker->do_assign_expansion($var_name.libbash_value, libbash_word, $var_name.index);
}
|^(USE_ALTERNATE var_name libbash_word=word) {
- libbash_value = walker->do_alternate_expansion($var_name.libbash_value, libbash_word);
+ libbash_value = walker->do_alternate_expansion($var_name.libbash_value, libbash_word, $var_name.index);
}
|(^(OFFSET var_name arithmetics arithmetics)) => ^(OFFSET var_name offset=arithmetics length=arithmetics) {
- libbash_value = walker->do_substring_expansion($var_name.libbash_value, offset, length);
+ libbash_value = walker->do_substring_expansion($var_name.libbash_value, offset, length, $var_name.index);
}
|^(OFFSET var_name offset=arithmetics) {
- libbash_value = walker->do_substring_expansion($var_name.libbash_value, offset);
- }
- |^(POUND var_name) {
- libbash_value = boost::lexical_cast<std::string>(walker->get_length($var_name.libbash_value));
- };
+ libbash_value = walker->do_substring_expansion($var_name.libbash_value, offset, $var_name.index);
+ }
+ |^(POUND(
+ var_name {
+ libbash_value = boost::lexical_cast<std::string>(walker->get_length($var_name.libbash_value, $var_name.index));
+ }
+ |^(libbash_name=name_base ARRAY_SIZE) {
+ libbash_value = boost::lexical_cast<std::string>(walker->get_array_length(libbash_name));
+ }
+ ));
word returns[std::string libbash_value]:
|(num) => libbash_string=num { $libbash_value = libbash_string; }
diff --git a/scripts/var_expansion.ebuild b/scripts/var_expansion.ebuild
index 0045b5e..96b6bf2 100644
--- a/scripts/var_expansion.ebuild
+++ b/scripts/var_expansion.ebuild
@@ -1,3 +1,4 @@
+ARRAY=(hi hello 1 2 3)
EAPI="3"
EAPI4="$(($EAPI+1))"
FOO001="${EAPI:-hello}"
@@ -24,3 +25,15 @@ FOO022=${FOO009: -2:100}
FOO023=${NOT_EXIST:0:2}
FOO024=${#FOO009}
FOO025=${#NOT_EXIST}
+FOO026="${ARRAY[0]:-hello}"
+FOO028="${ARRAY[5]:-hello}"
+FOO029="${ARRAY2[0]:=hello}"
+FOO030="${ARRAY2[0]:=hi}"
+FOO031="${ARRAY2[0]:+hi}"
+FOO032="${ARRAY2[1]:+hi}"
+FOO033="${ARRAY[1]:1}"
+FOO034="${ARRAY[1]:1:3}"
+FOO035="${#ARRAY[0]}"
+FOO036="${#ARRAY[@]}"
+FOO037="${#ARRAY[*]}"
+FOO038="${#ARRAY}"
diff --git a/scripts/var_expansion.ebuild.result b/scripts/var_expansion.ebuild.result
index e7b767a..8bea3b8 100644
--- a/scripts/var_expansion.ebuild.result
+++ b/scripts/var_expansion.ebuild.result
@@ -1,3 +1,5 @@
+ARRAY=hi hello 1 2 3
+ARRAY2=hello
EAPI=3
EAPI4=4
FOO001=3
@@ -25,3 +27,15 @@ FOO022=lo
FOO023=
FOO024=5
FOO025=0
+FOO026=hi
+FOO028=hello
+FOO029=hello
+FOO030=hello
+FOO031=hi
+FOO032=
+FOO033=ello
+FOO034=ell
+FOO035=2
+FOO036=5
+FOO037=5
+FOO038=2
diff --git a/src/core/interpreter.h b/src/core/interpreter.h
index 5c75bf0..9166379 100644
--- a/src/core/interpreter.h
+++ b/src/core/interpreter.h
@@ -392,11 +392,11 @@ public:
/// if the variable is undefined
/// \param variable name
/// \return whether the value of the variable is null
- bool is_unset_or_null(const std::string& name)
+ bool is_unset_or_null(const std::string& name, const unsigned index)
{
std::shared_ptr<variable> value = members.resolve(name);
if(value)
- return value->is_null();
+ return value->is_null(index);
else
return true;
}
@@ -449,9 +449,11 @@ public:
/// \param the value of the word
/// \return the expansion result
const std::string do_default_expansion(const std::string& name,
- const std::string& value)
+ const std::string& value,
+ const unsigned index)
{
- return (is_unset_or_null(name)? value : resolve<std::string>(name));
+ return (is_unset_or_null(name, index)?
+ value : resolve<std::string>(name, index));
}
/// \brief perform ${parameter:=word} expansion
@@ -459,9 +461,11 @@ public:
/// \param the value of the word
/// \return the expansion result
const std::string do_assign_expansion(const std::string& name,
- const std::string& value)
+ const std::string& value,
+ const unsigned index)
{
- return (is_unset_or_null(name)? set_value(name, value) : resolve<std::string>(name));
+ return (is_unset_or_null(name, index)?
+ set_value(name, value, index) : resolve<std::string>(name, index));
}
/// \brief perform ${parameter:+word} expansion
@@ -469,18 +473,20 @@ public:
/// \param the value of the word
/// \return the expansion result
const std::string do_alternate_expansion(const std::string& name,
- const std::string& value)
+ const std::string& value,
+ const unsigned index)
{
- return (is_unset_or_null(name)? "" : value);
+ return (is_unset_or_null(name, index)? "" : value);
}
/// \brief perform substring expansion
/// \param the offset of the substring
/// \return the expansion result
const std::string do_substring_expansion(const std::string& name,
- int offset)
+ int offset,
+ const unsigned index)
{
- std::string value = resolve<std::string>(name);
+ std::string value = resolve<std::string>(name, index);
if(!get_real_offset(offset, value))
return "";
return value.substr(offset);
@@ -492,11 +498,12 @@ public:
/// \return the expansion result
const std::string do_substring_expansion(const std::string& name,
int offset,
- int length)
+ int length,
+ const unsigned index)
{
if(length < 0)
throw interpreter_exception("length of substring expression should be greater or equal to zero");
- std::string value = resolve<std::string>(name);
+ std::string value = resolve<std::string>(name, index);
if(!get_real_offset(offset, value))
return "";
return value.substr(offset, length);
@@ -513,5 +520,15 @@ public:
return value->get_length(index);
}
+ /// \brief get the length of an array
+ /// \param the name of the array
+ /// \return the length of the array
+ unsigned get_array_length(const std::string& name)
+ {
+ std::shared_ptr<variable> value = members.resolve(name);
+ if(!value)
+ return 0;
+ return value->get_array_length();
+ }
};
#endif
diff --git a/src/core/symbols.hpp b/src/core/symbols.hpp
index 5992a67..7654ebe 100644
--- a/src/core/symbols.hpp
+++ b/src/core/symbols.hpp
@@ -125,10 +125,6 @@ class variable
/// \brief whether the variable is readonly
bool readonly;
- /// \var private::null_value
- /// \brief whether the variable is null
- bool null_value;
-
public:
/// \brief retrieve variable name
/// \return const string value of variable name
@@ -142,9 +138,10 @@ public:
const T& v,
bool ro=false,
bool is_null=false)
- : name(name), readonly(ro), null_value(is_null)
+ : name(name), readonly(ro)
{
- value[0] = v;
+ if(!is_null)
+ value[0] = v;
}
/// \brief retrieve actual value of the variable, if index is out of bound,
@@ -190,8 +187,10 @@ public:
if(readonly)
throw interpreter_exception(get_name() + " is readonly variable");
- null_value = is_null;
- value[index] = new_value;
+ if(is_null)
+ value.erase(index);
+ else
+ value[index] = new_value;
}
/// \brief get the length of a variable
@@ -211,9 +210,9 @@ public:
/// \brief check whether the value of the variable is null
/// \return whether the value of the variable is null
- bool is_null() const
+ bool is_null(const unsigned index=0) const
{
- return null_value;
+ return value.find(index) == value.end();
}
};
@@ -222,8 +221,8 @@ template <>
inline variable::variable<>(const std::string& name,
const std::map<int, std::string>& v,
bool ro,
- bool is_null)
- : name(name), value(v.begin(), v.end()), readonly(ro), null_value(is_null)
+ bool)
+ : name(name), value(v.begin(), v.end()), readonly(ro)
{
}
diff --git a/src/core/tests/interpreter_test.cpp b/src/core/tests/interpreter_test.cpp
index 9bb561a..fbf073e 100644
--- a/src/core/tests/interpreter_test.cpp
+++ b/src/core/tests/interpreter_test.cpp
@@ -59,9 +59,16 @@ TEST(interpreter, is_unset_or_null)
{
interpreter walker;
walker.define("foo", "hello");
- EXPECT_FALSE(walker.is_unset_or_null("foo"));
+ EXPECT_FALSE(walker.is_unset_or_null("foo", 0));
walker.define("foo", "hello", false, true);
- EXPECT_TRUE(walker.is_unset_or_null("foo"));
+ EXPECT_TRUE(walker.is_unset_or_null("foo", 0));
+
+ std::map<int, std::string> values = {{0, "1"}, {1, "2"}, {2, "3"}};
+ walker.define("bar", values);
+ EXPECT_FALSE(walker.is_unset_or_null("bar", 0));
+ EXPECT_FALSE(walker.is_unset_or_null("bar", 1));
+ EXPECT_FALSE(walker.is_unset_or_null("bar", 2));
+ EXPECT_TRUE(walker.is_unset_or_null("bar", 3));
}
TEST(interpreter, is_unset)
@@ -134,5 +141,5 @@ TEST(interpreter, get_array_values)
TEST(interperter, substring_expansion_exception)
{
interpreter walker;
- EXPECT_THROW(walker.do_substring_expansion("", 0, -1), interpreter_exception);
+ EXPECT_THROW(walker.do_substring_expansion("", 0, -1, 0), interpreter_exception);
}
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [gentoo-commits] proj/libbash:master commit in: scripts/, src/core/, bashast/, src/core/tests/
@ 2011-04-06 15:07 Petteri Räty
0 siblings, 0 replies; 7+ messages in thread
From: Petteri Räty @ 2011-04-06 15:07 UTC (permalink / raw
To: gentoo-commits
commit: 5e4a93528fc7b0cfef25f7265b1c308b4a54fded
Author: Mu Qiao <qiaomuf <AT> gentoo <DOT> org>
AuthorDate: Tue Apr 5 13:29:44 2011 +0000
Commit: Petteri Räty <betelgeuse <AT> gentoo <DOT> org>
CommitDate: Wed Apr 6 10:07:49 2011 +0000
URL: http://git.overlays.gentoo.org/gitweb/?p=proj/libbash.git;a=commit;h=5e4a9352
Implement substring expansion
Support substring expansion with string variables. Arrays and special
variables like @, * are not supported yet.
---
bashast/libbashWalker.g | 11 ++++++++-
scripts/var_expansion.ebuild | 13 +++++++++++
scripts/var_expansion.ebuild.result | 13 +++++++++++
src/core/interpreter.h | 41 +++++++++++++++++++++++++++++++++++
src/core/tests/interpreter_test.cpp | 6 +++++
5 files changed, 83 insertions(+), 1 deletions(-)
diff --git a/bashast/libbashWalker.g b/bashast/libbashWalker.g
index ad8e444..e6f4393 100644
--- a/bashast/libbashWalker.g
+++ b/bashast/libbashWalker.g
@@ -86,7 +86,10 @@ var_name returns[std::string libbash_value]
}:
num|name|TIMES|AT;
-var_expansion returns[std::string libbash_value]:
+var_expansion returns[std::string libbash_value]
+@declarations {
+ bool use_length;
+}:
^(USE_DEFAULT var_name libbash_word=word) {
libbash_value = walker->do_default_expansion($var_name.libbash_value, libbash_word);
}
@@ -95,6 +98,12 @@ var_expansion returns[std::string libbash_value]:
}
|^(USE_ALTERNATE var_name libbash_word=word) {
libbash_value = walker->do_alternate_expansion($var_name.libbash_value, libbash_word);
+ }
+ |^(OFFSET var_name offset=arithmetics { use_length = false; } (length=arithmetics { use_length = true; })?) {
+ if(use_length)
+ libbash_value = walker->do_substring_expansion($var_name.libbash_value, offset, length);
+ else
+ libbash_value = walker->do_substring_expansion($var_name.libbash_value, offset);
};
word returns[std::string libbash_value]:
diff --git a/scripts/var_expansion.ebuild b/scripts/var_expansion.ebuild
index f0ad504..247f512 100644
--- a/scripts/var_expansion.ebuild
+++ b/scripts/var_expansion.ebuild
@@ -9,3 +9,16 @@ FOO6=${EAPI:=hello}
FOO7=${FOO8:=hello}
FOO9=${EAPI:+hello}
FOO10=${NOT_EXIST:+hello}
+FOO11=${FOO9:0}
+FOO12=${FOO9:2}
+FOO13=${FOO9: -2}
+FOO14=${FOO9:100}
+FOO15=${FOO9: -100}
+FOO16=${FOO9:(-5 + 5)}
+FOO17=${NOT_EXIST:0}
+FOO18=${FOO9:0:2}
+FOO19=${FOO9:2:2}
+FOO20=${FOO9: -2:2}
+FOO21=${FOO9:2:100}
+FOO22=${FOO9: -2:100}
+FOO23=${NOT_EXIST:0:2}
diff --git a/scripts/var_expansion.ebuild.result b/scripts/var_expansion.ebuild.result
index 7d2e5ca..2c5c42f 100644
--- a/scripts/var_expansion.ebuild.result
+++ b/scripts/var_expansion.ebuild.result
@@ -2,7 +2,20 @@ EAPI=3
EAPI4=4
FOO=3
FOO10=
+FOO11=hello
+FOO12=llo
+FOO13=lo
+FOO14=
+FOO15=
+FOO16=hello
+FOO17=
+FOO18=he
+FOO19=ll
FOO2=hello
+FOO20=lo
+FOO21=llo
+FOO22=lo
+FOO23=
FOO3=123
FOO4=3
FOO5=2
diff --git a/src/core/interpreter.h b/src/core/interpreter.h
index aad8f48..cde08ac 100644
--- a/src/core/interpreter.h
+++ b/src/core/interpreter.h
@@ -44,6 +44,18 @@ class interpreter{
/// \var private::members
/// \brief global symbol table
scope members;
+
+ /// \brief calculate the correct offset when offset < 0 and check whether
+ /// the real offset is in legal range
+ /// \param[in,out] a value/result argument referring to offset
+ /// \param[in] the original string
+ /// \return whether the real offset is in legal range
+ bool get_real_offset(int& offset, const std::string& str)
+ {
+ offset = (offset >= 0? offset : str.size() + offset);
+ return !(offset < 0 || offset >= static_cast<int>(str.size()));
+ }
+
public:
///
@@ -444,5 +456,34 @@ public:
{
return (is_unset_or_null(name)? "" : value);
}
+
+ /// \brief perform substring expansion
+ /// \param the offset of the substring
+ /// \return the expansion result
+ const std::string do_substring_expansion(const std::string& name,
+ int offset)
+ {
+ std::string value = resolve<std::string>(name);
+ if(!get_real_offset(offset, value))
+ return "";
+ return value.substr(offset);
+ }
+
+ /// \brief perform substring expansion
+ /// \param the offset of the substring
+ /// \param the length of the substring
+ /// \return the expansion result
+ const std::string do_substring_expansion(const std::string& name,
+ int offset,
+ int length)
+ {
+ if(length < 0)
+ throw interpreter_exception("length of substring expression should be greater or equal to zero");
+ std::string value = resolve<std::string>(name);
+ if(!get_real_offset(offset, value))
+ return "";
+ return value.substr(offset, length);
+ }
+
};
#endif
diff --git a/src/core/tests/interpreter_test.cpp b/src/core/tests/interpreter_test.cpp
index 2d46e62..6cc2df9 100644
--- a/src/core/tests/interpreter_test.cpp
+++ b/src/core/tests/interpreter_test.cpp
@@ -90,3 +90,9 @@ TEST(interpreter, set_string_value)
interpreter_exception);
EXPECT_STREQ("hi", walker.resolve<string>("astring_ro").c_str());
}
+
+TEST(interperter, substring_expansion_exception)
+{
+ interpreter walker;
+ EXPECT_THROW(walker.do_substring_expansion("", 0, -1), interpreter_exception);
+}
^ permalink raw reply related [flat|nested] 7+ messages in thread
end of thread, other threads:[~2012-06-03 9:10 UTC | newest]
Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2012-06-03 9:08 [gentoo-commits] proj/libbash:master commit in: scripts/, src/core/, bashast/, src/core/tests/ Petteri Räty
-- strict thread matches above, loose matches on Subject: below --
2011-06-03 12:43 Petteri Räty
2011-05-23 14:34 Petteri Räty
2011-05-22 21:00 Petteri Räty
2011-04-28 6:19 Petteri Räty
2011-04-14 4:50 Petteri Räty
2011-04-06 15:07 Petteri Räty
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox