public inbox for gentoo-commits@lists.gentoo.org
 help / color / mirror / Atom feed
* [gentoo-commits] proj/libbash:master commit in: scripts/, /, src/builtins/tests/, src/core/, bashast/, src/core/tests/
@ 2011-06-09 11:46 Petteri Räty
  0 siblings, 0 replies; only message in thread
From: Petteri Räty @ 2011-06-09 11:46 UTC (permalink / raw
  To: gentoo-commits

commit:     eb40afee7b3edcf29779ea2f9ce59d4457322061
Author:     Mu Qiao <qiaomuf <AT> gentoo <DOT> org>
AuthorDate: Tue Jun  7 14:31:38 2011 +0000
Commit:     Petteri Räty <betelgeuse <AT> gentoo <DOT> org>
CommitDate: Thu Jun  9 11:41:23 2011 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/libbash.git;a=commit;h=eb40afee

Core: fix function handling

When there handle multiple input files (for example, source built-in is
called while interpreting), there will be multiple token streams. Then
the function index might not be correct as we don't know which stream
the function belongs to. Now both the AST and the function index are
stored to execute the function at the right index in the right stream.
Using single libbashWalker and changing the pointer of the ctns is not
working. The reason might be the internal data structures of
libbashWalker are broken after the function call. So a new libbashWalker
is created every time a function call is made. The current AST is saved
in std::stack because new functions may be defined during a function call.

---
 Makefile.am                         |    2 +
 bashast/libbashWalker.g             |    8 +++---
 scripts/source_true.sh              |    2 +-
 src/builtins/tests/source_tests.cpp |    9 +++++++
 src/core/bash_ast.cpp               |   11 ++++++++-
 src/core/bash_ast.h                 |   14 +++++++++-
 src/core/function.cpp               |   38 ++++++++++++++++++++++++++++++
 src/core/function.h                 |   44 +++++++++++++++++++++++++++++++++++
 src/core/interpreter.cpp            |   30 +++++------------------
 src/core/interpreter.h              |   29 ++++++++++++++++-------
 src/core/tests/interpreter_test.cpp |    9 +------
 11 files changed, 148 insertions(+), 48 deletions(-)

diff --git a/Makefile.am b/Makefile.am
index 928f7d3..f55db28 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -204,6 +204,8 @@ libcppbash_la_SOURCES = src/common.h \
 						src/core/interpreter.cpp \
 						src/core/interpreter.h \
 						src/core/symbols.hpp \
+						src/core/function.h \
+						src/core/function.cpp \
 						src/core/bash_condition.h \
 						src/core/bash_condition.cpp \
 						src/core/bash_ast.cpp \

diff --git a/bashast/libbashWalker.g b/bashast/libbashWalker.g
index ddbf669..9fff16f 100644
--- a/bashast/libbashWalker.g
+++ b/bashast/libbashWalker.g
@@ -480,10 +480,10 @@ execute_command[const std::string& name, std::vector<std::string>& libbash_args]
 			ANTLR3_MARKER command_index = INDEX();
 			try
 			{
-				walker->set_status(walker->call(name,
-												libbash_args,
-												ctx,
-												compound_command));
+				ANTLR3_MARKER current_index = INDEX();
+				// Calling functions may change current index
+				walker->call(name, libbash_args);
+				SEEK(current_index);
 			}
 			catch(return_exception& e)
 			{

diff --git a/scripts/source_true.sh b/scripts/source_true.sh
index aecb607..a848f2e 100644
--- a/scripts/source_true.sh
+++ b/scripts/source_true.sh
@@ -1,6 +1,6 @@
 FOO001=hello
 function foo()
 {
-    :
+    echo hi
 }
 FOO002=$0

diff --git a/src/builtins/tests/source_tests.cpp b/src/builtins/tests/source_tests.cpp
index e1fecee..438fbfd 100644
--- a/src/builtins/tests/source_tests.cpp
+++ b/src/builtins/tests/source_tests.cpp
@@ -42,7 +42,16 @@ TEST(source_builtin_test, source_true)
                                      std::cin,
                                      walker);
   EXPECT_EQ(status, 0);
+
   EXPECT_TRUE(walker.has_function("foo"));
+
+  // Call the function defined in source_true.sh
+  std::stringstream output;
+  walker.set_output_stream(&output);
+  interpreter::local_scope current_scope(walker);
+  walker.call("foo", {});
+  EXPECT_STREQ("hi\n", output.str().c_str());
+
   EXPECT_STREQ("hello", walker.resolve<std::string>("FOO001").c_str());
   EXPECT_STREQ((get_src_dir() + "/scripts/source_true.sh").c_str(),
                 walker.resolve<std::string>("FOO002").c_str());

diff --git a/src/core/bash_ast.cpp b/src/core/bash_ast.cpp
index b0ef4f8..cb85e2e 100644
--- a/src/core/bash_ast.cpp
+++ b/src/core/bash_ast.cpp
@@ -169,4 +169,13 @@ pANTLR3_BASE_TREE bash_ast::parser_arithmetics(plibbashParser parser)
   return parser->arithmetics(parser).tree;
 }
 
