aboutsummaryrefslogtreecommitdiff
path: root/build/diagnostics
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2015-01-20 17:18:09 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2015-01-20 17:18:09 +0200
commitb0524a0b18eec9d5e5c3f6ce30b6cecdd02a6306 (patch)
tree4b1efc586782507e0647e884d6a13c6605298508 /build/diagnostics
parent47751abc43dab40e0ac4a1523994fd533e6a3b22 (diff)
Diagnostic infrastructure revamp
Diffstat (limited to 'build/diagnostics')
-rw-r--r--build/diagnostics310
1 files changed, 282 insertions, 28 deletions
diff --git a/build/diagnostics b/build/diagnostics
index 98f481f..f85d118 100644
--- a/build/diagnostics
+++ b/build/diagnostics
@@ -5,20 +5,17 @@
#ifndef BUILD_DIAGNOSTICS
#define BUILD_DIAGNOSTICS
-#include <tuple>
#include <vector>
+#include <cstdint>
#include <utility>
+#include <cassert>
+#include <sstream>
+#include <ostream>
#include <exception>
-
-#include <build/trace>
+#include <type_traits>
namespace build
{
- // Throw this exception to terminate the build. The handler should
- // assume that the diagnostics has already been issued.
- //
- class error: public std::exception {};
-
// Print process commmand line.
//
void
@@ -30,39 +27,296 @@ namespace build
print_process (args.data ());
}
- // Call a function if there is an exception.
+ // Throw this exception to terminate the build. The handler should
+ // assume that the diagnostics has already been issued.
+ //
+ class failed: public std::exception {};
+
+ // Trace verbosity level.
//
- template <typename F, typename T>
- struct exception_guard;
+ // 1 - command lines to update explicit targets (e.g., .o)
+ // 2 - command lines to update implicit targets (e.g., .d)
+ // 3 - things didn't work out (e.g., rule did not match)
+ // 4 - additional information
+ // 5 - more additional information
+ //
+ extern std::uint8_t verb;
+
+ template <typename F> inline void level1 (const F& f) {if (verb >= 1) f ();}
+ template <typename F> inline void level2 (const F& f) {if (verb >= 2) f ();}
+ template <typename F> inline void level3 (const F& f) {if (verb >= 3) f ();}
+ template <typename F> inline void level4 (const F& f) {if (verb >= 4) f ();}
+ template <typename F> inline void level5 (const F& f) {if (verb >= 5) f ();}
+
+ // Diagnostic facility, base infrastructure (potentially reusable).
+ //
+ extern std::ostream* diag_stream;
+
+ template <typename> struct diag_prologue;
+ template <typename> struct diag_mark;
- template <typename F, typename... A>
- inline exception_guard<F, std::tuple<A&&...>>
- make_exception_guard (F f, A&&... a)
+ struct diag_record;
+
+ typedef void (*diag_epilogue) (const diag_record&);
+
+ struct diag_record
{
- return exception_guard<F, std::tuple<A&&...>> (
- std::move (f), std::forward_as_tuple (a...));
- }
+ template <typename T>
+ friend const diag_record&
+ operator<< (const diag_record& r, const T& x)
+ {
+ r.os_ << x;
+ return r;
+ }
+
+ diag_record (): empty_ (true), epilogue_ (nullptr) {}
+
+ template <typename B>
+ explicit
+ diag_record (const diag_prologue<B>& p)
+ : empty_ (true), epilogue_ (nullptr) { *this << p;}
+
+ template <typename B>
+ explicit
+ diag_record (const diag_mark<B>& m)
+ : empty_ (true), epilogue_ (nullptr) { *this << m;}
+
+ ~diag_record () noexcept(false);
+
+ void
+ append (diag_epilogue e) const
+ {
+ if (e != nullptr)
+ {
+ assert (epilogue_ == nullptr); // No multiple epilogues support.
+ epilogue_ = e;
+ }
+
+ if (empty_)
+ empty_ = false;
+ else
+ os_ << "\n ";
+ }
+
+ // Move constructible-only type.
+ //
+ /*
+ @@ libstdc++ doesn't yet have the ostringstream move support.
+
+ diag_record (diag_record&& r)
+ : os_ (std::move (r.os_))
+ {
+ empty_ = r.empty_;
+ r.empty_ = true;
+
+ epilogue_ = r.epilogue_;
+ r.epilogue_ = nullptr;
+ }
+ */
+
+ diag_record (diag_record&& r)
+ {
+ empty_ = r.empty_;
+ epilogue_ = r.epilogue_;
+
+ if (!empty_)
+ {
+ os_ << r.os_.str ();
+
+ r.empty_ = true;
+ r.epilogue_ = nullptr;
+ }
+ }
+
+ diag_record& operator= (diag_record&&) = delete;
+
+ diag_record (const diag_record&) = delete;
+ diag_record& operator= (const diag_record&) = delete;
+
+ private:
+ mutable bool empty_;
+ mutable std::ostringstream os_;
+ mutable diag_epilogue epilogue_;
+ };
+
+ template <typename B>
+ struct diag_prologue: B
+ {
+ diag_prologue (diag_epilogue e = nullptr): B (), epilogue_ (e) {}
+
+ template <typename... A>
+ diag_prologue (A&&... a)
+ : B (std::forward<A> (a)...), epilogue_ (nullptr) {}
+
+ template <typename... A>
+ diag_prologue (diag_epilogue e, A&&... a)
+ : B (std::forward<A> (a)...), epilogue_ (e) {}
+
+ template <typename T>
+ diag_record
+ operator<< (const T& x) const
+ {
+ diag_record r;
+ r.append (epilogue_);
+ B::operator() (r);
+ r << x;
+ return r;
+ }
+
+ friend const diag_record&
+ operator<< (const diag_record& r, const diag_prologue& p)
+ {
+ r.append (p.epilogue_);
+ p (r);
+ return r;
+ }
+
+ private:
+ diag_epilogue epilogue_;
+ };
- template <typename F, typename... A>
- struct exception_guard<F, std::tuple<A...>>
+ template <typename B>
+ struct diag_mark: B
{
- typedef std::tuple<A...> T;
+ diag_mark (): B () {}
- exception_guard (F f, T a): f_ (std::move (f)), a_ (std::move (a)) {}
- ~exception_guard ()
+ template <typename... A>
+ diag_mark (A&&... a): B (std::forward<A> (a)...) {}
+
+ template <typename T>
+ diag_record
+ operator<< (const T& x) const
{
- if (std::uncaught_exception ())
- call (std::index_sequence_for<A...> ());
+ return B::operator() () << x;
}
+ friend const diag_record&
+ operator<< (const diag_record& r, const diag_mark& m)
+ {
+ return r << m ();
+ }
+ };
+
+ // Diagnostic facility, project specifics.
+ //
+ struct simple_prologue_base
+ {
+ explicit
+ simple_prologue_base (const char* type, const char* name)
+ : type_ (type), name_ (name) {}
+
+ void
+ operator() (const diag_record& r) const;
+
private:
- template <std::size_t... I>
+ const char* type_;
+ const char* name_;
+ };
+ typedef diag_prologue<simple_prologue_base> simple_prologue;
+
+ struct location
+ {
+ location () {}
+ location (const char* f, std::uint64_t l, std::uint64_t c)
+ : file (f), line (l), column (c) {}
+
+ const char* file;
+ std::uint64_t line;
+ std::uint64_t column;
+ };
+
+ struct location_prologue_base
+ {
+ location_prologue_base (const char* type,
+ const char* name,
+ const location& l)
+ : type_ (type), name_ (name), loc_ (l) {}
+
void
- call (std::index_sequence<I...>) {f_ (std::get<I> (a_)...);}
+ operator() (const diag_record& r) const;
+
+ private:
+ const char* type_;
+ const char* name_;
+ const location& loc_;
+ };
+ typedef diag_prologue<location_prologue_base> location_prologue;
+
+ struct basic_mark_base
+ {
+ explicit
+ basic_mark_base (const char* type, const char* name = nullptr)
+ : type_ (type), name_ (name) {}
+
+ simple_prologue
+ operator() () const
+ {
+ return simple_prologue (type_, name_);
+ }
+
+ location_prologue
+ operator() (const location& l) const
+ {
+ return location_prologue (type_, name_, l);
+ }
+
+ template <typename L>
+ location_prologue
+ operator() (const L& l) const
+ {
+ return location_prologue (type_, name_, get_location (l));
+ }
- F f_;
- T a_;
+ private:
+ const char* type_;
+ const char* name_;
};
+ typedef diag_mark<basic_mark_base> basic_mark;
+
+ extern const basic_mark error;
+ extern const basic_mark warn;
+ extern const basic_mark info;
+ extern const basic_mark text;
+
+ struct trace_mark_base: basic_mark_base
+ {
+ explicit
+ trace_mark_base (const char* name): basic_mark_base ("trace", name) {}
+ };
+ typedef diag_mark<trace_mark_base> trace_mark;
+
+ typedef trace_mark tracer;
+
+ template <typename E>
+ struct fail_mark_base
+ {
+ simple_prologue
+ operator() () const
+ {
+ return simple_prologue (&epilogue, "error", nullptr);
+ }
+
+ location_prologue
+ operator() (const location& l) const
+ {
+ return location_prologue (&epilogue, "error", nullptr, l);
+ }
+
+ template <typename L>
+ location_prologue
+ operator() (const L& l) const
+ {
+ return location_prologue (&epilogue, "error", nullptr, get_location (l));
+ }
+
+ static void
+ epilogue (const diag_record&) {throw E ();}
+ };
+
+ template <typename E>
+ using fail_mark = diag_mark<fail_mark_base<E>>;
+
+ extern const fail_mark<failed> fail;
}
#endif // BUILD_DIAGNOSTICS