From 8150086c0ef168f48193ddc03b8c75e96e96d581 Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Thu, 9 Aug 2018 12:47:27 +0200 Subject: Add support for name patterns without wildcard characters In particular, this allows the "if-exists" specification of prerequisites, for example: for t: $tests exe{$t}: cxx{$t} test{+$t} --- build2/parser.cxx | 33 +++++++++++++++++---------------- build2/parser.hxx | 3 ++- doc/manual.cli | 20 +++++++++++--------- tests/name/pattern.test | 7 +++++-- 4 files changed, 35 insertions(+), 28 deletions(-) diff --git a/build2/parser.cxx b/build2/parser.cxx index caf970e..ceae594 100644 --- a/build2/parser.cxx +++ b/build2/parser.cxx @@ -3153,11 +3153,6 @@ namespace build2 << " pattern"; } - // Figure out if this is a pattern. - // - bool p (v.find_first_of ("*?") != string::npos); - assert (p || !first); // First must be a pattern. - // Factor non-empty extension back into the name for searching. // // Note that doing it at this stage means we don't support extension @@ -3172,15 +3167,10 @@ namespace build2 try { if (s == '+') - { - if (p) - include_pattern (move (v), move (e), a); - else - include_match (move (v), move (e), a); - } + include_pattern (move (v), move (e), a); else { - if (p) + if (v.find_first_of ("*?") != string::npos) exclude_pattern (move (v)); else exclude_match (move (v)); @@ -3300,11 +3290,13 @@ namespace build2 t, tt, r, pmode == pattern_mode::expand ? pattern_mode::detect : pmode, - false, + false /* chunk */, what, separators, 0, // Handled by the splice_names() call below. - pp, dp, tp, false).pattern); + pp, dp, tp, + false /* cross */, + true /* curly */).pattern); if (tt != type::rcbrace) fail (t) << "expected '}' instead of " << t; @@ -3420,7 +3412,8 @@ namespace build2 const optional& pp, const dir_path* dp, const string* tp, - bool cross) -> parse_names_result + bool cross, + bool curly) -> parse_names_result { // Note that support for pre-parsing is partial, it does not handle // groups ({}). @@ -3906,11 +3899,15 @@ namespace build2 // See if this is a wildcard pattern. // + // It should either contain a wildcard character or, in a curly + // context, start with unquoted '+'. + // if (pmode != pattern_mode::ignore && !*pp1 && // Cannot be project-qualified. t.qtype == quote_type::unquoted && // Cannot be quoted. ((dp != nullptr && dp->absolute ()) || pbase_ != nullptr) && - val.find_first_of ("*?") != string::npos) + ((val.find_first_of ("*?") != string::npos) || + (curly && val[0] == '+'))) { // Resolve the target if there is one. If we fail, then this is not // a pattern. @@ -4482,6 +4479,10 @@ namespace build2 pair p (lexer_->peek_char ()); char c (p.first); + // @@ Just checking for leading '+' is not sufficient, for example: + // + // print +foo + // return c == '\n' || c == '\0' || c == '(' || (p.second && c != '=' && c != '+'); } diff --git a/build2/parser.hxx b/build2/parser.hxx index acd0845..dfb4c6b 100644 --- a/build2/parser.hxx +++ b/build2/parser.hxx @@ -310,7 +310,8 @@ namespace build2 const optional& prj = nullopt, const dir_path* dir = nullptr, const string* type = nullptr, - bool cross = true); + bool cross = true, + bool curly = false); size_t parse_names_trailer (token&, token_type&, diff --git a/doc/manual.cli b/doc/manual.cli index eafe14d..713cd63 100644 --- a/doc/manual.cli +++ b/doc/manual.cli @@ -76,24 +76,26 @@ inclusion or exclusion if it starts with a literal, unquoted plus (\c{+}) or minus (\c{-}) sign, respectively. In this case the remaining group values, if any, must all be inclusions or exclusions. If the second value doesn't start with a plus or minus, then all the group values are considered independent -with leading pluses and minuses not having any special meaning. For -regularity, the first pattern can also start with the plus sign. For example: +with leading pluses and minuses not having any special meaning. For regularity +as well as to allow patterns without wildcards, the first pattern can also +start with the plus sign. For example: \ -exe{hello}: cxx{f* -foo} # Exclude foo if present. -exe{hello}: cxx{f* +foo} # Include foo if not present. -exe{hello}: cxx{f* -fo?} # Exclude foo and fox if present. -exe{hello}: cxx{f* +b* -foo -bar} # Exclude foo and bar if present. +exe{hello}: cxx{f* -foo} # Exclude foo if exists. +exe{hello}: cxx{f* +bar} # Include bar if exists. +exe{hello}: cxx{f* -fo?} # Exclude foo and fox if exist. +exe{hello}: cxx{f* +b* -foo -bar} # Exclude foo and bar if exist. exe{hello}: cxx{+f* +b* -foo -bar} # Same as above. +exe{hello}: cxx{+foo} # Pattern without wildcards. exe{hello}: cxx{f* b* -z*} # Names matching three patterns. \ Inclusions and exclusions are applied in the order specified and only to the result produced up to that point. The order of names in the result is -unspecified. However, it is guaranteed not to contain duplicates. The +unspecified. However, it is guaranteed not to contain duplicates. The first pattern and the following inclusions/exclusions must be consistent with -regards to the type of filesystem entry they match. That is, they should -all match either files or directories. For example: +regards to the type of filesystem entry they match. That is, they should all +match either files or directories. For example: \ exe{hello}: cxx{f* -foo +*oo} # Exclusion has no effect. diff --git a/tests/name/pattern.test b/tests/name/pattern.test index fad8478..8d8840c 100644 --- a/tests/name/pattern.test +++ b/tests/name/pattern.test @@ -107,7 +107,7 @@ EOI $* <'print d*/*.txt' >/'dir/foo.txt' : multi-pattern touch foo.txt bar.txt; - $* <'print {*.txt -bar.txt}' >'foo.txt' : exclude-match + $* <'print {*.txt -bar.txt}' >'foo.txt' : exclude-non-pattern mkdir baz; touch foo.txt bar.txt baz/fox.txt baz/box.txt; @@ -117,7 +117,7 @@ EOI $* <'print {*.txt -{*z.txt bar.txt}}' >'foo.txt' : exclude-group touch bar.txt; - $* <'print {f*.txt +bar.txt}' >'bar.txt' : include-match + $* <'print {f*.txt +bar.txt}' >'bar.txt' : include-non-wildcard touch bar.txt; $* <'print {f*.txt +b*.txt}' >'bar.txt' : include-pattern @@ -127,6 +127,9 @@ EOI touch foo.txt fox.txt; $* <'print {*.txt -f*.txt +*x.txt}' >'fox.txt' : include-exclude-order + + touch foo.txt; + $* <'print {+foo.txt} {+bar.txt}' >'foo.txt' : non-wildcard } : target-type -- cgit v1.1