From e6d7f3a96a8850199da5d71d717243333943549c Mon Sep 17 00:00:00 2001 From: Mu Qiao Date: Fri, 2 Mar 2012 16:01:49 +0800 Subject: Parser&Walker: support literals in regular exp --- bashast/bashast.g | 10 +++++++++- bashast/gunit/cond_main.gunit | 1 + bashast/libbashWalker.g | 3 ++- scripts/var_expansion.bash | 3 +-- src/core/bash_ast.cpp | 15 +++++++++------ src/core/bash_ast.h | 6 +++--- 6 files changed, 25 insertions(+), 13 deletions(-) diff --git a/bashast/bashast.g b/bashast/bashast.g index 92f4f92..c6d7f34 100644 --- a/bashast/bashast.g +++ b/bashast/bashast.g @@ -80,6 +80,7 @@ tokens{ BRANCH; MATCH_PATTERN; MATCH_REGULAR_EXPRESSION; + ESCAPED_CHAR; NOT_MATCH_PATTERN; MATCH_ANY; MATCH_ANY_EXCEPT; @@ -651,13 +652,20 @@ scope { } :( DQUOTE! { $bash_pattern_part::quoted = !$bash_pattern_part::quoted; } - | {$bash_pattern_part::quoted}? => ~DQUOTE + | {$bash_pattern_part::quoted}? => preserved_tokens | (ESC BLANK) => ESC BLANK | LPAREN { if(LA(-2) != ESC) $bash_pattern_part::parens++; } | LLPAREN { if(LA(-2) != ESC) $bash_pattern_part::parens += 2; } | {$bash_pattern_part::parens != 0}? => RPAREN { if(LA(-2) != ESC) $bash_pattern_part::parens--; } | ~(BLANK|EOL|LOGICAND|LOGICOR|LPAREN|RPAREN|DQUOTE|LLPAREN) )+; + +preserved_tokens + : non_dquote -> ESCAPED_CHAR non_dquote; + +non_dquote + : ~DQUOTE; + keyword_binary_string_operator : BLANK! binary_operator BLANK! | BLANK! EQUALS BLANK! diff --git a/bashast/gunit/cond_main.gunit b/bashast/gunit/cond_main.gunit index cb8ffef..b6f339b 100644 --- a/bashast/gunit/cond_main.gunit +++ b/bashast/gunit/cond_main.gunit @@ -31,6 +31,7 @@ condition_expr: "[ a == b ]" -> (BUILTIN_TEST (= (STRING a) (STRING b))) "[ a != b ]" -> (BUILTIN_TEST (NOT_EQUALS (STRING a) (STRING b))) "[[ \"${DISTUTILS_SRC_TEST}\" =~ ^(setup\.py|nosetests|py\.test|trial(\ .*)?)$ ]]" -> (KEYWORD_TEST (MATCH_REGULAR_EXPRESSION (STRING (DOUBLE_QUOTED_STRING (VAR_REF DISTUTILS_SRC_TEST))) (STRING ^ ( setup \ . py | nosetests | py \ . test | trial ( \ . * ) ? ) $))) +"[[ a =~ \" \"bcd ]]" -> (KEYWORD_TEST (MATCH_REGULAR_EXPRESSION (STRING a) (STRING ESCAPED_CHAR bcd))) "[ -n \"$FROM_LANG\" -a -n \"$TO_LANG\" ]" -> (BUILTIN_TEST (BUILTIN_LOGIC_AND (n (STRING (DOUBLE_QUOTED_STRING (VAR_REF FROM_LANG)))) (n (STRING (DOUBLE_QUOTED_STRING (VAR_REF TO_LANG)))))) "[ -n \"$FROM_LANG\" -o -n \"$TO_LANG\" ]" -> (BUILTIN_TEST (BUILTIN_LOGIC_OR (n (STRING (DOUBLE_QUOTED_STRING (VAR_REF FROM_LANG)))) (n (STRING (DOUBLE_QUOTED_STRING (VAR_REF TO_LANG)))))) "[ -n \"a\" -o -n \"a\" -a -n \"a\" ]" -> (BUILTIN_TEST (BUILTIN_LOGIC_OR (n (STRING (DOUBLE_QUOTED_STRING a))) (BUILTIN_LOGIC_AND (n (STRING (DOUBLE_QUOTED_STRING a))) (n (STRING (DOUBLE_QUOTED_STRING a)))))) diff --git a/bashast/libbashWalker.g b/bashast/libbashWalker.g index d45d9c3..f57f403 100644 --- a/bashast/libbashWalker.g +++ b/bashast/libbashWalker.g @@ -302,6 +302,7 @@ string_part returns[std::string libbash_value, bool quoted, bool is_raw_string] $libbash_value = transformed.str(); $quoted = true; } + |(ESCAPED_CHAR) => ESCAPED_CHAR libbash_string=any_string { $libbash_value = "\\" + libbash_string; } |(libbash_string=any_string { $libbash_value = libbash_string; }); @@ -797,7 +798,7 @@ keyword_condition returns[bool status] } r=keyword_condition) { $status= l && r; } |^(NEGATION l=keyword_condition) { $status = !l; } |^(MATCH_REGULAR_EXPRESSION left_str=string_expr right_str=string_expr) { - bash_ast ast(std::stringstream(right_str.libbash_value), &bash_ast::parser_all_expansions); + bash_ast ast(std::stringstream(right_str.libbash_value), &bash_ast::parser_all_expansions, false); std::string pattern = ast.interpret_with(*walker, &bash_ast::walker_string_expr); boost::xpressive::sregex re = boost::xpressive::sregex::compile(pattern); $status = boost::xpressive::regex_match(left_str.libbash_value, re); diff --git a/scripts/var_expansion.bash b/scripts/var_expansion.bash index 4bdcb3e..97e9587 100644 --- a/scripts/var_expansion.bash +++ b/scripts/var_expansion.bash @@ -135,8 +135,6 @@ root=123 echo "${search_paths/%/${root}}" echo "${search_paths/#/${root}}" -# This regular expression will cause boost::exception_detail::clone_impl -#[[ "${version_components_groups}" =~ ("*".*" "|" *"|^2.*\ (2|\*)|^3.*\ (3|\*)) ]] [[ " ${FUNCNAME[@]:2} " =~ " "(_python_final_sanity_checks|python_execute_function|python_mod_optimize|python_mod_cleanup)" " ]] [[ "$(declare -p PYTHON_SANITY_CHECKS_EXECUTED)" != "declare -- PYTHON_SANITY_CHECKS_EXECUTED="* || " ${FUNCNAME[@]:1} " =~ " "(python_set_active_version|python_pkg_setup)" " && -z "${PYTHON_SKIP_SANITY_CHECKS}" ]] [[ " ${FUNCNAME[@]:1} " =~ " "(python_set_active_version|python_pkg_setup)" " ]] @@ -146,3 +144,4 @@ PYTHON_DEPEND="2:2.6" version_components_group_regex="(2|3|\*)(:([[:digit:]]+\.[[:digit:]]+)?(:([[:digit:]]+\.[[:digit:]]+)?)?)?" version_components_groups="${PYTHON_DEPEND}" [[ "${version_components_groups}" =~ ^((\!)?[[:alnum:]_-]+\?\ )?${version_components_group_regex}(\ ${version_components_group_regex})?$ ]] && echo true +[[ "${version_components_groups}" =~ ("*".*" "|" *"|^2.*\ (2|\*)|^3.*\ (3|\*)) ]] && echo true diff --git a/src/core/bash_ast.cpp b/src/core/bash_ast.cpp index 5cca4f4..23571ef 100644 --- a/src/core/bash_ast.cpp +++ b/src/core/bash_ast.cpp @@ -36,31 +36,34 @@ #include "libbashParser.h" #include "libbashWalker.h" -void bash_ast::read_script(const std::istream& source) +void bash_ast::read_script(const std::istream& source, bool trim) { std::stringstream stream; stream << source.rdbuf(); script = stream.str(); boost::algorithm::erase_all(script, "\\\n"); - boost::trim_if(script, boost::is_any_of(" \t\n")); + if(trim) + boost::trim_if(script, boost::is_any_of(" \t\n")); } bash_ast::bash_ast(const std::istream& source, - std::function p): parse(p) + std::function p, + bool trim): parse(p) { - read_script(source); + read_script(source, trim); init_parser("unknown source"); } bash_ast::bash_ast(const std::string& script_path, - std::function p): parse(p) + std::function p, + bool trim): parse(p) { std::stringstream stream; std::ifstream file_stream(script_path); if(!file_stream) throw libbash::parse_exception(script_path + " can't be read"); - read_script(file_stream); + read_script(file_stream, trim); init_parser(script_path); } diff --git a/src/core/bash_ast.h b/src/core/bash_ast.h index 50ca7a6..073553c 100644 --- a/src/core/bash_ast.h +++ b/src/core/bash_ast.h @@ -67,7 +67,7 @@ class bash_ast: public boost::noncopyable typedef std::unique_ptr> walker_pointer; - void read_script(const std::istream& source); + void read_script(const std::istream& source, bool trim); void init_parser(const std::string& script_path); walker_pointer create_walker(interpreter& walker, antlr_pointer& nodes); @@ -77,13 +77,13 @@ public: /// \param source input source /// \param p the parser rule for building the AST bash_ast(const std::istream& source, - std::function p=parser_start); + std::function p=parser_start, bool trim=true); /// \brief build AST from string /// \param script_path input source /// \param p the parser rule for building the AST bash_ast(const std::string& script_path, - std::function p=parser_start); + std::function p=parser_start, bool trim=true); /// \brief the functor for walker start rule /// \param tree_parser the pointer to the tree_parser -- cgit v1.2.3-18-g5258