diff options
-rw-r--r-- | build/parser | 10 | ||||
-rw-r--r-- | build/parser.cxx | 68 | ||||
-rw-r--r-- | build/path | 6 | ||||
-rw-r--r-- | tests/build/parser/buildfile | 2 | ||||
-rw-r--r-- | tests/build/parser/driver.cxx | 6 |
5 files changed, 73 insertions, 19 deletions
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; } @@ -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}")); |