aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2021-05-03 11:17:14 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2021-05-03 11:17:14 +0200
commit8bae6cd94035cd5999ff2d767d91e176939ba203 (patch)
tree2c92af9548d5be75cc349aa61dbfd7085f227684
parentd55690a09ccc86b6ec285c9af2ab4f1921e84baf (diff)
Allow unseparated scope-qualified variable assignment and expansion
-rw-r--r--NEWS18
-rw-r--r--libbuild2/parser.cxx47
2 files changed, 59 insertions, 6 deletions
diff --git a/NEWS b/NEWS
index 5999e49..2f64076 100644
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,21 @@
+Version 0.14.0
+
+ * Allow unseparated scope-qualified variable assignment and expansion.
+
+ For example, now the following:
+
+ foo/x = y
+ info $(foo/x)
+
+ Is equivalent to:
+
+ foo/ x = y
+ info $(foo/ x)
+
+ While this makes scope-qualified syntax consistent with target-qualified,
+ it also means that variable names that contain directory separators are
+ now effectively reserved.
+
Version 0.13.0
* Support for project-specific configuration.
diff --git a/libbuild2/parser.cxx b/libbuild2/parser.cxx
index 3b20a65..b6d348e 100644
--- a/libbuild2/parser.cxx
+++ b/libbuild2/parser.cxx
@@ -891,6 +891,7 @@ namespace build2
//
// x = y
// foo/ x = y (ns will have two elements)
+ // foo/x = y (ns will have one element)
//
// And in the future we may also want to support:
//
@@ -915,13 +916,27 @@ namespace build2
// let parse_variable_name() complain.
//
dir_path d;
- if (ns.size () == 2 && ns[0].directory ())
+ size_t p;
+ if ((ns.size () == 2 && ns[0].directory ()) ||
+ (ns.size () == 1 && ns[0].simple () &&
+ (p = path_traits::rfind_separator (ns[0].value)) != string::npos))
{
if (at.first)
fail (at.second) << "attributes before scope directory";
- d = move (ns[0].dir);
- ns.erase (ns.begin ());
+ if (ns.size () == 2)
+ {
+ d = move (ns[0].dir);
+ ns.erase (ns.begin ());
+ }
+ else
+ {
+ // Note that p cannot point to the last character since then it
+ // would have been a directory, not a simple name.
+ //
+ d = dir_path (ns[0].value, 0, p + 1);
+ ns[0].value.erase (0, p + 1);
+ }
// Make sure it's not a pattern (see also the target case above and
// scope below).
@@ -6007,7 +6022,9 @@ namespace build2
// faster.
//
char c;
- if ((tt == type::word || (c = special (t))) &&
+ if ((tt == type::word
+ ? path_traits::rfind_separator (t.value) == string::npos
+ : (c = special (t))) &&
peek () == type::rparen)
{
name = (tt == type::word ? move (t.value) : string (1, c));
@@ -6015,6 +6032,8 @@ namespace build2
}
else
{
+ using name_type = build2::name;
+
//@@ OUT will parse @-pair and do well?
//
values vs (parse_eval (t, tt, pmode));
@@ -6030,7 +6049,7 @@ namespace build2
fail (loc) << "null variable/function name";
names storage;
- vector_view<build2::name> ns (reverse (v, storage)); // Movable.
+ vector_view<name_type> ns (reverse (v, storage)); // Movable.
size_t n (ns.size ());
// We cannot handle scope-qualification in the eval context as
@@ -6060,7 +6079,23 @@ namespace build2
fail (loc) << "expected variable/function name instead of '"
<< ns[n - 1] << "'";
- name = move (ns[n - 1].value);
+ size_t p;
+ if (n == 1 && // $(foo/x)
+ (p = path_traits::rfind_separator (ns[0].value)) !=
+ string::npos)
+ {
+ // Note that p cannot point to the last character since then
+ // it would have been a directory, not a simple name.
+ //
+ string& s (ns[0].value);
+
+ name = string (s, p + 1);
+ s.resize (p + 1);
+ qual = name_type (dir_path (move (s)));
+ qual.pair = '/';
+ }
+ else
+ name = move (ns[n - 1].value);
}
}
}