From 65dca85d0acc1ae69518e85b52a2877e38dc8c6d Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Thu, 2 Apr 2015 15:06:55 +0200 Subject: Implement translation of meta/operations to natural language --- build/algorithm.cxx | 30 +++++++------- build/config/operation.cxx | 6 +++ build/diagnostics | 15 +++++++ build/diagnostics.cxx | 99 ++++++++++++++++++++++++++++++++++++++++++++++ build/operation | 18 +++++++++ build/operation.cxx | 38 ++++++++++++++---- build/rule.cxx | 4 +- 7 files changed, 186 insertions(+), 24 deletions(-) (limited to 'build') diff --git a/build/algorithm.cxx b/build/algorithm.cxx index 91ece49..d649210 100644 --- a/build/algorithm.cxx +++ b/build/algorithm.cxx @@ -73,11 +73,12 @@ namespace build { auto g ( make_exception_guard ( - [](target& t, const string& n) + [](action a, target& t, const string& n) { - info << "while matching rule " << n << " for target " << t; + info << "while matching rule " << n << " to " + << diag_do (a, t); }, - t, n)); + a, t, n)); m = ru.match (a, t, hint); } @@ -99,12 +100,12 @@ namespace build { auto g ( make_exception_guard ( - [](target& t, const string& n1) + [](action a, target& t, const string& n1) { - info << "while matching rule " << n1 << " for target " - << t; + info << "while matching rule " << n1 << " to " + << diag_do (a, t); }, - t, n1)); + a, t, n1)); m1 = ru1.match (a, t, hint); } @@ -113,7 +114,7 @@ namespace build { if (!ambig) { - dr << fail << "multiple rules matching target " << t + dr << fail << "multiple rules matching " << diag_doing (a, t) << info << "rule " << n << " matches"; ambig = true; } @@ -126,11 +127,12 @@ namespace build { auto g ( make_exception_guard ( - [](target& t, const string& n) + [](action a, target& t, const string& n) { - info << "while applying rule " << n << " for target " << t; + info << "while applying rule " << n << " to " + << diag_do (a, t); }, - t, n)); + a, t, n)); t.recipe (a, ru.apply (a, t, m)); break; @@ -142,7 +144,7 @@ namespace build } if (!t.recipe (a)) - fail << "no rule to update target " << t; + fail << "no rule to " << diag_do (a, t); } void @@ -215,8 +217,8 @@ namespace build auto g ( make_exception_guard ( - [](target& t){info << "while updating target " << t;}, - t)); + [](action a, target& t){info << "while " << diag_doing (a, t);}, + a, t)); ts = t.recipe (a) (a, t); assert (ts != target_state::unknown && ts != target_state::failed); diff --git a/build/config/operation.cxx b/build/config/operation.cxx index 5b9cc5c..3269f9d 100644 --- a/build/config/operation.cxx +++ b/build/config/operation.cxx @@ -173,6 +173,9 @@ namespace build meta_operation_info configure { "configure", + "configure", + "configuring", + "configured", nullptr, // meta-operation pre &configure_operation_pre, &load, // normal load @@ -272,6 +275,9 @@ namespace build meta_operation_info disfigure { "disfigure", + "disfigure", + "disfiguring", + "disfigured", nullptr, // meta-operation pre &disfigure_operation_pre, &disfigure_load, diff --git a/build/diagnostics b/build/diagnostics index 21e02e2..64a0107 100644 --- a/build/diagnostics +++ b/build/diagnostics @@ -36,6 +36,21 @@ namespace build return os << diag_relative (p); } + // Action phrases, e.g., "configure update exe{foo}", "updating exe{foo}", + // and "updating exe{foo} already configured". + // + struct action; + class target; + + std::string + diag_do (const action&, const target&); + + std::string + diag_doing (const action&, const target&); + + std::string + diag_already_done (const action&, const target&); + // Print process commmand line. // void diff --git a/build/diagnostics.cxx b/build/diagnostics.cxx index 43ee0e5..aab7675 100644 --- a/build/diagnostics.cxx +++ b/build/diagnostics.cxx @@ -4,8 +4,12 @@ #include +#include #include +#include +#include +#include #include #include @@ -53,6 +57,101 @@ namespace build return p.string (); } + // diag_do(), etc. + // + string + diag_do (const action& a, const target& t) + { + // @@ root scope + // + scope& root ( + scopes.find ( + scopes.find (t.dir)["out_root"].as ())); + + const meta_operation_info& mi (root.meta_operations[a.meta_operation ()]); + const operation_info& oi (root.operations[a.operation ()]); + + ostringstream os; + + // perform(update(x)) -> "update x" + // configure(update(x)) -> "configure updating x" + // + if (mi.name_do.empty ()) + os << oi.name_do << ' '; + else + { + os << mi.name_do << ' '; + + if (!oi.name_doing.empty ()) + os << oi.name_doing << ' '; + } + + os << t; + return os.str (); + } + + string + diag_doing (const action& a, const target& t) + { + // @@ root scope + // + scope& root ( + scopes.find ( + scopes.find (t.dir)["out_root"].as ())); + + const meta_operation_info& mi (root.meta_operations[a.meta_operation ()]); + const operation_info& oi (root.operations[a.operation ()]); + + ostringstream os; + + // perform(update(x)) -> "updating x" + // configure(update(x)) -> "configuring updating x" + // + if (!mi.name_doing.empty ()) + os << mi.name_doing << ' '; + + if (!oi.name_doing.empty ()) + os << oi.name_doing << ' '; + + os << t; + return os.str (); + } + + string + diag_already_done (const action& a, const target& t) + { + // @@ root scope + // + scope& root ( + scopes.find ( + scopes.find (t.dir)["out_root"].as ())); + + const meta_operation_info& mi (root.meta_operations[a.meta_operation ()]); + const operation_info& oi (root.operations[a.operation ()]); + + ostringstream os; + + // perform(update(x)) -> "x is already up to date" + // configure(update(x)) -> "updating x is already configured" + // + if (mi.name_already_done.empty ()) + { + os << t; + + if (!oi.name_already_done.empty ()) + os << " is already " << oi.name_already_done; + } + else + { + if (!oi.name_doing.empty ()) + os << oi.name_doing << ' '; + + os << t << " is already " << mi.name_already_done; + } + + return os.str (); + } + void print_process (const char* const* args) { diff --git a/build/operation b/build/operation index ac93999..3d9c4a4 100644 --- a/build/operation +++ b/build/operation @@ -122,6 +122,13 @@ namespace build { const std::string name; + // Name derivatives for diagnostics. If empty, then the meta- + // operation need not be mentioned. + // + const std::string name_do; // E.g., [to] 'configure'. + const std::string name_doing; // E.g., [while] 'configuring'. + const std::string name_already_done; // E.g., [already] 'configured'. + void (*meta_operation_pre) (); // Start of meta-operation batch. operation_id (*operation_pre) (operation_id); // Start of operation batch. @@ -184,6 +191,17 @@ namespace build struct operation_info { const std::string name; + + // Name derivatives for diagnostics. Note that unlike meta-operations, + // these can only be empty for the default operation (id 1), And + // meta-operations that make use of the default operation shall not + // have empty derivatives (failed which only target name will be + // printed). + // + const std::string name_do; // E.g., [to] 'update'. + const std::string name_doing; // E.g., [while] 'updating'. + const std::string name_already_done; // E.g., [already] 'up to date'. + const execution_mode mode; }; diff --git a/build/operation.cxx b/build/operation.cxx index 7fab63e..0d6bfcd 100644 --- a/build/operation.cxx +++ b/build/operation.cxx @@ -98,19 +98,19 @@ namespace build { target& t (*static_cast (v)); - level4 ([&]{trace << "executing target " << t;}); + level4 ([&]{trace << diag_doing (a, t);}); switch (execute (a, t)) { case target_state::postponed: { - info << "target " << t << " is postponed"; + info << diag_doing (a, t) << " is postponed"; psp.push_back (t); break; } case target_state::unchanged: { - info << "target " << t << " is unchanged"; + info << diag_already_done (a, t); break; } case target_state::changed: @@ -130,12 +130,12 @@ namespace build { case target_state::postponed: { - info << "unable to execute target " << t << " at this time"; + info << "unable to " << diag_do (a, t) << " at this time"; break; } case target_state::unchanged: { - info << "target " << t << " is unchanged"; + info << diag_already_done (a, t); break; } case target_state::unknown: // Assume something was done to it. @@ -151,6 +151,9 @@ namespace build meta_operation_info perform { "perform", + "", + "", + "", nullptr, // meta-operation pre nullptr, // operation pre &load, @@ -162,7 +165,26 @@ namespace build // operations // - operation_info default_ {"", execution_mode::first}; - operation_info update {"update", execution_mode::first}; - operation_info clean {"clean", execution_mode::last}; + operation_info default_ { + "", + "", + "", + "", + execution_mode::first + }; + + operation_info update { + "update", + "update", + "updating", + "up to date", + execution_mode::first + }; + + operation_info clean { + "clean", + "clean", + "cleaning", + "clean", + execution_mode::last}; } diff --git a/build/rule.cxx b/build/rule.cxx index fb5af3f..413676b 100644 --- a/build/rule.cxx +++ b/build/rule.cxx @@ -125,7 +125,7 @@ namespace build timestamp mp (mpt->mtime ()); if (mt < mp) - fail << "no recipe to update target " << t << + fail << "no recipe to " << diag_do (a, t) << info << "prerequisite " << pt << " is ahead of " << t << " by " << (mp - mt); } @@ -134,7 +134,7 @@ namespace build // Otherwise we assume the prerequisite is newer if it was changed. // if (ts == target_state::changed) - fail << "no recipe to update target " << t << + fail << "no recipe to " << diag_do (a, t) << info << "prerequisite " << pt << " is ahead of " << t << " because it was updated"; } -- cgit v1.1