From 2a0f39b29c1bea6a4497c0f1826052ffa453af9e Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Thu, 21 Apr 2016 16:05:13 +0200 Subject: Move module implementation from brep/ to mod/ --- mod/diagnostics | 306 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 306 insertions(+) create mode 100644 mod/diagnostics (limited to 'mod/diagnostics') diff --git a/mod/diagnostics b/mod/diagnostics new file mode 100644 index 0000000..38286d4 --- /dev/null +++ b/mod/diagnostics @@ -0,0 +1,306 @@ +// file : mod/diagnostics -*- C++ -*- +// copyright : Copyright (c) 2014-2016 Code Synthesis Ltd +// license : MIT; see accompanying LICENSE file + +#ifndef MOD_DIAGNOSTICS +#define MOD_DIAGNOSTICS + +#include + +#include +#include + +namespace brep +{ + struct location + { + location (): line (0), column (0) {} + location (string f, uint64_t l, uint64_t c) + : file (move (f)), line (l), column (c) {} + + string file; + uint64_t line; + uint64_t column; + }; + + enum class severity {error, warning, info, trace}; + + struct diag_entry + { + severity sev; + const char* name {nullptr}; // E.g., a function name in tracing. + location loc; + string msg; + }; + + using diag_data = vector; + + // + // + template struct diag_prologue; + template struct diag_mark; + + using diag_epilogue = function; + + struct diag_record + { + template + friend const diag_record& + operator<< (const diag_record& r, const T& x) + { + r.os_ << x; + return r; + } + + diag_record () = default; + + template + explicit + diag_record (const diag_prologue& p) {*this << p;} // See below. + + template + explicit + diag_record (const diag_mark& m) {*this << m;} // See below. + + ~diag_record () noexcept(false); + + void + append (const diag_epilogue& e) const + { + if (epilogue_ == nullptr) // Keep the first epilogue (think 'fail'). + epilogue_ = &e; + + if (!data_.empty ()) + { + data_.back ().msg = os_.str (); + + // Reset the stream. There got to be a more efficient way to do it. + // + os_.clear (); + os_.str (""); + } + + data_.push_back (diag_entry ()); + } + + diag_entry& + current () const {return data_.back ();} + + // Move constructible-only type. + // + /* + @@ libstdc++ doesn't yet have the ostringstream move support. + + diag_record (diag_record&& r) + : data_ (move (r.data_)), os_ (move (r.os_)) + { + epilogue_ = r.epilogue_; + r.data_.clear (); // Empty. + } + */ + + diag_record (diag_record&& r): data_ (move (r.data_)) + { + if (!data_.empty ()) + os_ << r.os_.str (); + + epilogue_ = r.epilogue_; + r.data_.clear (); // Empty. + } + + diag_record& operator= (diag_record&&) = delete; + + diag_record (const diag_record&) = delete; + diag_record& operator= (const diag_record&) = delete; + + private: + mutable diag_data data_; + mutable std::ostringstream os_; + mutable const diag_epilogue* epilogue_ {nullptr}; + }; + + // Base (B) should provide operator() that configures diag_record. + // + template + struct diag_prologue: B + { + diag_prologue (const diag_epilogue& e): B (), epilogue_ (e) {} + + template + diag_prologue (const diag_epilogue& e, A&&... a) + : B (forward (a)...), epilogue_ (e) {} + + template + 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: + const diag_epilogue& epilogue_; + }; + + // Base (B) should provide operator() that returns diag_prologue. + // + template + struct diag_mark: B + { + diag_mark (): B () {} + + template + diag_mark (A&&... a): B (forward (a)...) {} + + template + diag_record + operator<< (const T& x) const + { + return B::operator() () << x; + } + + friend const diag_record& + operator<< (const diag_record& r, const diag_mark& m) + { + return r << m (); + } + }; + + // Prologues. + // + struct simple_prologue_base + { + explicit + simple_prologue_base (severity s, const char* name) + : sev_ (s), name_ (name) {} + + void + operator() (const diag_record& r) const + { + diag_entry& e (r.current ()); + e.sev = sev_; + e.name = name_; + } + + private: + severity sev_; + const char* name_; + }; + typedef diag_prologue simple_prologue; + + struct location_prologue_base + { + location_prologue_base (severity s, + const char* name, + const location& l) + : sev_ (s), name_ (name), loc_ (l) {} + + void + operator() (const diag_record& r) const + { + diag_entry& e (r.current ()); + e.sev = sev_; + e.name = name_; + e.loc = loc_; //@@ I think we can probably move it. + } + + private: + severity sev_; + const char* name_; + const location loc_; + }; + typedef diag_prologue location_prologue; + + // Marks. + // + struct basic_mark_base + { + explicit + basic_mark_base (severity s, + const diag_epilogue& e, + const char* name = nullptr, + const void* data = nullptr) + : sev_ (s), epilogue_ (e), name_ (name), data_ (data) {} + + simple_prologue + operator() () const + { + return simple_prologue (epilogue_, sev_, name_); + } + + location_prologue + operator() (const location& l) const + { + return location_prologue (epilogue_, sev_, name_, l); + } + + template + location_prologue + operator() (const L& l) const + { + // get_location() is the user-supplied ADL-searched function. + // + return location_prologue ( + epilogue_, sev_, name_, get_location (l, data_)); + } + + private: + severity sev_; + const diag_epilogue& epilogue_; + const char* name_; + const void* data_; + }; + typedef diag_mark basic_mark; + + template + struct fail_mark_base + { + explicit + fail_mark_base (const char* name = nullptr, const void* data = nullptr) + : name_ (name), data_ (data) {} + + simple_prologue + operator() () const + { + return simple_prologue (epilogue_, severity::error, name_); + } + + location_prologue + operator() (const location& l) const + { + return location_prologue (epilogue_, severity::error, name_, l); + } + + template + location_prologue + operator() (const L& l) const + { + return location_prologue ( + epilogue_, severity::error, name_, get_location (l, data_)); + } + + static void + epilogue (diag_data&& d) {throw E (move (d));} + + private: + const diag_epilogue epilogue_ {&epilogue}; + const char* name_; + const void* data_; + }; + + template + using fail_mark = diag_mark>; +} + +#endif // MOD_DIAGNOSTICS -- cgit v1.1