aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2015-01-16 15:32:00 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2015-01-16 15:32:00 +0200
commit47751abc43dab40e0ac4a1523994fd533e6a3b22 (patch)
treebb61a346538ddb6945e8aff4c3919ce002c55a89
parentc106259517d7693ea8e24564bc890fe575d5edcd (diff)
Add support for directory prefixes
For example: cxx{driver ../{foo bar}} cxx{driver} ../cxx{foo bar}
-rw-r--r--build/parser10
-rw-r--r--build/parser.cxx68
-rw-r--r--build/path6
-rw-r--r--tests/build/parser/buildfile2
-rw-r--r--tests/build/parser/driver.cxx6
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;
}
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}"));