public inbox for gentoo-commits@lists.gentoo.org
 help / color / mirror / Atom feed
* [gentoo-commits] proj/libbash:master commit in: /, src/core/, src/core/tests/
@ 2011-03-25  9:24 Petteri Räty
  0 siblings, 0 replies; 2+ messages in thread
From: Petteri Räty @ 2011-03-25  9:24 UTC (permalink / raw
  To: gentoo-commits

commit:     74e5523b8f672c046ad455cb8ed2d2eed1b0513e
Author:     Mu Qiao <qiaomuf <AT> gentoo <DOT> org>
AuthorDate: Wed Mar 16 02:15:14 2011 +0000
Commit:     Petteri Räty <betelgeuse <AT> gentoo <DOT> org>
CommitDate: Fri Mar 25 09:08:24 2011 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/libbash.git;a=commit;h=74e5523b

Implement symbols and symbol table

Using unordered_map to implement symbol table. boost::variant is
used to implement the type system. Simplify unit test by Petteri
Räty.

---
 .gitignore                       |    1 +
 Makefile.am                      |   10 ++-
 src/core/interpreter.h           |    4 +
 src/core/interpreter_exception.h |   41 ++++++++
 src/core/symbols.hpp             |  198 ++++++++++++++++++++++++++++++++++++++
 src/core/tests/symbols_test.cpp  |   73 ++++++++++++++
 6 files changed, 325 insertions(+), 2 deletions(-)

diff --git a/.gitignore b/.gitignore
index 81aa67f..a0936bd 100644
--- a/.gitignore
+++ b/.gitignore
@@ -16,6 +16,7 @@ install-sh
 missing
 Makefile
 autom4te.cache
+core_unittests
 builtin_unittests
 post_check
 bashast.g

diff --git a/Makefile.am b/Makefile.am
index 2554482..7cb508d 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -56,8 +56,12 @@ AM_CXXFLAGS=$(BOOST_CPPFLAGS) -std=c++0x -I$(top_srcdir)/src/
 AM_CFLAGS=-x c++ $(AM_CXXFLAGS)
 
 if HAVE_GTEST
-TESTS += builtin_unittests post_check
-check_PROGRAMS = builtin_unittests post_check
+TESTS += core_unittests builtin_unittests post_check
+check_PROGRAMS = core_unittests builtin_unittests post_check
+core_unittests_SOURCES = test/run_tests.cpp
+core_unittests_SOURCES += src/core/tests/symbols_test.cpp
+core_unittests_LDADD = ${GTEST_LIBS}
+
 builtin_unittests_SOURCES = test/run_tests.cpp
 builtin_unittests_SOURCES += src/builtins/tests/echo_tests.cpp
 builtin_unittests_SOURCES += src/builtins/tests/boolean_tests.cpp
@@ -96,8 +100,10 @@ libcppbash_la_SOURCES = src/cppbash_builtin.cpp \
 						src/builtins/echo_builtin.h \
 						src/builtins/boolean_builtins.h \
 						$(GENERATED_PARSER_C) \
+						src/core/interpreter_exception.h \
 						src/core/interpreter.cpp \
 						src/core/interpreter.h \
+						src/core/symbols.hpp \
 						$(GENERATED_WALKER_C)
 
 EXTRA_DIST = bashast/bashast.g \

diff --git a/src/core/interpreter.h b/src/core/interpreter.h
index a0bb344..3c0c23f 100644
--- a/src/core/interpreter.h
+++ b/src/core/interpreter.h
@@ -32,6 +32,7 @@
 #include <antlr3basetree.h>
 
 #include "bashastLexer.h"
+#include "core/symbols.hpp"
 
 ///
 /// \class interpreter
@@ -39,6 +40,9 @@
 ///
 class interpreter{
 public:
+  /// \var public::members
+  /// \brief global symbol table
+  scope members;
 
   /// \brief parse the text value of a tree to integer
   /// \param the target tree

diff --git a/src/core/interpreter_exception.h b/src/core/interpreter_exception.h
new file mode 100644
index 0000000..40f3d90
--- /dev/null
+++ b/src/core/interpreter_exception.h
@@ -0,0 +1,41 @@
+/*
+   Copyright 2011 Mu Qiao
+
+   This file is part of libbash.
+
+   libbash is free software: you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation, either version 2 of the License, or
+   (at your option) any later version.
+
+   libbash is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with libbash.  If not, see <http://www.gnu.org/licenses/>.
+*/
+///
+/// \file interpreter_exception.h
+/// \author Mu Qiao
+/// \brief implementation for interpreter_exception
+///
+
+#ifndef INTERPRETER_EXCEPTION_H_
+#define INTERPRETER_EXCEPTION_H_
+
+#include <stdexcept>
+#include <string>
+
+///
+/// \class interpreter_exception
+/// \brief runtime exception occured during interpreting
+///
+class interpreter_exception: public std::runtime_error
+{
+public:
+  explicit interpreter_exception(const std::string& err_msg):
+    runtime_error(err_msg){}
+};
+
+#endif

diff --git a/src/core/symbols.hpp b/src/core/symbols.hpp
new file mode 100644
index 0000000..c613cbf
--- /dev/null
+++ b/src/core/symbols.hpp
@@ -0,0 +1,198 @@
+/*
+   Copyright 2011 Mu Qiao
+
+   This file is part of libbash.
+
+   libbash is free software: you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation, either version 2 of the License, or
+   (at your option) any later version.
+
+   libbash is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with libbash.  If not, see <http://www.gnu.org/licenses/>.
+*/
+///
+/// \file symbols.hpp
+/// \author Mu Qiao
+/// \brief template implementation for symbols and symbol table
+///
+
+#ifndef SYMBOLS_HPP_
+#define SYMBOLS_HPP_
+
+#include <memory>
+#include <string>
+#include <sstream>
+#include <unordered_map>
+#include <vector>
+
+#include <boost/variant.hpp>
+#include <boost/lexical_cast.hpp>
+
+#include "core/interpreter_exception.h"
+
+///
+/// \class symbol
+/// \brief base class for symbols such as variables and functions
+///
+class symbol
+{
+  /// \var private::name
+  /// \brief symbol name
+  std::string name;
+
+public:
+  symbol(){}
+
+  symbol(const std::string& n): name(n){}
+
+  /// \brief retrieve symbol name
+  /// \return const string value of symbol name
+  const std::string& get_name() const
+  {
+    return name;
+  }
+
+};
+
+///
+/// \class converter
+/// \brief template class of converter
+///
+template<typename T>
+class converter: public boost::static_visitor<T>
+{};
+
+///
+/// \class converter
+/// \brief specialized converter for int
+///
+template<>
+class converter<int>: public boost::static_visitor<int>
+{
+public:
+  /// \brief converter for int value
+  /// \param the value to be converted
+  /// \return the converted int
+  int operator() (const int value) const
+  {
+    return value;
+  }
+
+  /// \brief converter for string value
+  /// \param the value to be converted
+  /// \return the converted int
+  int operator() (const std::string& value) const
+  {
+    int result = 0;
+    try
+    {
+      result = boost::lexical_cast<int>(value);
+    }
+    catch(boost::bad_lexical_cast& e)
+    {
+      throw interpreter_exception("can't cast " + value + " to int");
+    }
+    return result;
+  }
+};
+
+///
+/// \class converter
+/// \brief specialized converter for string
+///
+template<>
+class converter<std::string>:
+  public boost::static_visitor<std::string>
+{
+public:
+  /// \brief converter for int value
+  /// \param the value to be converted
+  /// \return the converted string
+  std::string operator() (const int value) const
+  {
+    return boost::lexical_cast<std::string>(value);
+  }
+
+  /// \brief converter for string value
+  /// \param the value to be converted
+  /// \return the converted string
+  std::string operator() (const std::string& value) const
+  {
+    return value;
+  }
+};
+
+///
+/// \class variable
+/// \brief implementation for all variable types
+///
+class variable: public symbol
+{
+  /// \var private::value
+  /// \brief actual value of the symbol
+  boost::variant<int, std::string> value;
+
+  /// \var private::readonly
+  /// \brief whether the symbol is readonly
+  bool readonly;
+
+public:
+  template <typename T>
+  variable(const std::string& name, T v, bool ro=false)
+    : symbol(name), value(v), readonly(ro){}
+
+  /// \brief retrieve actual value of the symbol
+  /// \return the value of the symbol
+  template<typename T>
+  T get_value() const
+  {
+    static converter<T> visitor;
+    return boost::apply_visitor(visitor, value);
+  }
+
+  /// \brief set the value of the symbol, raise exception if it's readonly
+  /// \param the new value to be set
+  template <typename T>
+  void set_value(T new_value)
+  {
+    if(readonly)
+      throw interpreter_exception(get_name() + " is readonly variable");
+    value = new_value;
+  }
+};
+
+///
+/// class scope
+/// \brief implementation for symbol table
+///
+class scope
+{
+public:
+  typedef std::unordered_map<std::string, std::shared_ptr<symbol>>
+    table_type;
+
+  /// \brief define a new symbol
+  /// \param the new symbol
+  void define(std::shared_ptr<symbol> s)
+  {
+    members[s->get_name()] = s;
+  }
+
+  /// \brief resolve a symbol
+  /// \param the symbol name
+  /// \return target symbol passed by reference
+  std::shared_ptr<symbol> resolve(const std::string& name)
+  {
+    return members[name];
+  }
+protected:
+  /// \var protected::member
+  /// \brief symbol table data structure
+  table_type members;
+};
+#endif

diff --git a/src/core/tests/symbols_test.cpp b/src/core/tests/symbols_test.cpp
new file mode 100644
index 0000000..aaaf66d
--- /dev/null
+++ b/src/core/tests/symbols_test.cpp
@@ -0,0 +1,73 @@
+/*
+Copyright 2011 Mu Qiao
+
+This file is part of libbash.
+
+libbash is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+libbash is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with libbash.  If not, see <http://www.gnu.org/licenses/>.
+*/
+///
+/// \file symbols_test.cpp
+/// \author Mu Qiao
+/// \brief series of unit tests for symbols and symbol table.
+///
+
+#include <gtest/gtest.h>
+
+#include "core/symbols.hpp"
+
+using namespace std;
+
+TEST(symbol_test, int_variable)
+{
+  // readonly integer
+  variable ro_integer("integer", 10, true);
+  EXPECT_STREQ("integer", ro_integer.get_name().c_str());
+  EXPECT_EQ(10, ro_integer.get_value<int>());
+  EXPECT_THROW(ro_integer.set_value(100), interpreter_exception);
+  EXPECT_EQ(10, ro_integer.get_value<int>());
+
+  // normal only integer
+  variable normal_integer("integer", 10);
+  normal_integer.set_value(100);
+  EXPECT_EQ(100, normal_integer.get_value<int>());
+
+  // get string value of an integer
+  EXPECT_STREQ("100", normal_integer.get_value<string>().c_str());
+}
+
+TEST(symbol_test, string_variable)
+{
+  // readonly string
+  variable ro_string("string", "hello", true);
+  EXPECT_STREQ("string", ro_string.get_name().c_str());
+  EXPECT_STREQ("hello", ro_string.get_value<string>().c_str());
+  EXPECT_THROW(ro_string.set_value("hello world"), interpreter_exception);
+  EXPECT_STREQ("hello", ro_string.get_value<string>().c_str());
+
+  // normal string
+  variable normal_string("string", "hello");
+  normal_string.set_value("hello world");
+  EXPECT_STREQ("hello world", normal_string.get_value<string>().c_str());
+
+  // string contains integer value
+  variable int_string("string", "123");
+  EXPECT_EQ(123, int_string.get_value<int>());
+}
+
+TEST(scope_test, define_resolve)
+{
+  scope members;
+  auto an_int = shared_ptr<variable>(new variable("integer_symbol", 100));
+  members.define(an_int);
+  EXPECT_EQ(an_int, members.resolve("integer_symbol"));
+}



^ permalink raw reply related	[flat|nested] 2+ messages in thread

* [gentoo-commits] proj/libbash:master commit in: /, src/core/, src/core/tests/
@ 2011-05-27 23:03 Petteri Räty
  0 siblings, 0 replies; 2+ messages in thread
From: Petteri Räty @ 2011-05-27 23:03 UTC (permalink / raw
  To: gentoo-commits

commit:     a6e8bcfd05d72ca16ea786aa78106111b7a4d15e
Author:     Mu Qiao <qiaomuf <AT> gentoo <DOT> org>
AuthorDate: Thu May 26 10:42:50 2011 +0000
Commit:     Petteri Räty <betelgeuse <AT> gentoo <DOT> org>
CommitDate: Fri May 27 08:45:41 2011 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/libbash.git;a=commit;h=a6e8bcfd

Core: adjust interpreter to support unset

We didn't not handle local variables and the interface was not
helpful. Now the implementation is adjusted to support unset
built-in. As we don't support read only functions, unsetting
functions will always return true.

---
 Makefile.am                         |    1 +
 src/core/interpreter.cpp            |   60 ++++++++++++++++++++++++++--------
 src/core/interpreter.h              |    4 ++
 src/core/tests/interpreter_test.cpp |   59 +++++++++++++++++++++++++++++-----
 src/core/unset_exception.h          |   44 +++++++++++++++++++++++++
 5 files changed, 145 insertions(+), 23 deletions(-)

diff --git a/Makefile.am b/Makefile.am
index 86c2583..3b72d46 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -193,6 +193,7 @@ libcppbash_la_SOURCES = src/common.h \
 						$(GENERATED_PARSER_C) \
 						$(GENERATED_PARSER_H) \
 						src/core/interpreter_exception.h \
+						src/core/unset_exception.h \
 						src/core/interpreter.cpp \
 						src/core/interpreter.h \
 						src/core/symbols.hpp \

diff --git a/src/core/interpreter.cpp b/src/core/interpreter.cpp
index 2337e87..41bc7b5 100644
--- a/src/core/interpreter.cpp
+++ b/src/core/interpreter.cpp
@@ -22,8 +22,6 @@
 /// \brief implementations for bash interpreter (visitor pattern).
 ///
 
-#include "core/interpreter.h"
-
 #include <cctype>
 
 #include <functional>
@@ -37,8 +35,11 @@
 #include <boost/range/adaptor/map.hpp>
 #include <boost/range/algorithm/copy.hpp>
 
+#include "core/unset_exception.h"
 #include "libbashWalker.h"
 
+#include "core/interpreter.h"
+
 interpreter::interpreter(): out(&std::cout), err(&std::cerr), in(&std::cin), bash_options(
     {
       {"autocd", false},
@@ -341,25 +342,56 @@ void interpreter::get_all_function_names(std::vector<std::string>& function_name
   boost::copy(functions | boost::adaptors::map_keys, back_inserter(function_names));
 }
 
+namespace
+{
+  void check_unset_positional(const std::string& name)
+  {
+    // Unsetting positional parameters is not allowed
+    if(isdigit(name[0]))
+      throw unset_exception("unset: not a valid identifier");
+  }
+}
+
 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);
+  check_unset_positional(name);
+
+  auto unsetter = [&](scope& frame) -> bool {
+    auto iter_local = frame.find(name);
+    if(iter_local != frame.end())
+    {
+      if(iter_local->second->is_readonly())
+        throw unset_exception("unset a readonly variable");
+      frame.erase(iter_local);
+      return true;
+    }
+    return false;
+  };
+
+  if(std::none_of(local_members.rbegin(), local_members.rend(), unsetter))
+    unsetter(members);
+}
+
+// We need to return false when unsetting readonly functions in future
+void interpreter::unset_function(const std::string& name)
+{
+  auto function = functions.find(name);
+  if(function != functions.end())
+    functions.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);
+  check_unset_positional(name);
+
+  auto var = resolve_variable(name);
+  if(var)
+  {
+    if(var->is_readonly())
+      throw unset_exception("unset a readonly variable");
+    var->unset_value(index);
+  }
 }
 
 bool interpreter::get_option(const std::string& name) const

diff --git a/src/core/interpreter.h b/src/core/interpreter.h
index f35b8ff..3420ee4 100644
--- a/src/core/interpreter.h
+++ b/src/core/interpreter.h
@@ -502,6 +502,10 @@ public:
   /// \param the name of the variable
   void unset(const std::string& name);
 
+  /// \brief unset a function
+  /// \param the name of the function
+  void unset_function(const std::string& name);
+
   /// \brief unset a array member
   /// \param the name of the array
   /// \param the index of the member

diff --git a/src/core/tests/interpreter_test.cpp b/src/core/tests/interpreter_test.cpp
index ab24449..d64866f 100644
--- a/src/core/tests/interpreter_test.cpp
+++ b/src/core/tests/interpreter_test.cpp
@@ -25,6 +25,7 @@
 #include <gtest/gtest.h>
 
 #include "core/interpreter.h"
+#include "core/unset_exception.h"
 
 using namespace std;
 
@@ -143,31 +144,71 @@ TEST(interpreter, get_array_values)
   EXPECT_FALSE(walker.resolve_array("undefined", array_values));
 }
 
-TEST(interpreter, unset_values)
+TEST(interpreter, unset_arrays)
 {
   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);
-
+  interpreter::local_scope temp_scope(walker);
+  values[0] = "local";
+  walker.define_local("array", values);
+  walker.define_local("ro_local_array", values, true);
+
+  // unset arrays
+  EXPECT_STREQ("local", walker.resolve<string>("array", 0).c_str());
+  // unset local
+  walker.unset("array", 0);
+  EXPECT_STREQ("", walker.resolve<string>("array", 0).c_str());
+  // unset local
+  walker.unset("array");
+  // resolve to global
+  EXPECT_STREQ("1", walker.resolve<string>("array", 0).c_str());
   EXPECT_STREQ("2", walker.resolve<string>("array", 1).c_str());
-  walker.unset("array", 1);
-  EXPECT_STREQ("", walker.resolve<string>("array", 1).c_str());
+  EXPECT_STREQ("3", walker.resolve<string>("array", 2).c_str());
+  // unset global
   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());
