From 9d0d078ff297138622cd2f3f1076f5984395e42b Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Sat, 19 Mar 2016 11:34:10 +0200 Subject: Add support for pair representation reversibility --- build2/name | 19 +++++++++----- build2/parser.cxx | 2 +- build2/variable | 15 +++++++---- build2/variable.cxx | 74 ++++++++++++++++++++++++++++++++++------------------- build2/variable.ixx | 9 ++++++- build2/variable.txx | 27 +++++++++++++++---- 6 files changed, 100 insertions(+), 46 deletions(-) (limited to 'build2') 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::assign (ns[0])) + if (ns.size () != 1 || !assign (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 value_traits::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 bool assign (name&); + template bool assign (name&, name&); + // Name cast. Can only be called after assign() above returned true. + // template typename value_traits::type as (name&); template typename value_traits::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:: - 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::assign (n)) + if (assign (n)) return true; } @@ -178,47 +178,64 @@ namespace build2 // string value // bool value_traits:: - 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::assign (n)) + if (assign (n)) return !n.value.empty (); } @@ -271,8 +288,11 @@ namespace build2 // dir_path value // bool value_traits:: - 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::assign (n)) + if (assign (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::assign (n); + return value_traits::assign (n, nullptr); + } + + template + inline bool + assign (name& l, name& r) + { + return value_traits::assign (l, &r); } template 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 (n)) - fail << "invalid " << value_traits::value_type.name << " element " - << "'" << n << "' in variable '" << var.name << "'"; + name& n (*i); + + if (n.pair) + { + name& r (*++i); + + if (!assign (n, r)) + fail << "invalid " << value_traits::value_type.name + << " pair '" << n << "'@'" << r << "'" + << " in variable '" << var.name << "'"; + + i = v.erase (i); + } + else + { + if (!assign (n)) + fail << "invalid " << value_traits::value_type.name + << " element '" << n << "' in variable '" << var.name << "'"; + ++i; + } } return !v.empty (); -- cgit v1.1