-
+void bash_ast::call_function(plibbashWalker ctx,
+                             ANTLR3_MARKER index)
+{
+  auto INPUT = ctx->pTreeParser->ctnstream;
+  // Push function index into INPUT
+  // The actual type of ANTLR3_MARKER is ANTLR3_INT32
+  INPUT->push(INPUT, boost::numeric_cast<ANTLR3_INT32>(index));
+  // Execute function body
+  ctx->compound_command(ctx);
+}

diff --git a/src/core/bash_ast.h b/src/core/bash_ast.h
index aa045bf..4163ad4 100644
--- a/src/core/bash_ast.h
+++ b/src/core/bash_ast.h
@@ -34,11 +34,11 @@
 #include <antlr3.h>
 #include <boost/utility.hpp>
 
+#include "core/interpreter.h"
 #include "libbashWalker.h"
 
 struct libbashLexer_Ctx_struct;
 struct libbashParser_Ctx_struct;
-class interpreter;
 
 template<typename T>
 class antlr_pointer: public std::unique_ptr<T, std::function<void(T*)>>
@@ -74,6 +74,9 @@ public:
 
   static int walker_arithmetics(plibbashWalker tree_parser);
 
+  static void call_function(plibbashWalker tree_parser,
+                            ANTLR3_MARKER index);
+
   static pANTLR3_BASE_TREE parser_start(libbashParser_Ctx_struct* parser);
 
   static pANTLR3_BASE_TREE parser_arithmetics(libbashParser_Ctx_struct* parser);
@@ -87,7 +90,14 @@ public:
   interpret_with(interpreter& walker, Functor walk)
   {
     set_interpreter(&walker);
-    antlr_pointer<libbashWalker_Ctx_struct> p_tree_parser(libbashWalkerNew(nodes.get()));
+    walker.push_current_ast(this);
+    std::unique_ptr<libbashWalker_Ctx_struct, std::function<void(plibbashWalker)>> p_tree_parser(
+        libbashWalkerNew(nodes.get()),
+        [&](plibbashWalker tree_parser)
+        {
+          tree_parser->free(tree_parser);
+          walker.pop_current_ast();
+        });
     return walk(p_tree_parser.get());
   }
 

