From 5807ff000225acf47064eb7f0be965bf1598faaa Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Mon, 9 Mar 2015 11:52:27 +0200 Subject: Add meta/operation lists, lift operations in buildspec --- build/b.cxx | 116 ++++++++++++++++++++++++++++++++++++++++++++++++++++-- build/context | 4 ++ build/context.cxx | 3 ++ build/parser.cxx | 16 ++++---- build/spec | 18 +++++---- build/spec.cxx | 22 +++++------ 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 #include #include -#include //@@ TMP, for dump() +#include // make_move_iterator() +#include //@@ TMP, for dump() #include #include @@ -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 ("", 1, 0); //@@ TODO + + for (auto oi (ms.begin ()); oi != ms.end (); ++oi) + { + opspec& os (*oi); + const location l ("", 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 ("", 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 #include +#include #include @@ -17,6 +18,9 @@ namespace build extern path work; extern path home; + extern std::unordered_set meta_operations; + extern std::unordered_set 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 meta_operations; + unordered_set 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 { 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 { 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 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; -- cgit v1.1