diff options
Diffstat (limited to 'build/diagnostics')
-rw-r--r-- | build/diagnostics | 310 |
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 |