aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKaren Arutyunov <karen@codesynthesis.com>2024-12-30 23:34:08 +0200
committerKaren Arutyunov <karen@codesynthesis.com>2025-01-01 21:13:37 +0200
commit4dc301a8cbd17b053ff86d141c8ee8daaaa866a3 (patch)
treef1be8ebbbbfc105b1124df2cd1d4c9bcc80441f2
parent4a4f6583b00a632977481c0f88b427912d5305a8 (diff)
Fix parser::parse_names() which fails on pattern inclusion groups for some corner cases
Specifically, fix the function for the case when the pattern inclusion group is specified first in the pattern group in a directory. For example, before the fix, compiling the following buildfile: fs = hello exe{hello}: foo/{hxx ixx txx cxx}{+{$fs}} would fail with the following error: invalid 'foo/hello' in name pattern
-rw-r--r--libbuild2/parser.cxx41
-rw-r--r--tests/name/pattern.testscript12
2 files changed, 47 insertions, 6 deletions
diff --git a/libbuild2/parser.cxx b/libbuild2/parser.cxx
index 53f808c..c3f349c 100644
--- a/libbuild2/parser.cxx
+++ b/libbuild2/parser.cxx
@@ -7569,7 +7569,10 @@ namespace build2
// and look for some wildcards since the pattern can be the result of an
// expansion (or, worse, concatenation). Thus pattern_mode::detect: we
// are going to ask parse_names() to detect for us if the first name is
- // a pattern. And if it is, to refrain from adding pair/dir/type.
+ // a pattern. And if it is, to refrain from adding pair/dir/type (note:
+ // for the pattern inclusions and exclusions the name's type member will
+ // be set to "+" and "-", respectively, and will later be cleared by
+ // expand_name_pattern()).
//
optional<const target_type*> pat_tt (
parse_names (
@@ -8313,16 +8316,42 @@ namespace build2
fail (loc) << "invalid path '" << e.path << "'";
}
- count = parse_names_trailer (
- t, tt, ns, pmode, what, separators, pairn, *pp1, dp1, tp1, cross);
+ // Note that for a pattern inclusion group (see above) we make sure
+ // that the resulting patterns are simple names, passing NULL as the
+ // directory path (the names' type members will still be set to "+"
+ // thought; see the parse_names_trailer::parse() lambda
+ // implementation for details).
+ //
+ assert (!pinc || (tp1 != nullptr && *tp1 == "+"));
- // If empty group or empty name, then this is not a pattern inclusion
- // group (see above).
+ count = parse_names_trailer (
+ t, tt,
+ ns,
+ pmode,
+ what,
+ separators, pairn,
+ *pp1, (!pinc ? dp1 : nullptr), tp1,
+ cross);
+
+ // If empty group, then this is not a pattern inclusion group.
//
if (pinc)
{
- if (count != 0 && (count > 1 || !ns.back ().empty ()))
+ if (count != 0)
+ {
+ // Note that we can never end up with the empty name here. For
+ // example, for the below constructs the above
+ // parse_names_trailer() call would fail with the `typed empty
+ // name` error, since the empty name's type will be set to "+"
+ // (see above for details):
+ //
+ // foo/{hxx cxx}{+{}}
+ // foo/{+{}}
+ //
+ assert (count > 1 || !ns.back ().empty ());
+
pattern_detected (ttp);
+ }
ppat = pinc = false;
}
diff --git a/tests/name/pattern.testscript b/tests/name/pattern.testscript
index c1a4ce4..efd15b2 100644
--- a/tests/name/pattern.testscript
+++ b/tests/name/pattern.testscript
@@ -153,6 +153,9 @@ EOI
mkdir bar;
$* <'print {f*/ +{b*/}}' >/'bar/' : include-group
+ mkdir -p foo/bar;
+ $* <'print $path.canonicalize(foo/{+{b*/}})' >/'foo/bar/' : include-group-first
+
touch foo.txt fox.txt;
$* <'print {*.txt -f*.txt +*x.txt}' >'fox.txt' : include-exclude-order
@@ -309,6 +312,15 @@ EOI
print {+{$pats}}
EOI
+ : pattern-via-expansion-list-subdir
+ :
+ mkdir baz;
+ touch baz/foo.txt baz/bar.hxx;
+ $* <<EOI >'baz/bar.hxx baz/foo.txt'
+ pats = '*.hxx' '*.txt'
+ print baz/{+{$pats}}
+ EOI
+
: pattern-via-expansion-type
:
touch foo.txt;