aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2022-06-28 09:50:05 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2022-06-28 11:11:55 +0200
commit17af650e17fafd4d3fa2bf0e06253e15f4e5b9c3 (patch)
tree278a64a0e34d454f5fa66f43ed3cea24e84f8ce5
parent664fc2807b6e97400c6e76aaad66a51ff0c57704 (diff)
Add support for querying out-qualified target-specific variables
-rw-r--r--libbuild2/build/script/parser.cxx2
-rw-r--r--libbuild2/build/script/parser.hxx2
-rw-r--r--libbuild2/parser.cxx81
-rw-r--r--libbuild2/parser.hxx10
-rw-r--r--libbuild2/prerequisite.hxx4
-rw-r--r--libbuild2/test/script/parser.cxx2
-rw-r--r--libbuild2/test/script/parser.hxx2
-rw-r--r--tests/eval/qual.testscript5
-rw-r--r--tests/variable/target-specific/testscript14
9 files changed, 79 insertions, 43 deletions
diff --git a/libbuild2/build/script/parser.cxx b/libbuild2/build/script/parser.cxx
index 795dc72..a27ec41 100644
--- a/libbuild2/build/script/parser.cxx
+++ b/libbuild2/build/script/parser.cxx
@@ -2271,7 +2271,7 @@ namespace build2
}
lookup parser::
- lookup_variable (name&& qual, string&& name, const location& loc)
+ lookup_variable (names&& qual, string&& name, const location& loc)
{
// In the pre-parse mode collect the referenced variable names for the
// script semantics change tracking.
diff --git a/libbuild2/build/script/parser.hxx b/libbuild2/build/script/parser.hxx
index 362c834..1a6c39d 100644
--- a/libbuild2/build/script/parser.hxx
+++ b/libbuild2/build/script/parser.hxx
@@ -229,7 +229,7 @@ namespace build2
//
protected:
virtual lookup
- lookup_variable (name&&, string&&, const location&) override;
+ lookup_variable (names&&, string&&, const location&) override;
virtual void
lookup_function (string&&, const location&) override;
diff --git a/libbuild2/parser.cxx b/libbuild2/parser.cxx
index 4c6cde0..8343112 100644
--- a/libbuild2/parser.cxx
+++ b/libbuild2/parser.cxx
@@ -5260,17 +5260,38 @@ namespace build2
if (pre_parse_)
return v; // Empty.
- if (v.type != nullptr || !v || v.as<names> ().size () != 1)
- fail (l) << "expected target before ':'";
-
+ // We used to return this as a <target>:<name> pair but that meant we
+ // could not handle an out-qualified target (which is represented as
+ // <target>@<out> pair). As a somewhat of a hack, we deal with this by
+ // changing the order of the name and target to be <name>:<target> with
+ // the qualified case becoming a "tripple pair" <name>:<target>@<out>.
+ //
+ // @@ This is actually not great since it's possible to observe such a
+ // tripple pair, for example with `print (file{x}@./:y)`.
+ //
if (n.type != nullptr || !n || n.as<names> ().size () != 1 ||
n.as<names> ()[0].pattern)
fail (nl) << "expected variable name after ':'";
- names& ns (v.as<names> ());
+ names& ns (n.as<names> ());
ns.back ().pair = ':';
- ns.push_back (move (n.as<names> ().back ()));
- return v;
+
+ if (v.type == nullptr && v)
+ {
+ names& ts (v.as<names> ());
+
+ size_t s (ts.size ());
+ if (s == 1 || (s == 2 && ts.front ().pair == '@'))
+ {
+ ns.push_back (move (ts.front ()));
+ if (s == 2)
+ ns.push_back (move (ts.back ()));
+
+ return n;
+ }
+ }
+
+ fail (l) << "expected target before ':'" << endf;
}
else
{
@@ -7004,7 +7025,7 @@ namespace build2
next (t, tt);
loc = get_location (t);
- name qual;
+ names qual;
string name;
if (t.separated)
@@ -7036,8 +7057,6 @@ namespace build2
{
using name_type = build2::name;
- //@@ OUT will parse @-pair and do well?
- //
values vs (parse_eval (t, tt, pmode));
if (!pre_parse_)
@@ -7059,17 +7078,26 @@ namespace build2
// we would be treating all paths as qualified variables. So
// we have to do it here.
//
- if (n == 2 && ns[0].pair == ':') // $(foo: x)
+ if (n >= 2 && ns[0].pair == ':') // $(foo: x)
{
- qual = move (ns[0]);
+ // Note: name is first (see eval for details).
+ //
+ qual.push_back (move (ns[1]));
- if (qual.empty ())
+ if (qual.back ().empty ())
fail (loc) << "empty variable/function qualification";
+
+ if (n > 2)
+ qual.push_back (move (ns[2]));
+
+ // Move name to the last position (see below).
+ //
+ swap (ns[0], ns[n - 1]);
}
else if (n == 2 && ns[0].directory ()) // $(foo/ x)
{
- qual = move (ns[0]);
- qual.pair = '/';
+ qual.push_back (move (ns[0]));
+ qual.back ().pair = '/';
}
else if (n > 1)
fail (loc) << "expected variable/function name instead of '"
@@ -7093,8 +7121,8 @@ namespace build2
name = string (s, p + 1);
s.resize (p + 1);
- qual = name_type (dir_path (move (s)));
- qual.pair = '/';
+ qual.push_back (name_type (dir_path (move (s))));
+ qual.back ().pair = '/';
}
else
name = move (ns[n - 1].value);
@@ -7903,7 +7931,7 @@ namespace build2
}
lookup parser::
- lookup_variable (name&& qual, string&& name, const location& loc)
+ lookup_variable (names&& qual, string&& name, const location& loc)
{
if (pre_parse_)
return lookup ();
@@ -7927,27 +7955,26 @@ namespace build2
}
else
{
- switch (qual.pair)
+ switch (qual.front ().pair)
{
case '/':
{
- assert (qual.directory ());
- sg = enter_scope (*this, move (qual.dir));
+ assert (qual.front ().directory ());
+ sg = enter_scope (*this, move (qual.front ().dir));
s = scope_;
break;
}
- case ':':
+ default:
{
- qual.pair = '\0';
+ build2::name n (move (qual.front ())), o;
- // @@ OUT TODO
- //
- tg = enter_target (
- *this, move (qual), build2::name (), true, loc, trace);
+ if (n.pair)
+ o = move (qual.back ());
+
+ tg = enter_target (*this, move (n), move (o), true, loc, trace);
t = target_;
break;
}
- default: assert (false);
}
}
diff --git a/libbuild2/parser.hxx b/libbuild2/parser.hxx
index 9e9f926..f806568 100644
--- a/libbuild2/parser.hxx
+++ b/libbuild2/parser.hxx
@@ -560,8 +560,12 @@ namespace build2
// Customization hooks.
//
protected:
- // If qual is not empty, then its pair member should indicate the kind
- // of qualification: ':' -- target, '/' -- scope.
+ // If qual is not empty, then firt element's pair member indicates the
+ // kind of qualification:
+ //
+ // '\0' -- target
+ // '@' -- out-qualified target
+ // '/' -- scope
//
// Note that this function is called even during pre-parse with the result
// unused. In this case a valid name will only be provided for variables
@@ -574,7 +578,7 @@ namespace build2
// if/when extending this and audit all the existing use-cases.
//
virtual lookup
- lookup_variable (name&& qual, string&& name, const location&);
+ lookup_variable (names&& qual, string&& name, const location&);
// This function is only called during pre-parse and is the continuation
// of the similar logic in lookup_variable() above (including the fact
diff --git a/libbuild2/prerequisite.hxx b/libbuild2/prerequisite.hxx
index 476ed9d..3b64eae 100644
--- a/libbuild2/prerequisite.hxx
+++ b/libbuild2/prerequisite.hxx
@@ -29,7 +29,9 @@ namespace build2
using target_type_type = build2::target_type;
// Note that unlike targets, for prerequisites an empty out directory
- // means undetermined rather than being definitely in the out tree.
+ // means undetermined rather than being definitely in the out tree (but
+ // maybe we should make this explicit via optional<>; see the from-target
+ // constructor).
//
// It might seem natural to keep the reference to the owner target instead
// of to the scope. But that's not the semantics that we have, consider:
diff --git a/libbuild2/test/script/parser.cxx b/libbuild2/test/script/parser.cxx
index 2cc1b65..eb7b140 100644
--- a/libbuild2/test/script/parser.cxx
+++ b/libbuild2/test/script/parser.cxx
@@ -1661,7 +1661,7 @@ namespace build2
}
lookup parser::
- lookup_variable (name&& qual, string&& name, const location& loc)
+ lookup_variable (names&& qual, string&& name, const location& loc)
{
if (pre_parse_)
return lookup ();
diff --git a/libbuild2/test/script/parser.hxx b/libbuild2/test/script/parser.hxx
index c63bce6..66160d9 100644
--- a/libbuild2/test/script/parser.hxx
+++ b/libbuild2/test/script/parser.hxx
@@ -117,7 +117,7 @@ namespace build2
//
protected:
virtual lookup
- lookup_variable (name&&, string&&, const location&) override;
+ lookup_variable (names&&, string&&, const location&) override;
// Insert id into the id map checking for duplicates.
//
diff --git a/tests/eval/qual.testscript b/tests/eval/qual.testscript
index 29f6340..88339fd 100644
--- a/tests/eval/qual.testscript
+++ b/tests/eval/qual.testscript
@@ -5,8 +5,9 @@
.include ../common.testscript
-$* <'print (file{foo}: bar)' >'file{foo}:bar' : target
-$* <'print (foo/dir{}: bar)' >'dir{foo/}:bar' : scope
+$* <'print (file{foo}: bar)' >'bar:file{foo}' : target
+$* <'print (file{foo}@./: bar)' >'bar:file{foo}@./' : target-out
+$* <'print (foo/dir{}: bar)' >'bar:dir{foo/}' : target-dir
: attribute
:
diff --git a/tests/variable/target-specific/testscript b/tests/variable/target-specific/testscript
index 627d8ab..c52712b 100644
--- a/tests/variable/target-specific/testscript
+++ b/tests/variable/target-specific/testscript
@@ -65,13 +65,15 @@ print (foo: bar)
print (foo : bar)
print (foo/: bar)
print (foo/file{fox}: bar)
+print (file{fox}@./: bar)
EOI
-foo:bar
-foo:bar
-foo:bar
-foo:bar
-foo/:bar
-foo/file{fox}:bar
+bar:foo
+bar:foo
+bar:foo
+bar:foo
+bar:foo/
+bar:foo/file{fox}
+bar:file{fox}@./
EOO
: eval-qual-name-expected