aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMu Qiao <qiaomuf@gentoo.org>2011-07-27 19:06:53 +0800
committerMu Qiao <qiaomuf@gentoo.org>2011-08-02 15:52:18 +0800
commit2afd34d4fef6dbdfb9afa2a371303dcf2fa4ab6e (patch)
tree0d80d50146d1eaca9d56b229e584703026f8798d
parentParser: support empty command with redirection (diff)
downloadlibbash-2afd34d4fef6dbdfb9afa2a371303dcf2fa4ab6e.tar.gz
libbash-2afd34d4fef6dbdfb9afa2a371303dcf2fa4ab6e.tar.bz2
libbash-2afd34d4fef6dbdfb9afa2a371303dcf2fa4ab6e.zip
Builtin: reimplement the local built-in
Now the local built-in is not handled only in parser grammar so that expansions can happen for the arguments. '=' is not checked in the local and export built-in anymore because we do not generate empty AST for "export foo".
-rw-r--r--Makefile.am2
-rw-r--r--bashast/bashast.g39
-rw-r--r--bashast/gunit/array.gunit2
-rw-r--r--bashast/gunit/simp_command.gunit2
-rw-r--r--bashast/libbashWalker.g6
-rw-r--r--scripts/command_execution.bash2
-rw-r--r--scripts/function_def.bash3
-rw-r--r--src/builtins/export_builtin.cpp11
-rw-r--r--src/builtins/local_builtin.cpp43
-rw-r--r--src/builtins/local_builtin.h46
-rw-r--r--src/core/bash_ast.cpp6
-rw-r--r--src/core/bash_ast.h2
-rw-r--r--src/cppbash_builtin.cpp2
-rwxr-xr-xtest/verify_error_output_test.sh2
14 files changed, 133 insertions, 35 deletions
diff --git a/Makefile.am b/Makefile.am
index ba77230..1aa58d9 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -203,6 +203,8 @@ libcppbash_la_SOURCES = src/common.h \
src/builtins/eval_builtin.h \
src/builtins/export_builtin.cpp \
src/builtins/export_builtin.h \
+ src/builtins/local_builtin.cpp \
+ src/builtins/local_builtin.h \
src/builtins/declare_builtin.cpp \
src/builtins/declare_builtin.h \
src/builtins/boolean_builtins.h \
diff --git a/bashast/bashast.g b/bashast/bashast.g
index dc0ff1b..cb0a63d 100644
--- a/bashast/bashast.g
+++ b/bashast/bashast.g
@@ -373,12 +373,15 @@ command_atom
: (FOR|SELECT|IF|WHILE|UNTIL|CASE|LPAREN|LBRACE|LLPAREN|LSQUARE|TEST_EXPR) => compound_command
| FUNCTION BLANK string_expr_no_reserved_word ((BLANK? parens wspace?)|wspace) compound_command
-> ^(FUNCTION string_expr_no_reserved_word compound_command)
- | (name (LSQUARE|EQUALS|PLUS EQUALS)|LOCAL) => variable_definitions
+ | (name (LSQUARE|EQUALS|PLUS EQUALS)) => variable_definitions
(
(BLANK bash_command) => BLANK bash_command -> bash_command variable_definitions
| -> ^(VARIABLE_DEFINITIONS variable_definitions)
)
- | (EXPORT) => EXPORT BLANK export_item -> ^(STRING EXPORT) ^(STRING ^(DOUBLE_QUOTED_STRING export_item))
+ | (EXPORT) => EXPORT BLANK builtin_variable_definition_item
+ -> ^(STRING EXPORT) ^(STRING ^(DOUBLE_QUOTED_STRING builtin_variable_definition_item))
+ | (LOCAL) => LOCAL BLANK builtin_variable_definition_item
+ -> ^(STRING LOCAL) ^(STRING ^(DOUBLE_QUOTED_STRING builtin_variable_definition_item))
| command_name
(
(BLANK? parens) => BLANK? parens wspace? compound_command
@@ -403,10 +406,7 @@ command_name
| {LA(1) == GREATER_THAN}? => redirection_atom -> ^(STRING NAME) redirection_atom;
variable_definitions
- : (
- variable_definition_atom ((BLANK name (LSQUARE|EQUALS|PLUS EQUALS)) => BLANK! variable_definition_atom)*
- | (LOCAL) => LOCAL BLANK! local_item ((BLANK name) => BLANK! local_item)*
- );
+ : variable_definition_atom ((BLANK name (LSQUARE|EQUALS|PLUS EQUALS)) => BLANK! variable_definition_atom)* ;
variable_definition_atom
: name LSQUARE BLANK? explicit_arithmetic BLANK? RSQUARE EQUALS string_expr?
@@ -445,26 +445,26 @@ array_atom
|
);
-local_item
- : variable_definition_atom
- | name -> ^(EQUALS name)
- | MINUS op=LETTER {
-#ifdef OUTPUT_C
- std::string option = get_string(op);
- if(option != "i" && option != "a")
- throw libbash::unsupported_exception("We do not support -" + option + " for local");
-#endif
- } ->;
-export_item
+builtin_variable_definition_item
: ((~EOL) => expansion_base)+;
+#ifdef OUTPUT_C
+builtin_variable_definitions[bool local]
+ : {$local}? => (builtin_variable_definition_atom) (BLANK builtin_variable_definition_atom)*
+ -> ^(LIST ^(COMMAND ^(VARIABLE_DEFINITIONS LOCAL builtin_variable_definition_atom+)))
+ | {!$local}? => (builtin_variable_definition_atom) (BLANK builtin_variable_definition_atom)*
+ -> ^(LIST ^(COMMAND ^(VARIABLE_DEFINITIONS builtin_variable_definition_atom+)));
+#else
builtin_variable_definitions
: (builtin_variable_definition_atom) (BLANK builtin_variable_definition_atom)*
- -> ^(LIST ^(COMMAND ^(VARIABLE_DEFINITIONS builtin_variable_definition_atom +)));
+ -> ^(LIST ^(COMMAND ^(VARIABLE_DEFINITIONS builtin_variable_definition_atom+)));
+#endif
builtin_variable_definition_atom
: variable_definition_atom
- | name ->;
+ // We completely ignore the options for export, local and readonly for now
+ | (MINUS LETTER BLANK) => MINUS LETTER ->
+ | name -> ^(EQUALS name ^(STRING ^(VAR_REF name)));
bash_command
: string_expr_no_reserved_word ((BLANK bash_command_arguments) => BLANK! bash_command_arguments)*;
@@ -702,6 +702,7 @@ expansion_base
| (ESC DQUOTE) => ESC DQUOTE -> DQUOTE
| (ESC TICK) => ESC TICK -> TICK
| (ESC DOLLAR) => ESC DOLLAR -> DOLLAR
+ | (brace_expansion) => brace_expansion
| .;
all_expansions
diff --git a/bashast/gunit/array.gunit b/bashast/gunit/array.gunit
index fe49511..514eb53 100644
--- a/bashast/gunit/array.gunit
+++ b/bashast/gunit/array.gunit
@@ -32,7 +32,7 @@ variable_definition_atom:
"asdf+=(a)" -> (PLUS_ASSIGN asdf (ARRAY (STRING a)))
builtin_variable_definitions:
-"asdf=(a b c d) ade acd=bde" -> (LIST (COMMAND (VARIABLE_DEFINITIONS (= asdf (ARRAY (STRING a) (STRING b) (STRING c) (STRING d))) (= acd (STRING bde)))))
+"asdf=(a b c d) ade acd=bde" -> (LIST (COMMAND (VARIABLE_DEFINITIONS (= asdf (ARRAY (STRING a) (STRING b) (STRING c) (STRING d))) (EQUALS ade (STRING (VAR_REF ade))) (= acd (STRING bde)))))
variable_reference:
"$asdf" -> (VAR_REF asdf)
diff --git a/bashast/gunit/simp_command.gunit b/bashast/gunit/simp_command.gunit
index fdd4346..2d98061 100644
--- a/bashast/gunit/simp_command.gunit
+++ b/bashast/gunit/simp_command.gunit
@@ -27,7 +27,7 @@ command_atom:
"./foobär" -> (STRING . / foob ä r)
"cat ~/Documents/todo.txt" -> (STRING cat) (STRING ~ / Documents / todo . txt)
"dodir ${foo}/${bar}" -> (STRING dodir) (STRING (VAR_REF foo) / (VAR_REF bar))
-"local a=123 b=(1 2 3) c" -> (VARIABLE_DEFINITIONS local (= a (STRING 123)) (= b (ARRAY (STRING 1) (STRING 2) (STRING 3))) (EQUALS c))
+"local a=123 b=(1 2 3) c" -> (STRING local) (STRING (DOUBLE_QUOTED_STRING a = 123 b = ( 1 2 3 ) c))
"echo {}{}}{{{}}{{}" -> (STRING echo) (STRING { } { } } { { { } } { { })
"echo \"ab#af ###\" #abc" -> (STRING echo) (STRING (DOUBLE_QUOTED_STRING ab # af # # #))
diff --git a/bashast/libbashWalker.g b/bashast/libbashWalker.g
index 7deb461..65fade5 100644
--- a/bashast/libbashWalker.g
+++ b/bashast/libbashWalker.g
@@ -581,12 +581,16 @@ simple_command
execute_command[std::string& name, std::vector<std::string>& libbash_args]
@declarations {
- interpreter::local_scope current_scope(*walker);
+ std::unique_ptr<interpreter::local_scope> current_scope;
std::unique_ptr<std::ostream> out;
std::unique_ptr<std::ostream> err;
std::unique_ptr<std::istream> in;
bool redirection = false;
}
+@init {
+ if(name != "local")
+ current_scope.reset(new interpreter::local_scope(*walker));
+}
:var_def[true]* (redirect[out, err, in]{ redirection = true; })* {
// Empty command, still need to run bash redirection
if(name.empty())
diff --git a/scripts/command_execution.bash b/scripts/command_execution.bash
index 132d72d..1721fa9 100644
--- a/scripts/command_execution.bash
+++ b/scripts/command_execution.bash
@@ -34,9 +34,11 @@ function unset_inner()
function unset_outer()
{
local FOO006=1 FOO007=2
+ local gjl_${FOO006}="${FOO007}"
unset_inner
echo "FOO006=$FOO006 in unset_outer"
echo "FOO007=$FOO007 in unset_outer"
+ echo "gjl_1=${gjl_1}"
unset FOO006
echo "FOO006=$FOO006 in unset_outer"
}
diff --git a/scripts/function_def.bash b/scripts/function_def.bash
index 609d8b4..6f463a4 100644
--- a/scripts/function_def.bash
+++ b/scripts/function_def.bash
@@ -47,8 +47,7 @@ func_nested1() {
echo $foo_nested ${bar_nested[0]} $localbar
}
func_nested2() {
- local foo_nested=hi bar_nested=(1 2
- 3) localbar
+ local foo_nested=hi bar_nested=(1 2 3) localbar
localbar=1
echo ${bar_nested[@]}
echo ${not_exist[@]}
diff --git a/src/builtins/export_builtin.cpp b/src/builtins/export_builtin.cpp
index 2086cea..e08bfb5 100644
--- a/src/builtins/export_builtin.cpp
+++ b/src/builtins/export_builtin.cpp
@@ -23,6 +23,8 @@
#include "builtins/export_builtin.h"
+#include <functional>
+
#include <sstream>
#include "core/bash_ast.h"
@@ -34,13 +36,8 @@ int export_builtin::exec(const std::vector<std::string>& bash_args)
for(auto iter = bash_args.begin(); iter != bash_args.end(); ++iter)
script << *iter;
- // Check if there is variable definition. If there isn't, parser_builtin_variable_definitions
- // will generate empty AST, which is not what we want.
- if(script.str().find("=") != std::string::npos)
- {
- bash_ast ast(script, &bash_ast::parser_builtin_variable_definitions);
- ast.interpret_with(_walker);
- }
+ bash_ast ast(script, std::bind(&bash_ast::parser_builtin_variable_definitions, std::placeholders::_1, false));
+ ast.interpret_with(_walker);
return 0;
}
diff --git a/src/builtins/local_builtin.cpp b/src/builtins/local_builtin.cpp
new file mode 100644
index 0000000..e28741f
--- /dev/null
+++ b/src/builtins/local_builtin.cpp
@@ -0,0 +1,43 @@
+/*
+ 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 local_builtin.h
+/// \brief class that implements the local builtin
+///
+
+#include "builtins/local_builtin.h"
+
+#include <functional>
+
+#include <sstream>
+
+#include "core/bash_ast.h"
+#include "core/interpreter.h"
+
+int local_builtin::exec(const std::vector<std::string>& bash_args)
+{
+ std::stringstream script;
+ for(auto iter = bash_args.begin(); iter != bash_args.end(); ++iter)
+ script << *iter;
+
+ bash_ast ast(script, std::bind(&bash_ast::parser_builtin_variable_definitions, std::placeholders::_1, true));
+ ast.interpret_with(_walker);
+
+ return 0;
+}
diff --git a/src/builtins/local_builtin.h b/src/builtins/local_builtin.h
new file mode 100644
index 0000000..e475ac4
--- /dev/null
+++ b/src/builtins/local_builtin.h
@@ -0,0 +1,46 @@
+/*
+ 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 local_builtin.h
+/// \brief class that implements the local builtin
+///
+
+#ifndef LIBBASH_BUILTINS_local_BUILTIN_H_
+#define LIBBASH_BUILTINS_local_BUILTIN_H_
+
+#include "cppbash_builtin.h"
+
+///
+/// \class local_builtin
+/// \brief the local builtin for bash
+///
+class local_builtin: public virtual cppbash_builtin
+{
+ public:
+ BUILTIN_CONSTRUCTOR(local)
+
+ ///
+ /// \brief runs the local builtin on the supplied arguments
+ /// \param bash_args the arguments to the local builtin
+ /// \return exit status of local
+ ///
+ virtual int exec(const std::vector<std::string>& bash_args);
+};
+
+#endif
diff --git a/src/core/bash_ast.cpp b/src/core/bash_ast.cpp
index 5b2ac68..ee4fe13 100644
--- a/src/core/bash_ast.cpp
+++ b/src/core/bash_ast.cpp
@@ -27,6 +27,7 @@
#include <thread>
#include <boost/algorithm/string/erase.hpp>
+#include <boost/algorithm/string/trim.hpp>
#include <boost/numeric/conversion/cast.hpp>
#include "core/exceptions.h"
@@ -41,6 +42,7 @@ void bash_ast::read_script(const std::istream& source)
stream << source.rdbuf();
script = stream.str();
boost::algorithm::erase_all(script, "\\\n");
+ boost::trim_if(script, boost::is_any_of(" \t\n"));
}
bash_ast::bash_ast(const std::istream& source,
@@ -237,9 +239,9 @@ pANTLR3_BASE_TREE bash_ast::parser_all_expansions(libbashParser_Ctx_struct* pars
return parser->all_expansions(parser).tree;
}
-pANTLR3_BASE_TREE bash_ast::parser_builtin_variable_definitions(libbashParser_Ctx_struct* parser)
+pANTLR3_BASE_TREE bash_ast::parser_builtin_variable_definitions(libbashParser_Ctx_struct* parser, bool local)
{
- return parser->builtin_variable_definitions(parser).tree;
+ return parser->builtin_variable_definitions(parser, local).tree;
}
void bash_ast::call_function(plibbashWalker ctx,
diff --git a/src/core/bash_ast.h b/src/core/bash_ast.h
index bd7ecf8..2e0c30e 100644
--- a/src/core/bash_ast.h
+++ b/src/core/bash_ast.h
@@ -117,7 +117,7 @@ public:
/// \brief the functor for parser builtin_variable_definitions rule
/// \param parser the pointer to the parser
- static pANTLR3_BASE_TREE parser_builtin_variable_definitions(libbashParser_Ctx_struct* parser);
+ static pANTLR3_BASE_TREE parser_builtin_variable_definitions(libbashParser_Ctx_struct* parser, bool local);
///
/// \brief interpret the script with a given interpreter
diff --git a/src/cppbash_builtin.cpp b/src/cppbash_builtin.cpp
index 03620d1..452fe64 100644
--- a/src/cppbash_builtin.cpp
+++ b/src/cppbash_builtin.cpp
@@ -35,6 +35,7 @@
#include "builtins/echo_builtin.h"
#include "builtins/eval_builtin.h"
#include "builtins/export_builtin.h"
+#include "builtins/local_builtin.h"
#include "builtins/inherit_builtin.h"
#include "builtins/let_builtin.h"
#include "builtins/return_builtin.h"
@@ -59,6 +60,7 @@ cppbash_builtin::builtins_type& cppbash_builtin::builtins() {
{"echo", boost::factory<echo_builtin*>()},
{"eval", boost::factory<eval_builtin*>()},
{"export", boost::factory<export_builtin*>()},
+ {"local", boost::factory<local_builtin*>()},
{"declare", boost::factory<declare_builtin*>()},
{"source", boost::factory<source_builtin*>()},
{"shift", boost::factory<shift_builtin*>()},
diff --git a/test/verify_error_output_test.sh b/test/verify_error_output_test.sh
index cbf6cf2..f6d96ed 100755
--- a/test/verify_error_output_test.sh
+++ b/test/verify_error_output_test.sh
@@ -2,4 +2,4 @@
illegal="${srcdir}/scripts/illegal_script.sh"
output=$(./variable_printer "$illegal" 2>&1)
-[[ $output == "${illegal}(1) : error 1 : Unexpected token, at offset 3"* ]]
+[[ $output == *"(1) : error 1 : Unexpected token, at offset"* ]]