aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2015-03-09 11:52:27 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2015-03-09 11:52:27 +0200
commit5807ff000225acf47064eb7f0be965bf1598faaa (patch)
tree0811254ebad92470a54cbeb6ce89646a7f8aa815
parentfa6f9986dd73627643469c238b32dd92607f5214 (diff)
Add meta/operation lists, lift operations in buildspec
-rw-r--r--build/b.cxx116
-rw-r--r--build/context4
-rw-r--r--build/context.cxx3
-rw-r--r--build/parser.cxx16
-rw-r--r--build/spec18
-rw-r--r--build/spec.cxx22
6 files changed, 149 insertions, 30 deletions
diff --git a/build/b.cxx b/build/b.cxx
index ce10b22..4779a57 100644
--- a/build/b.cxx
+++ b/build/b.cxx
@@ -14,7 +14,8 @@
#include <cassert>
#include <fstream>
#include <sstream>
-#include <iostream> //@@ TMP, for dump()
+#include <iterator> // make_move_iterator()
+#include <iostream> //@@ TMP, for dump()
#include <typeinfo>
#include <system_error>
@@ -101,6 +102,17 @@ main (int argc, char* argv[])
target_types.insert (cxx::ixx::static_type);
target_types.insert (cxx::txx::static_type);
+ // Enter built-in meta-operation and operation names. Loading of
+ // the buildfiles can result in additional names being added (via
+ // module loading).
+ //
+ meta_operations.emplace ("perform"); // Default.
+ meta_operations.emplace ("configure");
+ meta_operations.emplace ("disfigure");
+
+ operations.emplace ("update"); // Default.
+ operations.emplace ("clean");
+
// Figure out work and home directories.
//
work = path::current ();
@@ -193,7 +205,7 @@ main (int argc, char* argv[])
for (targetspec& ts: os)
{
- name& tn (ts.target);
+ name& tn (ts.name);
// First figure out the out_base of this target. The logic
// is as follows: if a directory was specified in any form,
@@ -325,6 +337,103 @@ main (int argc, char* argv[])
dump_scopes ();
dump ();
+ // At this stage we know all the names of meta-operations and
+ // operations so "lift" names that we assumed (from buildspec
+ // syntax) were operations but are actually meta-operations.
+ // Also convert empty names (which means they weren't explicitly
+ // specified) to the defaults and verify that all the names are
+ // known.
+ //
+ for (auto mi (bspec.begin ()); mi != bspec.end (); ++mi)
+ {
+ metaopspec& ms (*mi);
+ const location l ("<buildspec>", 1, 0); //@@ TODO
+
+ for (auto oi (ms.begin ()); oi != ms.end (); ++oi)
+ {
+ opspec& os (*oi);
+ const location l ("<buildspec>", 1, 0); //@@ TODO
+
+ if (os.name.empty ())
+ {
+ os.name = "update";
+ continue;
+ }
+
+ if (meta_operations.count (os.name))
+ {
+ if (!ms.name.empty ())
+ fail (l) << "nested meta-operation " << os.name;
+
+ // The easy case is when the metaopspec contains a
+ // single opspec (us). In this case we can just move
+ // the name.
+ //
+ if (ms.size () == 1)
+ {
+ ms.name = move (os.name);
+ os.name = "update";
+ continue;
+ }
+ // The hard case is when there are other operations that
+ // need to keep their original meta-operation. In this
+ // case we have to "split" the metaopspec, in the worst
+ // case scenario, into three parts: prefix, us, and suffix.
+ //
+ else
+ {
+ if (oi != ms.begin ()) // We have a prefix of opspec's.
+ {
+ // Keep the prefix in the original metaopspec and move
+ // the suffix into a new one that is inserted after the
+ // prefix. Then simply let the loop finish with the prefix
+ // and naturally move to the suffix (in other words, we
+ // are reducing this case to the one without a prefix).
+ //
+ metaopspec suffix;
+ suffix.insert (suffix.end (),
+ make_move_iterator (oi),
+ make_move_iterator (ms.end ()));
+ ms.resize (oi - ms.begin ());
+
+ mi = bspec.insert (++mi, move (suffix)); // Insert after prefix.
+ --mi; // Move back to prefix.
+ break;
+ }
+
+ // We are the first element and have a suffix of opspec's
+ // (otherwise one of the previous cases would have matched).
+ //
+ assert (oi == ms.begin () && (oi + 1) != ms.end ());
+
+ // Move this opspec into a new metaopspec and insert it before
+ // the current one. Then continue with the next opspec.
+ //
+ metaopspec prefix (move (os.name));
+ os.name = "update";
+ prefix.push_back (move (os));
+ ms.erase (oi);
+
+ mi = bspec.insert (mi, move (prefix)); // Insert before suffix.
+ break; // Restart inner loop: outer loop ++ moves back to suffix.
+ }
+ }
+
+ if (!operations.count (os.name))
+ fail (l) << "unknown operation " << os.name;
+ }
+
+ // Note: using mi rather than ms since ms is invalidated by above
+ // insert()'s.
+ //
+ if (mi->name.empty ())
+ mi->name = "perform";
+ else if (!meta_operations.count (mi->name))
+ fail (l) << "unknown meta-operation " << mi->name;
+ }
+
+ level4 ([&]{trace << "buildspec: " << bspec;});
+
// Register rules.
//
cxx::link cxx_link;
@@ -342,6 +451,7 @@ main (int argc, char* argv[])
path_rule path_r;
rules[typeid (path_target)].emplace ("path", path_r);
+
// Do the operations. We do meta-operations and operations sequentially
// (no parallelism).
//
@@ -361,7 +471,7 @@ main (int argc, char* argv[])
//
for (targetspec& ts: os)
{
- name& tn (ts.target);
+ name& tn (ts.name);
const location l ("<buildspec>", 1, 0); //@@ TODO
const string* e;
diff --git a/build/context b/build/context
index 7c7421d..1967a83 100644
--- a/build/context
+++ b/build/context
@@ -7,6 +7,7 @@
#include <string>
#include <ostream>
+#include <unordered_set>
#include <build/path>
@@ -17,6 +18,9 @@ namespace build
extern path work;
extern path home;
+ extern std::unordered_set<std::string> meta_operations;
+ extern std::unordered_set<std::string> operations;
+
// Return the src/out directory corresponding to the given out/src. The
// passed directory should be a sub-directory of out/src_root.
//
diff --git a/build/context.cxx b/build/context.cxx
index 6c37e38..d58f9c7 100644
--- a/build/context.cxx
+++ b/build/context.cxx
@@ -16,6 +16,9 @@ namespace build
path work;
path home;
+ unordered_set<string> meta_operations;
+ unordered_set<string> operations;
+
path
src_out (const path& out, scope& s)
{
diff --git a/build/parser.cxx b/build/parser.cxx
index 343f5e1..74b41cc 100644
--- a/build/parser.cxx
+++ b/build/parser.cxx
@@ -1025,7 +1025,7 @@ namespace build
//
if (targets != 0)
{
- if (bs.empty () || !bs.back ().meta_operation.empty ())
+ if (bs.empty () || !bs.back ().name.empty ())
bs.push_back (metaopspec ()); // Empty (default) meta operation.
metaopspec& ms (bs.back ());
@@ -1053,7 +1053,7 @@ namespace build
assert (i != e);
}
- if (ms.empty () || !ms.back ().operation.empty ())
+ if (ms.empty () || !ms.back ().name.empty ())
ms.push_back (opspec ()); // Empty (default) operation.
opspec& os (ms.back ());
@@ -1079,14 +1079,14 @@ namespace build
bool meta (false);
for (const metaopspec& nms: nbs)
{
- if (!nms.meta_operation.empty ())
- fail (l) << "nested meta-operation " << nms.meta_operation;
+ if (!nms.name.empty ())
+ fail (l) << "nested meta-operation " << nms.name;
if (!meta)
{
for (const opspec& nos: nms)
{
- if (!nos.operation.empty ())
+ if (!nos.name.empty ())
{
meta = true;
break;
@@ -1103,7 +1103,7 @@ namespace build
if (meta)
{
- nmo.meta_operation = move (ns.back ().value);
+ nmo.name = move (ns.back ().value);
bs.push_back (move (nmo));
}
else
@@ -1114,10 +1114,10 @@ namespace build
assert (nmo.size () == 1);
opspec& nos (nmo.back ());
- if (bs.empty () || !bs.back ().meta_operation.empty ())
+ if (bs.empty () || !bs.back ().name.empty ())
bs.push_back (metaopspec ()); // Empty (default) meta operation.
- nos.operation = move (ns.back ().value);
+ nos.name = move (ns.back ().value);
bs.back ().push_back (move (nos));
}
diff --git a/build/spec b/build/spec
index fda4186..ace0400 100644
--- a/build/spec
+++ b/build/spec
@@ -17,29 +17,31 @@ namespace build
{
struct targetspec
{
+ typedef build::name name_type;
+
explicit
- targetspec (name t): target (std::move (t)) {}
- targetspec (path sb, name t)
- : src_base (std::move (sb)), target (std::move (t)) {}
+ targetspec (name_type n): name (std::move (n)) {}
+ targetspec (path sb, name_type n)
+ : src_base (std::move (sb)), name (std::move (n)) {}
path src_base;
- name target;
+ name_type name;
};
struct opspec: std::vector<targetspec>
{
opspec () = default;
- opspec (std::string o): operation (std::move (o)) {}
+ opspec (std::string n): name (std::move (n)) {}
- std::string operation;
+ std::string name;
};
struct metaopspec: std::vector<opspec>
{
metaopspec () = default;
- metaopspec (std::string mo): meta_operation (std::move (mo)) {}
+ metaopspec (std::string n): name (std::move (n)) {}
- std::string meta_operation;
+ std::string name;
};
typedef std::vector<metaopspec> buildspec;
diff --git a/build/spec.cxx b/build/spec.cxx
index 31bd4f1..d68154f 100644
--- a/build/spec.cxx
+++ b/build/spec.cxx
@@ -32,26 +32,26 @@ namespace build
}
}
- os << s.target;
+ os << s.name;
return os;
}
ostream&
operator<< (ostream& os, const opspec& s)
{
- bool ho (!s.operation.empty ());
+ bool hn (!s.name.empty ());
bool ht (!s.empty ());
- //os << s.operation;
- os << (ho ? "\"" : "") << s.operation << (ho ? "\"" : "");
+ //os << s.name;
+ os << (hn ? "\"" : "") << s.name << (hn ? "\"" : "");
- if (ho && ht)
+ if (hn && ht)
os << '(';
for (auto b (s.begin ()), i (b); i != s.end (); ++i)
os << (i != b ? " " : "") << *i;
- if (ho && ht)
+ if (hn && ht)
os << ')';
return os;
@@ -60,19 +60,19 @@ namespace build
ostream&
operator<< (ostream& os, const metaopspec& s)
{
- bool hm (!s.meta_operation.empty ());
+ bool hn (!s.name.empty ());
bool ho (!s.empty ());
- //os << s.meta_operation;
- os << (hm ? "\'" : "") << s.meta_operation << (hm ? "\'" : "");
+ //os << s.name;
+ os << (hn ? "\'" : "") << s.name << (hn ? "\'" : "");
- if (hm && ho)
+ if (hn && ho)
os << '(';
for (auto b (s.begin ()), i (b); i != s.end (); ++i)
os << (i != b ? " " : "") << *i;
- if (hm && ho)
+ if (hn && ho)
os << ')';
return os;