aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPetteri Räty <petsku@petteriraty.eu>2011-05-11 10:15:58 +0300
committerPetteri Räty <petsku@petteriraty.eu>2011-05-11 10:15:58 +0300
commitaf3866332694ab98054f042c95080d130e310a06 (patch)
tree93c054fa7d477b3a655bd4b6f0dfc5b61ba766fc
parentParser: rename MATCH_PATTERN to MATCH_ANY (diff)
parentWalker: support patterns in variable expansion (diff)
downloadlibbash-af3866332694ab98054f042c95080d130e310a06.tar.gz
libbash-af3866332694ab98054f042c95080d130e310a06.tar.bz2
libbash-af3866332694ab98054f042c95080d130e310a06.zip
Merge remote-tracking branch 'mu/pattern_matching'
Conflicts: bashast/bashast.g
-rw-r--r--bashast/bashast.g10
-rw-r--r--bashast/features_script/features.sh.ast2
-rw-r--r--bashast/gunit/compound.gunit10
-rw-r--r--bashast/gunit/param_main.gunit2
-rw-r--r--bashast/libbashWalker.g194
-rw-r--r--scripts/compound_command.bash57
-rw-r--r--scripts/compound_command.bash.result8
-rw-r--r--scripts/var_expansion.bash10
-rw-r--r--scripts/var_expansion.bash.result10
-rw-r--r--src/core/interpreter.cpp49
-rw-r--r--src/core/interpreter.h33
11 files changed, 268 insertions, 117 deletions
diff --git a/bashast/bashast.g b/bashast/bashast.g
index 220d01f..c4156ec 100644
--- a/bashast/bashast.g
+++ b/bashast/bashast.g
@@ -70,6 +70,8 @@ tokens{
EXTENDED_MATCH_AT_LEAST_ONE;
MATCH_ANY;
MATCH_ANY_EXCEPT;
+ MATCH_ALL;
+ MATCH_ONE;
CHARACTER_CLASS;
EQUIVALENCE_CLASS;
COLLATING_SYMBOL;
@@ -416,8 +418,8 @@ fname_part
| res_word_str;
//non-quoted string part rule, allows expansions
nqstr_part
- : bracket_pattern_match
- | extended_pattern_match
+ : extended_pattern_match
+ | bracket_pattern_match
| var_ref
| command_sub
| arithmetic_expansion
@@ -452,7 +454,9 @@ bracket_pattern_match
: LSQUARE RSQUARE (BANG|CARET) pattern_match* RSQUARE -> ^(MATCH_ANY_EXCEPT RSQUARE pattern_match*)
| LSQUARE RSQUARE pattern_match* RSQUARE -> ^(MATCH_ANY RSQUARE pattern_match*)
| LSQUARE (BANG|CARET) pattern_match+ RSQUARE -> ^(MATCH_ANY_EXCEPT pattern_match+)
- | LSQUARE pattern_match+ RSQUARE -> ^(MATCH_ANY pattern_match+);
+ | LSQUARE pattern_match+ RSQUARE -> ^(MATCH_ANY pattern_match+)
+ | TIMES -> MATCH_ALL
+ | QMARK -> MATCH_ONE;
//allowable patterns with bracket pattern matching
pattern_match
: pattern_class_match
diff --git a/bashast/features_script/features.sh.ast b/bashast/features_script/features.sh.ast
index b9b6c62..920a23a 100644
--- a/bashast/features_script/features.sh.ast
+++ b/bashast/features_script/features.sh.ast
@@ -1 +1 @@
-(LIST (function (STRING lots_o_echo) (CURRENT_SHELL (LIST (COMMAND (STRING echo) (STRING (DOUBLE_QUOTED_STRING The number of tests that have failed : (VAR_REF failedtests)))) (COMMAND (STRING echo) (STRING (SINGLE_QUOTED_STRING $ failedtests))) (COMMAND (STRING echo) (STRING (VAR_REF failedtests)))))) (function (STRING do_some_arith) (CURRENT_SHELL (LIST (COMPOUND_ARITH (* 5 4)) (COMPOUND_ARITH (** 5 4)) (COMPOUND_ARITH (+ (VAR_REF (VAR_REF failedtests)) (/ 5 4))) (COMPOUND_ARITH (+ (VAR_REF (VAR_REF z)) (MINUS_SIGN 3)))))) (function (STRING arrays) (SUBSHELL (LIST (VARIABLE_DEFINITIONS (= asdf (ARRAY (STRING a) (STRING b) (STRING c) (STRING d)))) (COMMAND (STRING echo) (STRING (VAR_REF (asdf 3)))) (VARIABLE_DEFINITIONS (= foo (ARRAY (STRING (COMMAND_SUB (LIST (COMMAND (STRING echo) (STRING 6))))) (STRING b) (STRING c) (STRING d)))) (VARIABLE_DEFINITIONS (= (arr (VAR_REF foo)) (STRING 3))) (VARIABLE_DEFINITIONS (= bar (ARRAY (STRING a) (STRING b) (= 5 (STRING c)))))))) (COMMAND (STRING echo) (STRING (BRACE_EXP (STRING a) (STRING b)))) (COMMAND (STRING echo) (STRING (BRACE_EXP (.. a d)))) (COMMAND (STRING echo) (STRING (BRACE_EXP (BRACE_EXP (STRING a) (STRING b)) (STRING c) (STRING d)))) (COMMAND (STRING echo) (STRING a (BRACE_EXP (STRING b) (STRING c)))) (COMMAND (STRING (COMMAND_SUB (LIST (COMMAND (STRING echo) (STRING foobar)))))) (| (COMMAND (STRING ls)) (COMMAND (STRING grep) (STRING gunit) (REDIR >> (STRING filelist)))) (case (COMMAND_SUB (LIST (COMMAND (STRING echo) (STRING asdf)))) (CASE_PATTERN (STRING gz) CASE_COMMAND (LIST (COMMAND (STRING echo) (STRING yay)))) (CASE_PATTERN (STRING bzip) CASE_COMMAND (LIST (COMMAND (STRING echo) (STRING three)))) (CASE_PATTERN (STRING *) CASE_COMMAND (LIST (COMMAND (STRING echo) (STRING woo))))) (for each (STRING (COMMAND_SUB (LIST (| (COMMAND (STRING ls)) (COMMAND (STRING grep) (STRING log)))))) (LIST (COMMAND (STRING echo) (STRING (VAR_REF each))) (COMMAND (STRING cat) (STRING each)))) (CFOR (FOR_INIT (+ 5 3)) (FOR_COND (+ 6 2)) (LIST (COMMAND (STRING echo) (STRING yay))) (FOR_MOD (+ 3 1))) (select each (COMMAND_SUB (LIST (| (COMMAND (STRING ls)) (COMMAND (STRING grep) (STRING output))))) (LIST (COMMAND (STRING echo) (STRING asdf) (STRING 2) (REDIR > (STRING / dev / null))))) (IF_STATEMENT (if (LIST (COMMAND (STRING echo) (STRING yay2))) (LIST (COMMAND (STRING echo) (STRING yay))))) (until (LIST (COMPOUND_COND (KEYWORD_TEST (a (STRING this / is . afile))))) (LIST (COMMAND (STRING touch) (STRING this / is . afile)))) (while (LIST (COMPOUND_COND (BUILTIN_TEST (n (STRING foobar))))) (LIST (COMMAND (STRING echo) (STRING (DOUBLE_QUOTED_STRING file found))))) (IF_STATEMENT (if (LIST (COMPOUND_COND (BUILTIN_TEST (eq (STRING 5) (STRING 6))))) (LIST (COMMAND (STRING echo) (STRING (DOUBLE_QUOTED_STRING something ' s wrong)))))) (COMMAND (STRING echo) (STRING this) (STRING command) (STRING has) (STRING multiple) (STRING arguments)) (COMMAND (STRING wc) (PROCESS_SUBSTITUTION < (LIST (COMMAND (STRING cat) (STRING / usr / share / dict / linux . words))))) (|| (&& (&& (&& (COMMAND (STRING cd) (STRING build)) (COMMAND (STRING . / configure))) (COMMAND (STRING make))) (COMMAND (STRING make_install))) (COMMAND (STRING echo) (STRING fail))) (COMMAND (STRING cd) (STRING / usr / bin)) (| (COMMAND (STRING ls) (STRING - al)) (COMMAND (STRING grep) (STRING more))) (VARIABLE_DEFINITIONS (= asdf (STRING parameters))) (COMMAND (STRING (VAR_REF (USE_DEFAULT_WHEN_UNSET_OR_NULL asdf (STRING foo))))) (COMMAND (STRING (VAR_REF (OFFSET asdf 8)))) (COMMAND (STRING (VAR_REF (! asdf *)))) (COMMAND (STRING (VAR_REF (! asdf @)))) (COMMAND (STRING (VAR_REF (# foo)))) (COMMAND (STRING (VAR_REF (REPLACE_FIRST replaice (STRING with) (STRING pattern))))) (COMMAND (STRING (VAR_REF (LAZY_REMOVE_AT_START asdf (STRING bar))))) (COMMAND (STRING (VAR_REF (REPLACE_AT_START asdf (STRING bar))))) (COMMAND (STRING (VAR_REF (LAZY_REMOVE_AT_END asdf (STRING bar))))) (COMMAND (STRING (VAR_REF (LAZY_REMOVE_AT_END asdf (STRING bar))))) (COMMAND (STRING (VAR_REF 1)) (STRING (VAR_REF @)) (STRING (VAR_REF *))) (COMMAND (STRING (VAR_REF ?))) (COMMAND (STRING (VAR_REF (REPLACE_ALL PV (STRING .) (STRING _))))) (COMMAND (STRING (VAR_REF (REPLACE_AT_START PV (STRING foo) (STRING bar))))) (COMMAND (STRING (VAR_REF (REPLACE_AT_END PV (STRING foo) (STRING bar))))) (VARIABLE_DEFINITIONS (= MY_PN (STRING (VAR_REF (REPLACE_FIRST PN (STRING asterisk -)))))) (| (COMMAND (STRING cat) (STRING asdf)) (COMMAND (STRING grep) (STRING three) (STRING 2) (REDIR >& 1) (REDIR > (STRING / dev / null)))) (COMMAND (STRING echo) (STRING asdf) (REDIR >> (STRING APPEND))) (COMMAND (STRING echo) (STRING cat) (<<< (STRING word))))
+(LIST (function (STRING lots_o_echo) (CURRENT_SHELL (LIST (COMMAND (STRING echo) (STRING (DOUBLE_QUOTED_STRING The number of tests that have failed : (VAR_REF failedtests)))) (COMMAND (STRING echo) (STRING (SINGLE_QUOTED_STRING $ failedtests))) (COMMAND (STRING echo) (STRING (VAR_REF failedtests)))))) (function (STRING do_some_arith) (CURRENT_SHELL (LIST (COMPOUND_ARITH (* 5 4)) (COMPOUND_ARITH (** 5 4)) (COMPOUND_ARITH (+ (VAR_REF (VAR_REF failedtests)) (/ 5 4))) (COMPOUND_ARITH (+ (VAR_REF (VAR_REF z)) (MINUS_SIGN 3)))))) (function (STRING arrays) (SUBSHELL (LIST (VARIABLE_DEFINITIONS (= asdf (ARRAY (STRING a) (STRING b) (STRING c) (STRING d)))) (COMMAND (STRING echo) (STRING (VAR_REF (asdf 3)))) (VARIABLE_DEFINITIONS (= foo (ARRAY (STRING (COMMAND_SUB (LIST (COMMAND (STRING echo) (STRING 6))))) (STRING b) (STRING c) (STRING d)))) (VARIABLE_DEFINITIONS (= (arr (VAR_REF foo)) (STRING 3))) (VARIABLE_DEFINITIONS (= bar (ARRAY (STRING a) (STRING b) (= 5 (STRING c)))))))) (COMMAND (STRING echo) (STRING (BRACE_EXP (STRING a) (STRING b)))) (COMMAND (STRING echo) (STRING (BRACE_EXP (.. a d)))) (COMMAND (STRING echo) (STRING (BRACE_EXP (BRACE_EXP (STRING a) (STRING b)) (STRING c) (STRING d)))) (COMMAND (STRING echo) (STRING a (BRACE_EXP (STRING b) (STRING c)))) (COMMAND (STRING (COMMAND_SUB (LIST (COMMAND (STRING echo) (STRING foobar)))))) (| (COMMAND (STRING ls)) (COMMAND (STRING grep) (STRING gunit) (REDIR >> (STRING filelist)))) (case (COMMAND_SUB (LIST (COMMAND (STRING echo) (STRING asdf)))) (CASE_PATTERN (STRING gz) CASE_COMMAND (LIST (COMMAND (STRING echo) (STRING yay)))) (CASE_PATTERN (STRING bzip) CASE_COMMAND (LIST (COMMAND (STRING echo) (STRING three)))) (CASE_PATTERN (STRING MATCH_ALL) CASE_COMMAND (LIST (COMMAND (STRING echo) (STRING woo))))) (for each (STRING (COMMAND_SUB (LIST (| (COMMAND (STRING ls)) (COMMAND (STRING grep) (STRING log)))))) (LIST (COMMAND (STRING echo) (STRING (VAR_REF each))) (COMMAND (STRING cat) (STRING each)))) (CFOR (FOR_INIT (+ 5 3)) (FOR_COND (+ 6 2)) (LIST (COMMAND (STRING echo) (STRING yay))) (FOR_MOD (+ 3 1))) (select each (COMMAND_SUB (LIST (| (COMMAND (STRING ls)) (COMMAND (STRING grep) (STRING output))))) (LIST (COMMAND (STRING echo) (STRING asdf) (STRING 2) (REDIR > (STRING / dev / null))))) (IF_STATEMENT (if (LIST (COMMAND (STRING echo) (STRING yay2))) (LIST (COMMAND (STRING echo) (STRING yay))))) (until (LIST (COMPOUND_COND (KEYWORD_TEST (a (STRING this / is . afile))))) (LIST (COMMAND (STRING touch) (STRING this / is . afile)))) (while (LIST (COMPOUND_COND (BUILTIN_TEST (n (STRING foobar))))) (LIST (COMMAND (STRING echo) (STRING (DOUBLE_QUOTED_STRING file found))))) (IF_STATEMENT (if (LIST (COMPOUND_COND (BUILTIN_TEST (eq (STRING 5) (STRING 6))))) (LIST (COMMAND (STRING echo) (STRING (DOUBLE_QUOTED_STRING something ' s wrong)))))) (COMMAND (STRING echo) (STRING this) (STRING command) (STRING has) (STRING multiple) (STRING arguments)) (COMMAND (STRING wc) (PROCESS_SUBSTITUTION < (LIST (COMMAND (STRING cat) (STRING / usr / share / dict / linux . words))))) (|| (&& (&& (&& (COMMAND (STRING cd) (STRING build)) (COMMAND (STRING . / configure))) (COMMAND (STRING make))) (COMMAND (STRING make_install))) (COMMAND (STRING echo) (STRING fail))) (COMMAND (STRING cd) (STRING / usr / bin)) (| (COMMAND (STRING ls) (STRING - al)) (COMMAND (STRING grep) (STRING more))) (VARIABLE_DEFINITIONS (= asdf (STRING parameters))) (COMMAND (STRING (VAR_REF (USE_DEFAULT_WHEN_UNSET_OR_NULL asdf (STRING foo))))) (COMMAND (STRING (VAR_REF (OFFSET asdf 8)))) (COMMAND (STRING (VAR_REF (! asdf *)))) (COMMAND (STRING (VAR_REF (! asdf @)))) (COMMAND (STRING (VAR_REF (# foo)))) (COMMAND (STRING (VAR_REF (REPLACE_FIRST replaice (STRING with) (STRING pattern))))) (COMMAND (STRING (VAR_REF (LAZY_REMOVE_AT_START asdf (STRING bar))))) (COMMAND (STRING (VAR_REF (REPLACE_AT_START asdf (STRING bar))))) (COMMAND (STRING (VAR_REF (LAZY_REMOVE_AT_END asdf (STRING bar))))) (COMMAND (STRING (VAR_REF (LAZY_REMOVE_AT_END asdf (STRING bar))))) (COMMAND (STRING (VAR_REF 1)) (STRING (VAR_REF @)) (STRING (VAR_REF *))) (COMMAND (STRING (VAR_REF ?))) (COMMAND (STRING (VAR_REF (REPLACE_ALL PV (STRING .) (STRING _))))) (COMMAND (STRING (VAR_REF (REPLACE_AT_START PV (STRING foo) (STRING bar))))) (COMMAND (STRING (VAR_REF (REPLACE_AT_END PV (STRING foo) (STRING bar))))) (VARIABLE_DEFINITIONS (= MY_PN (STRING (VAR_REF (REPLACE_FIRST PN (STRING asterisk -)))))) (| (COMMAND (STRING cat) (STRING asdf)) (COMMAND (STRING grep) (STRING three) (STRING 2) (REDIR >& 1) (REDIR > (STRING / dev / null)))) (COMMAND (STRING echo) (STRING asdf) (REDIR >> (STRING APPEND))) (COMMAND (STRING echo) (STRING cat) (<<< (STRING word))))
diff --git a/bashast/gunit/compound.gunit b/bashast/gunit/compound.gunit
index 398bb3d..a7ce999 100644
--- a/bashast/gunit/compound.gunit
+++ b/bashast/gunit/compound.gunit
@@ -65,7 +65,7 @@ echo three
;;
*) echo woo
;;
-esac" -> (case (COMMAND_SUB (LIST (COMMAND (STRING echo) (STRING asdf)))) (CASE_PATTERN (STRING gz) CASE_COMMAND (LIST (COMMAND (STRING echo) (STRING yay)))) (CASE_PATTERN (STRING bzip) CASE_COMMAND (LIST (COMMAND (STRING echo) (STRING three)))) (CASE_PATTERN (STRING *) CASE_COMMAND (LIST (COMMAND (STRING echo) (STRING woo)))))
+esac" -> (case (COMMAND_SUB (LIST (COMMAND (STRING echo) (STRING asdf)))) (CASE_PATTERN (STRING gz) CASE_COMMAND (LIST (COMMAND (STRING echo) (STRING yay)))) (CASE_PATTERN (STRING bzip) CASE_COMMAND (LIST (COMMAND (STRING echo) (STRING three)))) (CASE_PATTERN (STRING MATCH_ALL) CASE_COMMAND (LIST (COMMAND (STRING echo) (STRING woo)))))
"case `echo asdf` in
gz)
@@ -75,10 +75,10 @@ esac" -> (case (COMMAND_SUB (LIST (COMMAND (STRING echo) (STRING asdf)))) (CASE_
echo three
;;
*) echo woo
-esac" -> (case (COMMAND_SUB (LIST (COMMAND (STRING echo) (STRING asdf)))) (CASE_PATTERN (STRING gz) CASE_COMMAND (LIST (COMMAND (STRING echo) (STRING yay)))) (CASE_PATTERN (STRING bzip) CASE_COMMAND (LIST (COMMAND (STRING echo) (STRING three)))) (CASE_PATTERN (STRING *) CASE_COMMAND (LIST (COMMAND (STRING echo) (STRING woo)))))
+esac" -> (case (COMMAND_SUB (LIST (COMMAND (STRING echo) (STRING asdf)))) (CASE_PATTERN (STRING gz) CASE_COMMAND (LIST (COMMAND (STRING echo) (STRING yay)))) (CASE_PATTERN (STRING bzip) CASE_COMMAND (LIST (COMMAND (STRING echo) (STRING three)))) (CASE_PATTERN (STRING MATCH_ALL) CASE_COMMAND (LIST (COMMAND (STRING echo) (STRING woo)))))
"case `echo asdf` in gz|asdf) echo yay ;; bzip) echo three ;; *) echo woo esac" FAIL
-"case `echo asdf` in gz|asdf) echo yay ;; bzip) echo three ;; *) echo woo ;; esac" -> (case (COMMAND_SUB (LIST (COMMAND (STRING echo) (STRING asdf)))) (CASE_PATTERN (STRING gz) (STRING asdf) CASE_COMMAND (LIST (COMMAND (STRING echo) (STRING yay)))) (CASE_PATTERN (STRING bzip) CASE_COMMAND (LIST (COMMAND (STRING echo) (STRING three)))) (CASE_PATTERN (STRING *) CASE_COMMAND (LIST (COMMAND (STRING echo) (STRING woo)))))
+"case `echo asdf` in gz|asdf) echo yay ;; bzip) echo three ;; *) echo woo ;; esac" -> (case (COMMAND_SUB (LIST (COMMAND (STRING echo) (STRING asdf)))) (CASE_PATTERN (STRING gz) (STRING asdf) CASE_COMMAND (LIST (COMMAND (STRING echo) (STRING yay)))) (CASE_PATTERN (STRING bzip) CASE_COMMAND (LIST (COMMAND (STRING echo) (STRING three)))) (CASE_PATTERN (STRING MATCH_ALL) CASE_COMMAND (LIST (COMMAND (STRING echo) (STRING woo)))))
for_expr:
"for each in `ls |grep log`; do
@@ -147,7 +147,7 @@ case_expr:
echo \"Usage: $0 start|stop\" >&2
exit 3
;;
-esac" -> (case (STRING (DOUBLE_QUOTED_STRING (VAR_REF 1))) (CASE_PATTERN (STRING *) CASE_COMMAND (LIST (COMMAND (STRING echo) (STRING (DOUBLE_QUOTED_STRING Usage : (VAR_REF 0) start | stop)) (REDIR >& 2)) (COMMAND (STRING exit) (STRING 3)))))
+esac" -> (case (STRING (DOUBLE_QUOTED_STRING (VAR_REF 1))) (CASE_PATTERN (STRING MATCH_ALL) CASE_COMMAND (LIST (COMMAND (STRING echo) (STRING (DOUBLE_QUOTED_STRING Usage : (VAR_REF 0) start | stop)) (REDIR >& 2)) (COMMAND (STRING exit) (STRING 3)))))
"case $asdf in
a)
@@ -168,4 +168,4 @@ stop)
echo \"Usage: $0 start|stop\" >&2
exit 3
;;
-esac" -> (case (STRING (DOUBLE_QUOTED_STRING (VAR_REF 1))) (CASE_PATTERN (STRING stop)) (CASE_PATTERN (STRING *) CASE_COMMAND (LIST (COMMAND (STRING echo) (STRING (DOUBLE_QUOTED_STRING Usage : (VAR_REF 0) start | stop)) (REDIR >& 2)) (COMMAND (STRING exit) (STRING 3)))))
+esac" -> (case (STRING (DOUBLE_QUOTED_STRING (VAR_REF 1))) (CASE_PATTERN (STRING stop)) (CASE_PATTERN (STRING MATCH_ALL) CASE_COMMAND (LIST (COMMAND (STRING echo) (STRING (DOUBLE_QUOTED_STRING Usage : (VAR_REF 0) start | stop)) (REDIR >& 2)) (COMMAND (STRING exit) (STRING 3)))))
diff --git a/bashast/gunit/param_main.gunit b/bashast/gunit/param_main.gunit
index 54a2edb..5fd818e 100644
--- a/bashast/gunit/param_main.gunit
+++ b/bashast/gunit/param_main.gunit
@@ -39,7 +39,7 @@ var_ref:
"${foo##bar}" -> (VAR_REF (REPLACE_AT_START foo (STRING bar)))
"${foo%bar}" -> (VAR_REF (LAZY_REMOVE_AT_END foo (STRING bar)))
"${foo%%bar}" -> (VAR_REF (REPLACE_AT_END foo (STRING bar)))
-"${foo%; *}" -> (VAR_REF (LAZY_REMOVE_AT_END foo (STRING ; *)))
+"${foo%; *}" -> (VAR_REF (LAZY_REMOVE_AT_END foo (STRING ; MATCH_ALL)))
"${foo%/}" -> (VAR_REF (LAZY_REMOVE_AT_END foo (STRING /)))
"${this/is/pattern}"->(VAR_REF (REPLACE_FIRST this (STRING is) (STRING pattern)))
//Test positional/special parameters
diff --git a/bashast/libbashWalker.g b/bashast/libbashWalker.g
index f39e603..307333d 100644
--- a/bashast/libbashWalker.g
+++ b/bashast/libbashWalker.g
@@ -27,9 +27,12 @@ options
@includes{
+ #include <memory>
#include <string>
#include <vector>
+ #include <boost/xpressive/xpressive.hpp>
+
class interpreter;
void set_interpreter(interpreter* w);
@@ -86,6 +89,29 @@ options
SEEK(INDEX() + index - 3);
CONSUME();
}
+
+ // The method is used to append a pattern with another one. Because it's not allowed to append an empty pattern,
+ // we need the argument 'do_append' to indicate whether the pattern is empty. 'do_append' will be set to true after
+ // the first assignment.
+ inline void append(boost::xpressive::sregex& pattern, const boost::xpressive::sregex& new_pattern, bool& do_append)
+ {
+ using namespace boost::xpressive;
+ if(do_append)
+ {
+ pattern = sregex(pattern >> new_pattern);
+ }
+ else
+ {
+ pattern = new_pattern;
+ do_append = true;
+ }
+ }
+
+ bool match(const std::string& target,
+ const boost::xpressive::sregex& pattern)
+ {
+ return boost::xpressive::regex_match(target, pattern);
+ }
}
start: list|EOF;
@@ -149,15 +175,98 @@ string_expr returns[std::string libbash_value, bool quoted]
$quoted = true;
}
:^(STRING (
+ string_part {
+ $libbash_value += $string_part.libbash_value;
+ $quoted = $string_part.quoted;
+ }
+ )+);
+
+string_part returns[std::string libbash_value, bool quoted]
+@init {
+ $quoted = false;
+}
+ :(DOUBLE_QUOTED_STRING) =>
+ ^(DOUBLE_QUOTED_STRING (libbash_string=double_quoted_string {
+ $libbash_value += libbash_string;
+ $quoted = true;
+ })*)
+ |(ARITHMETIC_EXPRESSION) =>
+ ^(ARITHMETIC_EXPRESSION value=arithmetics {
+ $libbash_value = boost::lexical_cast<std::string>(value);
+ })
+ |(var_ref[false]) => libbash_string=var_ref[false] {
+ $libbash_value = libbash_string;
+ }
+ |libbash_string=command_substitution {
+ $libbash_value = libbash_string;
+ }
+ |(libbash_string=any_string {
+ $libbash_value = libbash_string;
+ });
+
+bash_pattern[boost::xpressive::sregex& pattern, bool greedy]
+@declarations {
+ using namespace boost::xpressive;
+ bool do_append = false;
+ bool negation;
+ std::string pattern_str;
+}
+ :^(STRING (
(DOUBLE_QUOTED_STRING) =>
- ^(DOUBLE_QUOTED_STRING (libbash_string=double_quoted_string { $libbash_value += libbash_string; })*)
- |(ARITHMETIC_EXPRESSION) =>
- ^(ARITHMETIC_EXPRESSION value=arithmetics {
- $libbash_value += boost::lexical_cast<std::string>(value); $quoted = false;
- })
- |(var_ref[false]) => libbash_string=var_ref[false] { $libbash_value += libbash_string; $quoted = false; }
- |libbash_string=command_substitution { $libbash_value += libbash_string; $quoted = false; }
- |(libbash_string=any_string { $libbash_value += libbash_string; $quoted = false; })
+ ^(DOUBLE_QUOTED_STRING (libbash_string=double_quoted_string {
+ append($pattern, as_xpr(libbash_string), do_append);
+ })*)
+ |(MATCH_ALL) => MATCH_ALL {
+ if($greedy)
+ append($pattern, *_, do_append);
+ else
+ append($pattern, -*_, do_append);
+ }
+ |(MATCH_ONE) => MATCH_ONE {
+ append($pattern, _, do_append);
+ }
+ |(MATCH_ANY_EXCEPT|MATCH_ANY) =>
+ ^((MATCH_ANY_EXCEPT { negation = true; } | MATCH_ANY { negation = false; })
+ (s=string_part { pattern_str += s.libbash_value; })+) {
+ if(pattern_str.empty())
+ return;
+
+ // deal with the first character specially
+ int index = 0;
+ auto char_set = set = as_xpr(pattern_str[0]);
+ if( index + 1 < pattern_str.size() && pattern_str[index + 1] == '-')
+ {
+ char_set = set[range(pattern_str[index], pattern_str[index + 2])];
+ index += 3;
+ }
+ else
+ {
+ ++index;
+ }
+
+ // handle all characters in the pattern
+ while(index < pattern_str.size())
+ {
+ if( index + 1 < pattern_str.size() && pattern_str[index + 1] == '-')
+ {
+ char_set |= range(pattern_str[index], pattern_str[index + 2]);
+ index += 3;
+ }
+ else
+ {
+ char_set |= pattern_str[index];
+ ++index;
+ }
+ }
+
+ if(negation)
+ append($pattern, ~char_set, do_append);
+ else
+ append($pattern, char_set, do_append);
+ }
+ |(libbash_string=any_string {
+ append($pattern, as_xpr(libbash_string), do_append);
+ })
)+);
//double quoted string rule, allows expansions
@@ -186,6 +295,11 @@ var_name returns[std::string libbash_value, unsigned index]
};
var_expansion returns[std::string libbash_value]
+@declarations {
+ using namespace boost::xpressive;
+ sregex replace_pattern;
+ bool greedy;
+}
:^(USE_DEFAULT_WHEN_UNSET_OR_NULL var_name libbash_word=word) {
libbash_value = walker->do_default_expansion($var_name.libbash_value, libbash_word, $var_name.index);
}
@@ -209,56 +323,54 @@ var_expansion returns[std::string libbash_value]
libbash_value = boost::lexical_cast<std::string>(walker->get_array_length(libbash_name));
}
))
- |^(REPLACE_ALL var_name pattern=string_expr (replacement=string_expr)?) {
+ |^(REPLACE_ALL var_name bash_pattern[replace_pattern, true] (replacement=string_expr)?) {
libbash_value = walker->do_replace_expansion($var_name.libbash_value,
std::bind(&interpreter::replace_all,
std::placeholders::_1,
- pattern.libbash_value,
+ replace_pattern,
replacement.libbash_value),
$var_name.index);
}
- |^(REPLACE_AT_END var_name pattern=string_expr (replacement=string_expr)?) {
+ |^(REPLACE_AT_END var_name bash_pattern[replace_pattern, true] (replacement=string_expr)?) {
+ replace_pattern = sregex(replace_pattern >> eos);
libbash_value = walker->do_replace_expansion($var_name.libbash_value,
- std::bind(&interpreter::replace_at_end,
+ std::bind(&interpreter::replace_all,
std::placeholders::_1,
- pattern.libbash_value,
+ replace_pattern,
replacement.libbash_value),
$var_name.index);
}
- |^(REPLACE_AT_START var_name pattern=string_expr (replacement=string_expr)?) {
+ |^(LAZY_REMOVE_AT_END var_name bash_pattern[replace_pattern, false] (replacement=string_expr)?) {
+ replace_pattern = sregex(bos >> (s1=*_) >> replace_pattern >> eos);
libbash_value = walker->do_replace_expansion($var_name.libbash_value,
- std::bind(&interpreter::replace_at_start,
+ std::bind(&interpreter::lazy_remove_at_end,
std::placeholders::_1,
- pattern.libbash_value,
- replacement.libbash_value),
+ replace_pattern),
$var_name.index);
}
- |^(REPLACE_FIRST var_name pattern=string_expr (replacement=string_expr)?) {
+ |^((REPLACE_AT_START { greedy = true; }|LAZY_REMOVE_AT_START { greedy = false; })
+ var_name bash_pattern[replace_pattern, greedy] (replacement=string_expr)?) {
+ replace_pattern = sregex(bos >> replace_pattern);
libbash_value = walker->do_replace_expansion($var_name.libbash_value,
- std::bind(&interpreter::replace_first,
+ std::bind(&interpreter::replace_all,
std::placeholders::_1,
- pattern.libbash_value,
+ replace_pattern,
replacement.libbash_value),
$var_name.index);
}
- |^(LAZY_REMOVE_AT_START var_name pattern=string_expr) {
+ |^(REPLACE_FIRST var_name bash_pattern[replace_pattern, true] (replacement=string_expr)?) {
libbash_value = walker->do_replace_expansion($var_name.libbash_value,
- std::bind(&interpreter::lazy_remove_at_start,
- std::placeholders::_1,
- pattern.libbash_value),
- $var_name.index);
- }
- |^(LAZY_REMOVE_AT_END var_name pattern=string_expr) {
- libbash_value = walker->do_replace_expansion($var_name.libbash_value,
- std::bind(&interpreter::lazy_remove_at_end,
+ std::bind(&interpreter::replace_first,
std::placeholders::_1,
- pattern.libbash_value),
+ replace_pattern,
+ replacement.libbash_value),
$var_name.index);
};
word returns[std::string libbash_value]
:(num) => libbash_string=num { $libbash_value = libbash_string; }
|string_expr { $libbash_value = $string_expr.libbash_value; }
+ |(VAR_REF) => libbash_string=var_ref[false] { $libbash_value = libbash_string; }
|value=arithmetics { $libbash_value = boost::lexical_cast<std::string>(value); };
//variable reference
@@ -524,35 +636,29 @@ case_expr
case_clause[const std::string& target] returns[bool matched]
@declarations {
- std::vector<std::string> patterns;
+ std::vector<boost::xpressive::sregex> patterns;
}
- :^(CASE_PATTERN (libbash_string=case_pattern { patterns.push_back(libbash_string); })+ {
+ :^(CASE_PATTERN ( { patterns.push_back(boost::xpressive::sregex()); } bash_pattern[patterns.back(), true])+ {
if(LA(1) == CASE_COMMAND)
{
// omit CASE_COMMAND
SEEK(INDEX() + 1);
- matched = false;
+ $matched = false;
+
for(auto iter = patterns.begin(); iter != patterns.end(); ++iter)
{
- // pattern matching should happen here in future
- if(*iter == "*" || *iter == target)
+ if(match(target, *iter))
{
command_list(ctx);
$matched = true;
- }
- else
- {
- seek_to_next_tree(ctx);
+ break;
}
}
+ if(!$matched)
+ seek_to_next_tree(ctx);
}
});
-case_pattern returns[std::string libbash_value]
- :libbash_string=command_substitution { $libbash_value = libbash_string; }
- |string_expr { $libbash_value = $string_expr.libbash_value; }
- |TIMES { $libbash_value = "*"; };
-
command_substitution returns[std::string libbash_value]
@declarations {
std::stringstream out;
diff --git a/scripts/compound_command.bash b/scripts/compound_command.bash
index 6365fbe..a75898f 100644
--- a/scripts/compound_command.bash
+++ b/scripts/compound_command.bash
@@ -85,19 +85,20 @@ fi
target=123
case $target in
- bcd)
+ 1.3)
echo "Shouldn't print this"
;;
- abc)
+ \d+)
echo "Shouldn't print this"
;;
- 123)
+ 456|1?*|789)
echo yep
;;
123)
echo "Shouldn't print this"
;;
esac
+target=xyz
case $target in
bcd)
echo "Shouldn't print this"
@@ -109,4 +110,54 @@ case $target in
echo "default"
;;
esac
+target=a
+case $target in
+ [def])
+ echo "Shouldn't print this"
+ ;;
+ [abc])
+ echo yep
+ ;;
+esac
+case $target in
+ [def])
+ echo "Shouldn't print this"
+ ;;
+ [a])
+ echo yep
+ ;;
+esac
+case $target in
+ [!abc])
+ echo "Shouldn't print this"
+ ;;
+ [!def])
+ echo yep
+ ;;
+esac
+case $target in
+ [d-z])
+ echo "Shouldn't print this"
+ ;;
+ [a-c])
+ echo yep
+ ;;
+esac
+case $target in
+ [!a-c])
+ echo "Shouldn't print this"
+ ;;
+ [!d-z])
+ echo yep
+ ;;
+esac
+target=bar
+case $target in
+ a[a-cx-z]r)
+ echo "Shouldn't print this"
+ ;;
+ b[!d-fx-z]r)
+ echo yep
+ ;;
+esac
echo "case end"
diff --git a/scripts/compound_command.bash.result b/scripts/compound_command.bash.result
index 69d693d..255c8eb 100644
--- a/scripts/compound_command.bash.result
+++ b/scripts/compound_command.bash.result
@@ -25,10 +25,16 @@ ghi
1
yep
default
+yep
+yep
+yep
+yep
+yep
+yep
case end
a=1
b=2
file= foo bar
foo=ghi
i=4
-target=123
+target=bar
diff --git a/scripts/var_expansion.bash b/scripts/var_expansion.bash
index 5ebd63e..7a371b3 100644
--- a/scripts/var_expansion.bash
+++ b/scripts/var_expansion.bash
@@ -60,3 +60,13 @@ FOO058=${FOO039%world}
FOO059=${FOO039%%world}
FOO060=${FOO039%World}
FOO061=${FOO039%%World}
+FOO062=${FOO039#Hel*}
+FOO063=${FOO039##Hel*}
+FOO064=${FOO039%*rld}
+FOO065=${FOO039%%*rld}
+FOO066=${FOO039/l/r}
+FOO067=${FOO039//l/r}
+FOO068=${FOO039/#He/he}
+FOO069=${FOO039/#ello/i}
+FOO070=${FOO039/%ld/d}
+FOO071=${FOO039/%rl/r}
diff --git a/scripts/var_expansion.bash.result b/scripts/var_expansion.bash.result
index 50fd5d5..a1fe905 100644
--- a/scripts/var_expansion.bash.result
+++ b/scripts/var_expansion.bash.result
@@ -62,3 +62,13 @@ FOO058=Hello World
FOO059=Hello World
FOO060=Hello
FOO061=Hello
+FOO062=lo World
+FOO063=
+FOO064=Hello Wo
+FOO065=
+FOO066=Herlo World
+FOO067=Herro Worrd
+FOO068=hello World
+FOO069=Hello World
+FOO070=Hello Word
+FOO071=Hello World
diff --git a/src/core/interpreter.cpp b/src/core/interpreter.cpp
index aa6c4de..1102138 100644
--- a/src/core/interpreter.cpp
+++ b/src/core/interpreter.cpp
@@ -228,48 +228,33 @@ int interpreter::call(const std::string& name,
}
void interpreter::replace_all(std::string& value,
- const std::string& pattern,
+ const boost::xpressive::sregex& pattern,
const std::string& replacement)
{
- boost::replace_all(value, pattern, replacement);
+ value = boost::xpressive::regex_replace(value,
+ pattern,
+ replacement,
+ boost::xpressive::regex_constants::format_literal);
}
-void interpreter::replace_at_end(std::string& value,
- const std::string& pattern,
- const std::string& replacement)
-{
- if(value.size() >= pattern.size() &&
- value.substr(value.size() - pattern.size()) == pattern)
- value.replace(value.size() - pattern.size(),
- pattern.size(),
- replacement);
-}
-
-void interpreter::replace_at_start(std::string& value,
- const std::string& pattern,
- const std::string& replacement)
+void interpreter::lazy_remove_at_end(std::string& value,
+ const boost::xpressive::sregex& pattern)
{
- if(value.substr(0, pattern.size()) == pattern)
- value.replace(0, pattern.size(), replacement);
+ boost::xpressive::smatch what;
+ if(boost::xpressive::regex_match(value,
+ what,
+ pattern))
+ value = what[1];
}
void interpreter::replace_first(std::string& value,
- const std::string& pattern,
+ const boost::xpressive::sregex& pattern,
const std::string& replacement)
{
- boost::replace_first(value, pattern, replacement);
-}
-
-void interpreter::lazy_remove_at_start(std::string& value,
- const std::string& pattern)
-{
- replace_at_start(value, pattern, "");
-}
-
-void interpreter::lazy_remove_at_end(std::string& value,
- const std::string& pattern)
-{
- replace_at_end(value, pattern, "");
+ value = boost::xpressive::regex_replace(value,
+ pattern,
+ replacement,
+ boost::xpressive::regex_constants::format_literal | boost::xpressive::regex_constants::format_first_only);
}
void interpreter::trim_trailing_eols(std::string& value)
diff --git a/src/core/interpreter.h b/src/core/interpreter.h
index 7673479..d71885a 100644
--- a/src/core/interpreter.h
+++ b/src/core/interpreter.h
@@ -32,6 +32,7 @@
#include <string>
#include <antlr3basetree.h>
+#include <boost/xpressive/xpressive.hpp>
#include "core/symbols.hpp"
#include "cppbash_builtin.h"
@@ -637,45 +638,23 @@ public:
/// \param the pattern used to match the value
/// \param the replacement string
static void replace_all(std::string& value,
- const std::string& pattern,
+ const boost::xpressive::sregex& pattern,
const std::string& replacement);
- /// \brief perform expansion like ${var/%foo/bar}
- /// \param the value to be expanded
- /// \param the pattern used to match the value
- /// \param the replacement string
- static void replace_at_end(std::string& value,
- const std::string& pattern,
- const std::string& replacement);
-
- /// \brief perform expansion like ${var/#foo/bar}
+ /// \brief perform expansion like ${var%foo}
/// \param the value to be expanded
/// \param the pattern used to match the value
- /// \param the replacement string
- static void replace_at_start(std::string& value,
- const std::string& pattern,
- const std::string& replacement);
+ static void lazy_remove_at_end(std::string& value,
+ const boost::xpressive::sregex& pattern);
/// \brief perform expansion like ${var/foo/bar}
/// \param the value to be expanded
/// \param the pattern used to match the value
/// \param the replacement string
static void replace_first(std::string& value,
- const std::string& pattern,
+ const boost::xpressive::sregex& pattern,
const std::string& replacement);
- /// \brief perform expansion like ${var#foo}
- /// \param the value to be expanded
- /// \param the pattern used to match the value
- static void lazy_remove_at_start(std::string& value,
- const std::string& pattern);
-
- /// \brief perform expansion like ${var%foo}
- /// \param the value to be expanded
- /// \param the pattern used to match the value
- static void lazy_remove_at_end(std::string& value,
- const std::string& pattern);
-
/// \brief remove trailing EOLs from the value
/// \param[in, out] the target
static void trim_trailing_eols(std::string& value);