diff --git a/src/core/function.cpp b/src/core/function.cpp
new file mode 100644
index 0000000..5fda04b
--- /dev/null
+++ b/src/core/function.cpp
@@ -0,0 +1,38 @@
+/*
+   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 function.cpp
+/// \author Mu Qiao
+/// \brief implementation for function
+///
+
+#include "core/function.h"
+
+#include <functional>
+
+#include "core/bash_ast.h"
+#include "core/interpreter.h"
+
+void function::call(interpreter& walker)
+{
+  ast.interpret_with(walker,
+                     std::bind(bash_ast::call_function,
+                               std::placeholders::_1,
+                               index));
+}

diff --git a/src/core/function.h b/src/core/function.h
new file mode 100644
index 0000000..ceb6e67
--- /dev/null
+++ b/src/core/function.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 function.hpp
+/// \brief implementation for function
+///
+
+#ifndef LIBBASH_CORE_FUNCTION_H_
+#define LIBBASH_CORE_FUNCTION_H_
+
+#include "core/interpreter_exception.h"
+
+#include <antlr3.h>
+
+class bash_ast;
+class interpreter;
+
+class function
+{
+  bash_ast& ast;
+  ANTLR3_MARKER index;
+public:
+  function(bash_ast& ast_, ANTLR3_MARKER i): ast(ast_), index(i){}
+
+  void call(interpreter& walker);
+};
+
+#endif

diff --git a/src/core/interpreter.cpp b/src/core/interpreter.cpp
index e08fd57..6922df9 100644
--- a/src/core/interpreter.cpp
+++ b/src/core/interpreter.cpp
@@ -280,33 +280,17 @@ void interpreter::define_function_arguments(scope& current_stack,
   define("*", positional_args);
 }
 
-int interpreter::call(const std::string& name,
-                       const std::vector<std::string>& arguments,
-                       plibbashWalker ctx,
-                       std::function<void(plibbashWalker)> f)
+void interpreter::call(const std::string& name,
+                       const std::vector<std::string>& arguments)
 {
-  ANTLR3_MARKER func_index;
-  auto iter = functions.find(name);
-  if(iter == functions.end())
-    return -1;
-  func_index = iter->second;
-
   // Prepare arguments
   define_function_arguments(local_members.back(), arguments);
 
-  auto INPUT = ctx->pTreeParser->ctnstream;
-  auto ISTREAM = INPUT->tnstream->istream;
-  // Saving current index
-  ANTLR3_MARKER curr = ISTREAM->index(ISTREAM);
-  // Push function index into INPUT
-  // The actual type of ANTLR3_MARKER is ANTLR3_INT32
-  INPUT->push(INPUT, boost::numeric_cast<ANTLR3_INT32>(func_index));
-  // Execute function body
-  f(ctx);
-  // Reset to the previous index
-  ISTREAM->seek(ISTREAM, curr);
-
-  return 0;
+  auto iter = functions.find(name);
+  if(iter != functions.end())
+    iter->second.call(*this);
+  else
+    throw interpreter_exception(name + " is not defined.");
 }
 
 void interpreter::replace_all(std::string& value,

diff --git a/src/core/interpreter.h b/src/core/interpreter.h
index 1e47fc9..6aefc4c 100644
--- a/src/core/interpreter.h
+++ b/src/core/interpreter.h
@@ -35,6 +35,7 @@
 #include <boost/xpressive/xpressive.hpp>
 #include <boost/numeric/conversion/cast.hpp>
 
+#include "core/function.h"
 #include "core/symbols.hpp"
 #include "cppbash_builtin.h"
 
@@ -55,7 +56,9 @@ class interpreter: public boost::noncopyable
 
   /// \var private::function_definitions
   /// \brief global symbol table for functions
-  std::unordered_map<std::string, ANTLR3_MARKER> functions;
+  std::unordered_map<std::string, function> functions;
+
+  std::stack<bash_ast*> ast_stack;
 
   /// \var private::local_members
   /// \brief local scope for function arguments, execution environment and
@@ -554,19 +557,27 @@ public:
   void define_function(const std::string& name,
                        ANTLR3_MARKER body_index)
   {
-    functions[name] = body_index;
+    functions.insert(make_pair(name, function(*ast_stack.top(), body_index)));
+  }
+
+  /// \brief push current AST, used for function definition
+  /// \param current ast
+  void push_current_ast(bash_ast* ast)
+  {
+    ast_stack.push(ast);
+  }
+
+  /// \brief pop current AST, used for function definition
+  void pop_current_ast()
+  {
+    ast_stack.pop();
   }
 
   /// \brief make function call
   /// \param function name
   /// \param function arguments
-  /// \param walker context
-  /// \param the function that needs to be executed
-  /// \return the return value of the function
-  int call(const std::string& name,
-           const std::vector<std::string>& arguments,
-           plibbashWalker ctx,
-           std::function<void(plibbashWalker)> f);
+  void call(const std::string& name,
+            const std::vector<std::string>& arguments);
 
   /// \brief check if we have 'name' defined as a function
   /// \param function name

diff --git a/src/core/tests/interpreter_test.cpp b/src/core/tests/interpreter_test.cpp
index a6395fd..9619ad8 100644
--- a/src/core/tests/interpreter_test.cpp
+++ b/src/core/tests/interpreter_test.cpp
@@ -208,6 +208,7 @@ TEST(interpreter, unset_variables)
 TEST(interpreter, unset_functions)
 {
   interpreter walker;
+  walker.push_current_ast(0);
   walker.define_function("foo", 0);
   EXPECT_TRUE(walker.has_function("foo"));
   walker.unset_function("foo");
@@ -246,11 +247,3 @@ TEST(interpreter, bash_option)
   walker.set_option("extglob", true);
   EXPECT_TRUE(walker.get_option("extglob"));
 }
-
-TEST(interpreter, call_function)
-{
-  interpreter walker;
-  std::vector<std::string> arguments;
-
-  EXPECT_EQ(-1, walker.call("not exist", arguments, 0, 0));
-}



^ permalink raw reply related	[flat|nested] only message in thread

only message in thread, other threads:[~2011-06-09 11:46 UTC | newest]

Thread overview: (only message) (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2011-06-09 11:46 [gentoo-commits] proj/libbash:master commit in: scripts/, /, src/builtins/tests/, src/core/, bashast/, src/core/tests/ 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