diff options
-rw-r--r-- | build2/name | 19 | ||||
-rw-r--r-- | build2/parser.cxx | 2 | ||||
-rw-r--r-- | build2/variable | 15 | ||||
-rw-r--r-- | build2/variable.cxx | 74 | ||||
-rw-r--r-- | build2/variable.ixx | 9 | ||||
-rw-r--r-- | build2/variable.txx | 27 | ||||
-rw-r--r-- | tests/variable/representation/buildfile | 8 | ||||
-rw-r--r-- | tests/variable/representation/test.out | 8 |
8 files changed, 116 insertions, 46 deletions
diff --git a/build2/name b/build2/name index 99c21f4..a4de95c 100644 --- a/build2/name +++ b/build2/name @@ -68,19 +68,24 @@ namespace build2 bool empty () const {return dir.empty () && value.empty ();} - // Note that strictly speaking the following tests should be - // orthogonal to qualification. However, the vast majority of - // cases where we expect a simple or directory name, we also - // expect it to be unqualified. + // Note that strictly speaking the following tests should be orthogonal + // to qualification. However, the vast majority of cases where we expect + // a simple or directory name, we also expect it to be unqualified. // // Note also that empty name is simple but not a directory. // bool - simple () const {return unqualified () && untyped () && dir.empty ();} + simple (bool ignore_qual = false) const + { + return (ignore_qual || unqualified ()) && untyped () && dir.empty (); + } bool - directory () const - {return unqualified () && untyped () && !dir.empty () && value.empty ();} + directory (bool ignore_qual = false) const + { + return (ignore_qual || unqualified ()) && + untyped () && !dir.empty () && value.empty (); + } const std::string* proj = nullptr; // Points to project_name_pool. dir_path dir; diff --git a/build2/parser.cxx b/build2/parser.cxx index e1d63aa..ab9012c 100644 --- a/build2/parser.cxx +++ b/build2/parser.cxx @@ -1064,7 +1064,7 @@ namespace build2 // Should evaluate to true or false. // - if (ns.size () != 1 || !value_traits<bool>::assign (ns[0])) + if (ns.size () != 1 || !assign<bool> (ns[0])) fail (nsl) << "expected " << k << "-expression to evaluate to " << "'true' or 'false' instead of '" << ns << "'"; diff --git a/build2/variable b/build2/variable index a2490ac..029aafa 100644 --- a/build2/variable +++ b/build2/variable @@ -214,10 +214,15 @@ namespace build2 template <typename T> typename value_traits<T>::const_type as (const value&); // Try to "assign" a simple value type to the value stored in name. Return - // false if the value is not valid for this type. + // false if the value is not valid for this type. The second version is + // called for a pair and it is expected to merge the result into the first + // name. // template <typename T> bool assign (name&); + template <typename T> bool assign (name&, name&); + // Name cast. Can only be called after assign() above returned true. + // template <typename T> typename value_traits<T>::type as (name&); template <typename T> typename value_traits<T>::const_type as (const name&); @@ -270,7 +275,7 @@ namespace build2 static type as (value&); static const_type as (const value&); - static bool assign (name&); + static bool assign (name&, name*); static void assign (value&, bool); static void append (value&, bool); @@ -293,7 +298,7 @@ namespace build2 static type as (value&); static const_type as (const value&); - static bool assign (name&); + static bool assign (name&, name*); static void assign (value&, string); static void append (value&, string); @@ -316,7 +321,7 @@ namespace build2 static type as (value&); static const_type as (const value&); - static bool assign (name&); + static bool assign (name&, name*); static void assign (value&, dir_path); static void append (value&, dir_path); @@ -339,7 +344,7 @@ namespace build2 static type as (value&); static const_type as (const value&); - static bool assign (name&) {return true;} + static bool assign (name&, name* r) {return r == nullptr;} static void assign (value&, name); static void append (value&, name) = delete; diff --git a/build2/variable.cxx b/build2/variable.cxx index 39d8cdd..ce06d3e 100644 --- a/build2/variable.cxx +++ b/build2/variable.cxx @@ -123,9 +123,9 @@ namespace build2 // bool value // bool value_traits<bool>:: - assign (name& n) + assign (name& n, name* r) { - if (n.simple ()) + if (r == nullptr && n.simple ()) { const string& s (n.value); @@ -145,7 +145,7 @@ namespace build2 { name& n (v.front ()); - if (value_traits<bool>::assign (n)) + if (assign<bool> (n)) return true; } @@ -178,47 +178,64 @@ namespace build2 // string value // bool value_traits<string>:: - assign (name& n) + assign (name& n, name* r) { - // The below code is quite convoluted because we don't want to - // modify the name until we know it good (if it is not, then it - // will most likely be printed by the caller in diagnostics). - - // Suspend project qualification. + // The goal is to reverse the name into its original representation. The + // code is a bit convoluted because we try to avoid extra allocation for + // the common cases (unqualified, unpaired simple name or directory). // - const string* p (n.proj); - n.proj = nullptr; - // Convert directory to string. + // We can only convert project-qualified simple and directory names. // - if (n.directory ()) + if (!(n.simple (true) || n.directory (true)) || + !(r == nullptr || r->simple (true) || r->directory (true))) + return false; + + if (n.directory (true)) { n.value = move (n.dir).string (); // Move string out of path. - // Add / back to the end of the path unless it is already there. - // Note that the string cannot be empty (n.directory () would - // have been false). + // Add / back to the end of the path unless it is already there. Note + // that the string cannot be empty (n.directory () would have been + // false). // if (!dir_path::traits::is_separator (n.value[n.value.size () - 1])) n.value += '/'; } - if (!n.simple ()) - { - n.proj = p; // Restore. - return false; - } - // Convert project qualification to its string representation. // - if (p != nullptr) + if (n.qualified ()) { - string s (*p); + string s (*n.proj); s += '%'; s += n.value; s.swap (n.value); } + // The same for the RHS of a pair, if we have one. + // + if (r != nullptr) + { + n.value += '@'; + + if (r->qualified ()) + { + n.value += *r->proj; + n.value += '%'; + } + + if (r->directory (true)) + { + n.value += r->dir.string (); + + if (!dir_path::traits::is_separator (n.value[n.value.size () - 1])) + n.value += '/'; + } + else + n.value += r->value; + } + return true; } @@ -236,7 +253,7 @@ namespace build2 { name& n (v.front ()); - if (value_traits<string>::assign (n)) + if (assign<string> (n)) return !n.value.empty (); } @@ -271,8 +288,11 @@ namespace build2 // dir_path value // bool value_traits<dir_path>:: - assign (name& n) + assign (name& n, name* r) { + if (r != nullptr) + return false; + if (n.directory ()) return true; @@ -304,7 +324,7 @@ namespace build2 { name& n (v.front ()); - if (value_traits<dir_path>::assign (n)) + if (assign<dir_path> (n)) return !n.dir.empty (); } diff --git a/build2/variable.ixx b/build2/variable.ixx index b368c6e..df3f0c5 100644 --- a/build2/variable.ixx +++ b/build2/variable.ixx @@ -34,7 +34,14 @@ namespace build2 inline bool assign (name& n) { - return value_traits<T>::assign (n); + return value_traits<T>::assign (n, nullptr); + } + + template <typename T> + inline bool + assign (name& l, name& r) + { + return value_traits<T>::assign (l, &r); } template <typename T> diff --git a/build2/variable.txx b/build2/variable.txx index 54e48a3..7a0d53a 100644 --- a/build2/variable.txx +++ b/build2/variable.txx @@ -12,13 +12,30 @@ namespace build2 bool vector_assign (names& v, const variable& var) { - // Verify each element has valid value of T. + // Verify each element has valid value of T. Merge pairs. // - for (name& n: v) + for (auto i (v.begin ()); i != v.end (); ) { - if (!assign<T> (n)) - fail << "invalid " << value_traits<T>::value_type.name << " element " - << "'" << n << "' in variable '" << var.name << "'"; + name& n (*i); + + if (n.pair) + { + name& r (*++i); + + if (!assign<T> (n, r)) + fail << "invalid " << value_traits<T>::value_type.name + << " pair '" << n << "'@'" << r << "'" + << " in variable '" << var.name << "'"; + + i = v.erase (i); + } + else + { + if (!assign<T> (n)) + fail << "invalid " << value_traits<T>::value_type.name + << " element '" << n << "' in variable '" << var.name << "'"; + ++i; + } } return !v.empty (); diff --git a/tests/variable/representation/buildfile b/tests/variable/representation/buildfile index 7a2c3f2..8410c96 100644 --- a/tests/variable/representation/buildfile +++ b/tests/variable/representation/buildfile @@ -10,12 +10,20 @@ val += /// val += //foo/ #val += dir{-L/} +# Note that this is "reversed" when we assign it to test.options +# since that variable is of type strings. +# +val += foo@bar foo/@bar/ foo@ @bar @ "@@" + val += foo%bar val += foo% val += %bar val += foo%{bar} #val += foo%file{x} +val += x%foo@y%bar +val += x%foo/@y%bar/ + using cxx cxx.ext = cxx diff --git a/tests/variable/representation/test.out b/tests/variable/representation/test.out index 04d8528..84e7250 100644 --- a/tests/variable/representation/test.out +++ b/tests/variable/representation/test.out @@ -6,7 +6,15 @@ '//' '///' '//foo/' +'foo@bar' +'foo/@bar/' +'foo@' +'@bar' +'@' +'@@' 'foo%bar' 'foo%' '%bar' 'foo%bar' +'x%foo@y%bar' +'x%foo/@y%bar/' |