+  walker.unset("array");
+
+  EXPECT_THROW(walker.unset("ro_array", 1), unset_exception);
+  EXPECT_THROW(walker.unset("ro_local_array", 1), unset_exception);
+  EXPECT_THROW(walker.unset("ro_array"), unset_exception);
+  EXPECT_THROW(walker.unset("ro_local_array"), unset_exception);
+
+  EXPECT_THROW(walker.unset("1", 1), interpreter_exception);
+}
 
-  EXPECT_THROW(walker.unset("ro_array", 1), interpreter_exception);
-  EXPECT_THROW(walker.unset("ro_array"), interpreter_exception);
+TEST(interpreter, unset_variables)
+{
+  interpreter walker;
+  walker.define("var", "123");
+  walker.define("ro_var", "123", true);
+  interpreter::local_scope temp_scope(walker);
+  walker.define_local("var", 456);
+  walker.define_local("ro_local_var", 456, true);
 
+  EXPECT_STREQ("456", walker.resolve<string>("var").c_str());
+  walker.unset("var");
   EXPECT_STREQ("123", walker.resolve<string>("var").c_str());
   walker.unset("var");
   EXPECT_STREQ("", walker.resolve<string>("var").c_str());
+  walker.unset("var");
+
+  EXPECT_THROW(walker.unset("ro_var"), unset_exception);
+  EXPECT_THROW(walker.unset("ro_local_var"), unset_exception);
+  EXPECT_THROW(walker.unset("1"), interpreter_exception);
+}
 
