public inbox for gentoo-commits@lists.gentoo.org
 help / color / mirror / Atom feed
* [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/
@ 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-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 --
2011-05-22 21:00 [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 --
2012-06-03  9:08 Petteri Räty
2011-06-03 12:43 Petteri Räty
2011-05-23 14:34 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