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