-  EXPECT_THROW(walker.unset("ro_var"), interpreter_exception);
+TEST(interpreter, unset_functions)
+{
+  interpreter walker;
+  walker.define_function("foo", 0);
+  EXPECT_TRUE(walker.has_function("foo"));
+  walker.unset_function("foo");
+  EXPECT_FALSE(walker.has_function("foo"));
 }
 
 TEST(interperter, substring_expansion_exception)

diff --git a/src/core/unset_exception.h b/src/core/unset_exception.h
new file mode 100644
index 0000000..7ee6c03
--- /dev/null
+++ b/src/core/unset_exception.h
@@ -0,0 +1,44 @@
+/*
+   Please use git log for copyright holder and year information
+
+   This file is part of libbash.
+
+   libbash is free software: you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation, either version 2 of the License, or
+   (at your option) any later version.
+
+   libbash is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with libbash.  If not, see <http://www.gnu.org/licenses/>.
+*/
+///
+/// \file unset_exception.h
+/// \author Mu Qiao
+/// \brief implementation for unset_exception
+///
+
+#ifndef LIBBASH_CORE_UNSET_EXCEPTION_H_
+#define LIBBASH_CORE_UNSET_EXCEPTION_H_
+
+#include <stdexcept>
+#include <string>
+
+#include "interpreter_exception.h"
+
+///
+/// \class unset_exception
+/// \brief exception for unsetting variables
+///
+class unset_exception: public interpreter_exception
+{
+public:
+  explicit unset_exception(const std::string& err_msg):
+    interpreter_exception(err_msg){}
+};
+
+#endif



^ permalink raw reply related	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2011-05-27 23:03 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2011-05-27 23:03 [gentoo-commits] proj/libbash:master commit in: /, src/core/, src/core/tests/ Petteri Räty
  -- strict thread matches above, loose matches on Subject: below --
2011-03-25  9:24 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