From 47751abc43dab40e0ac4a1523994fd533e6a3b22 Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Fri, 16 Jan 2015 15:32:00 +0200 Subject: Add support for directory prefixes For example: cxx{driver ../{foo bar}} cxx{driver} ../cxx{foo bar} --- build/parser | 10 ++++--- build/parser.cxx | 68 +++++++++++++++++++++++++++++++++---------- build/path | 6 ++++ tests/build/parser/buildfile | 2 ++ tests/build/parser/driver.cxx | 6 ++++ 5 files changed, 73 insertions(+), 19 deletions(-) create mode 100644 tests/build/parser/buildfile diff --git a/build/parser b/build/parser index e8e7314..66c0357 100644 --- a/build/parser +++ b/build/parser @@ -39,10 +39,11 @@ namespace build private: struct name_type { - name_type (std::string t, std::string n) - : type (std::move (t)), name (std::move (n)) {} + name_type (std::string t, path d, std::string n) + : type (std::move (t)), dir (std::move (d)), name (std::move (n)) {} std::string type; // Empty if untyped. + path dir; std::string name; }; @@ -55,12 +56,13 @@ namespace build parse_names (token& t, token_type& tt) { names ns; - parse_names (t, tt, ns, nullptr); + parse_names (t, tt, ns, nullptr, nullptr); return ns; } void - parse_names (token&, token_type&, names&, const std::string* type); + parse_names (token&, token_type&, names&, + const path* dir, const std::string* type); // Utilities. // diff --git a/build/parser.cxx b/build/parser.cxx index 1927ebf..ccb41b4 100644 --- a/build/parser.cxx +++ b/build/parser.cxx @@ -101,7 +101,7 @@ namespace build // the name part is a valid filesystem name so we will have // to do the splitting manually. // - path d; + path d (pn.dir); string n; const string* e (nullptr); @@ -112,11 +112,12 @@ namespace build n = move (pn.name); // NOTE: steal! else { - d = path (pn.name, i); + d /= path (pn.name, i); n.assign (pn.name, i + 1, string::npos); - d.normalize (); } + d.normalize (); + // Extract extension. // string::size_type j (n.rfind ('.')); @@ -139,7 +140,7 @@ namespace build for (auto& tn: tns) { - path d; + path d (tn.dir); string n; const string* e (nullptr); @@ -149,15 +150,17 @@ namespace build path::size_type i (path::traits::rfind_separator (tn.name)); if (i == string::npos) - { - d = scope_->path (); // Already normalized. n = move (tn.name); // NOTE: steal! - } else { - d = path (tn.name, i); + d /= path (tn.name, i); n.assign (tn.name, i + 1, string::npos); + } + if (d.empty ()) + d = scope_->path (); // Already normalized. + else + { if (d.relative ()) d = scope_->path () / d; @@ -305,16 +308,16 @@ namespace build } void parser:: - parse_names (token& t, type& tt, names& ns, const string* tp) + parse_names (token& t, type& tt, names& ns, const path* dp, const string* tp) { for (bool first (true);; first = false) { - // Untyped name group, e.g., '{foo bar}'. + // Untyped name group without a directory prefix, e.g., '{foo bar}'. // if (tt == type::lcbrace) { next (t, tt); - parse_names (t, tt, ns, tp); + parse_names (t, tt, ns, dp, tp); if (tt != type::rcbrace) { @@ -332,18 +335,51 @@ namespace build { string name (t.name ()); //@@ move? - // See if this is a type name, that is, it is followed by '{'. + // See if this is a type name, directory prefix, or both. That is, + // it is followed by '{'. // if (next (t, tt) == type::lcbrace) { - if (tp != nullptr) + string::size_type p (name.rfind ('/')), n (name.size () - 1); + + if (p != n && tp != nullptr) { error (t) << "nested type name '" << name << "'" << endl; throw parser_error (); } + path d1; + const path* dp1 (dp); + + string t1; + const string* tp1 (tp); + + if (p == string::npos) // type + tp1 = &name; + else if (p == n) // directory + { + if (dp == nullptr) + d1 = path (name); + else + d1 = *dp / path (name); + + dp1 = &d1; + } + else // both + { + t1.assign (name, p + 1, n - p); + + if (dp == nullptr) + d1 = path (name, 0, p + 1); + else + d1 = *dp / path (name, 0, p + 1); + + dp1 = &d1; + tp1 = &t1; + } + next (t, tt); - parse_names (t, tt, ns, &name); + parse_names (t, tt, ns, dp1, tp1); if (tt != type::rcbrace) { @@ -355,7 +391,9 @@ namespace build continue; } - ns.emplace_back ((tp != nullptr ? *tp : string ()), move (name)); + ns.emplace_back ((tp != nullptr ? *tp : string ()), + (dp != nullptr ? *dp : path ()), + move (name)); continue; } diff --git a/build/path b/build/path index 49d543c..ee7937b 100644 --- a/build/path +++ b/build/path @@ -181,6 +181,12 @@ namespace build init (); } + basic_path (const string_type& s, size_type p, size_type n) + : path_ (s, p, n) + { + init (); + } + void swap (basic_path& p) { diff --git a/tests/build/parser/buildfile b/tests/build/parser/buildfile new file mode 100644 index 0000000..2672a02 --- /dev/null +++ b/tests/build/parser/buildfile @@ -0,0 +1,2 @@ +exe{driver}: cxx{driver ../../../build/{lexer parser scope target native \ + prerequisite context diagnostics trace utility path timestamp}} diff --git a/tests/build/parser/driver.cxx b/tests/build/parser/driver.cxx index a8c8fc9..8e4a60b 100644 --- a/tests/build/parser/driver.cxx +++ b/tests/build/parser/driver.cxx @@ -54,6 +54,12 @@ main () assert (!parse ("foo: bar:")); assert (!parse ("exe{foo:")); + // Directory prefix. + // + assert (parse ("../{foo}: ../{bar}")); + assert (parse ("../exe{foo}: ../obj{bar}")); + assert (!parse ("../exe{exe{foo}}:")); + // Directory scope. // assert (parse ("test/:\n{\n}")); -- cgit v1.1