1 // {{{ MIT License
2 
3 // Copyright 2017 Roland Kaminski
4 
5 // Permission is hereby granted, free of charge, to any person obtaining a copy
6 // of this software and associated documentation files (the "Software"), to
7 // deal in the Software without restriction, including without limitation the
8 // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
9 // sell copies of the Software, and to permit persons to whom the Software is
10 // furnished to do so, subject to the following conditions:
11 
12 // The above copyright notice and this permission notice shall be included in
13 // all copies or substantial portions of the Software.
14 
15 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21 // IN THE SOFTWARE.
22 
23 // }}}
24 
25 #ifndef _GRINGO_REPORT_HH
26 #define _GRINGO_REPORT_HH
27 
28 #include <bitset>
29 #include <cstdio>
30 #include <sstream>
31 #include <stdexcept>
32 #include <memory>
33 #include <functional>
34 
35 #include <iostream>
36 
37 namespace Gringo {
38 
39 // {{{1 declaration of GringoError
40 
41 class GringoError : public std::runtime_error {
42 public:
GringoError(char const * msg)43     GringoError(char const *msg) : std::runtime_error(msg) { }
44 };
45 
46 class MessageLimitError : public std::runtime_error {
47 public:
MessageLimitError(char const * msg)48     MessageLimitError(char const *msg) : std::runtime_error(msg) { }
49 };
50 
51 // {{{1 declaration of Logger
52 
53 enum class Errors : int {
54     Success   = 0,
55     Runtime   = 1,
56     Logic     = 2,
57     Bad_alloc = 3,
58     Unknown   = 4
59 };
60 
61 enum class Warnings : int {
62     OperationUndefined = 0,
63     RuntimeError       = 1,
64     AtomUndefined      = 2,
65     FileIncluded       = 3,
66     VariableUnbounded  = 4,
67     GlobalVariable     = 5,
68     Other              = 6,
69 };
70 
71 class Logger {
72 public:
73     using Printer = std::function<void (Warnings, char const *)>;
Logger(Printer p=nullptr,unsigned limit=20)74     Logger(Printer p = nullptr, unsigned limit = 20)
75     : p_(p)
76     , limit_(limit) { }
77     bool check(Errors id);
78     bool check(Warnings id);
79     bool hasError() const;
80     void enable(Warnings id, bool enable);
81     void print(Warnings code, char const *msg);
82     ~Logger();
83 private:
84     Printer p_;
85     unsigned limit_;
86     std::bitset<static_cast<int>(Warnings::Other)+1> disabled_;
87     bool error_ = false;
88 };
89 
90 // }}}1
91 
92 // {{{1 definition of Logger
93 
check(Warnings id)94 inline bool Logger::check(Warnings id) {
95     if (id == Warnings::RuntimeError) {
96         if (!limit_ && error_) { throw MessageLimitError("too many messages."); }
97         if (limit_) { --limit_; }
98         error_ = true;
99         return true;
100     }
101     else {
102         if (!limit_ && error_) { throw MessageLimitError("too many messages."); }
103         return !disabled_[static_cast<int>(id)] && limit_ && (--limit_, true);
104     }
105 }
106 
hasError() const107 inline bool Logger::hasError() const {
108     return error_;
109 }
110 
enable(Warnings id,bool enabled)111 inline void Logger::enable(Warnings id, bool enabled) {
112     disabled_[static_cast<int>(id)] = !enabled;
113 }
114 
print(Warnings code,char const * msg)115 inline void Logger::print(Warnings code, char const *msg) {
116     if (p_) { p_(code, msg); }
117     else {
118         fprintf(stderr, "%s\n", msg);
119         fflush(stderr);
120     }
121 }
122 
~Logger()123 inline Logger::~Logger() { }
124 
125 // {{{1 definition of Report
126 
127 class Report {
128 public:
Report(Logger & p,Warnings code)129     Report(Logger &p, Warnings code) : p_(p), code_(code) { }
~Report()130     ~Report() { p_.print(code_, out.str().c_str()); }
131     std::ostringstream out;
132 private:
133     Logger &p_;
134     Warnings code_;
135 };
136 
137 // }}}1
138 
139 } // namespace GRINGO
140 
141 #define GRINGO_REPORT(p, id) \
142 if (!(p).check(id)) { } \
143 else Gringo::Report(p, id).out
144 
145 #endif // _GRINGO_REPORT_HH
146 
147