Lattice Land Core Library
Loading...
Searching...
No Matches
diagnostics.hpp
Go to the documentation of this file.
1// Copyright 2021 Pierre Talbot
2
3#ifndef LALA_CORE_IDIAGNOSTICS_HPP
4#define LALA_CORE_IDIAGNOSTICS_HPP
5
6#include "battery/utility.hpp"
7#include "battery/vector.hpp"
8#include "battery/string.hpp"
9#include "battery/string.hpp"
10#include "battery/tuple.hpp"
11#include "battery/variant.hpp"
12#include "ast.hpp"
13
14namespace lala {
15
16/** `IDiagnostics` is used in abstract domains to diagnose why a formula cannot be interpreted (error) or if it was interpreted by under- or over-approximation (warnings).
17 If the abstract domain cannot interpret the formula, it must explain why.
18 This is similar to compilation errors in compiler. */
20public:
21 using allocator_type = battery::standard_allocator;
24
25private:
26 battery::string<allocator_type> ad_name;
27 battery::string<allocator_type> description;
28 F uninterpretable_formula;
29 AType aty;
30 battery::vector<IDiagnostics, allocator_type> suberrors;
31 bool fatal;
32
33 CUDA void print_indent(int indent) const {
34 for(int i = 0; i < indent; ++i) {
35 printf(" ");
36 }
37 }
38
39 CUDA void print_line(const char* line, int indent) const {
40 print_indent(indent);
41 printf("%s", line);
42 }
43
44public:
45 CUDA NI IDiagnostics(): fatal(false), aty(-2) {} // -2 is a special value indicating it is a top-level diagnostics.
46
47 // If fatal is false, it is considered as a warning.
48 template <class F2>
49 CUDA NI IDiagnostics(bool fatal,
50 battery::string<allocator_type> ad_name,
51 battery::string<allocator_type> description,
52 const F2& uninterpretable_formula,
53 AType aty = UNTYPED)
54 : fatal(fatal),
55 ad_name(std::move(ad_name)),
56 description(std::move(description)),
57 uninterpretable_formula(uninterpretable_formula),
58 aty(aty)
59 {}
60
61 CUDA NI this_type& add_suberror(IDiagnostics&& suberror) {
62 fatal |= suberror.is_fatal();
63 suberrors.push_back(std::move(suberror));
64 return *this;
65 }
66
67 CUDA size_t num_suberrors() const {
68 return suberrors.size();
69 }
70
71 /** Deletes all suberrors between `i` and `n-1`. */
72 CUDA void cut(size_t i) {
73 suberrors.resize(i);
74 fatal = false;
75 for(size_t j = 0; j < suberrors.size(); ++j) {
76 if(suberrors[j].is_fatal()) {
77 fatal = true;
78 return;
79 }
80 }
81 }
82
83 /** This operator moves all `suberrors[i..(n-1)]` as a suberror of `suberrors[i-1]`.
84 * If only warnings are present, `suberrors[i-1]` is converted into a warning.
85 * If `succeeded` is true, then all suberrors are erased.
86 */
87 CUDA void merge(bool succeeded, size_t i) {
88 assert(i > 0);
89 assert(i <= suberrors.size());
90 suberrors[i-1].fatal = !succeeded;
91 for(size_t j = i; j < suberrors.size(); ++j) {
92 // In case of success, we erase the fatal suberrors.
93 if(!succeeded || !suberrors[j].is_fatal()) {
94 suberrors[i-1].add_suberror(std::move(suberrors[j]));
95 }
96 }
97 cut((suberrors[i-1].num_suberrors() == 0 && succeeded) ? i-1 : i);
98 }
99
100 CUDA NI void print(int indent = 0) const {
101 // If it is not a top-level error, we print it, otherwise all errors are listed as `suberrors`.
102 if(aty != -2) {
103 if(fatal) {
104 print_line("[error] ", indent);
105 }
106 else {
107 print_line("[warning] ", indent);
108 }
109 printf("Uninterpretable formula.\n");
110 print_indent(indent);
111 printf(" Abstract domain: %s\n", ad_name.data());
112 print_line(" Abstract type: ", indent);
113 if(aty == UNTYPED) {
114 printf("untyped\n");
115 }
116 else {
117 printf("%d\n", aty);
118 }
119 print_line(" Formula: ", indent);
120 uninterpretable_formula.print(true);
121 printf("\n");
122 print_indent(indent);
123 printf(" Description: %s\n", description.data());
124 }
125 else {
126 indent -= 2;
127 }
128 for(int i = 0; i < suberrors.size(); ++i) {
129 suberrors[i].print(indent + 2);
130 printf("\n");
131 }
132 }
133
134 CUDA bool is_fatal() const { return fatal; }
135 CUDA bool has_warning() const {
136 for(int i = 0; i < suberrors.size(); ++i) {
137 if(!suberrors[i].is_fatal()) {
138 return true;
139 }
140 }
141 return false;
142 }
143};
144
145#define INTERPRETATION_ERROR(MSG) \
146 if constexpr(diagnose) { \
147 diagnostics.add_suberror(IDiagnostics(true, name, (MSG), f)); \
148 }
149
150#define INTERPRETATION_WARNING(MSG) \
151 if constexpr(diagnose) { \
152 diagnostics.add_suberror(IDiagnostics(false, name, (MSG), f)); \
153 }
154
155#define RETURN_INTERPRETATION_ERROR(MSG) \
156 INTERPRETATION_ERROR(MSG) \
157 return false;
158
159#define RETURN_INTERPRETATION_WARNING(MSG) \
160 INTERPRETATION_WARNING(MSG) \
161 return true;
162
163/** This macro creates a high-level error message that is possibly erased if `call` does not lead to any error.
164 * If `call` leads to errors, these errors are moved as suberrors of the high-level error message.
165 * Additionally, `merge` is executed if `call` does not lead to any error.
166 */
167#define CALL_WITH_ERROR_CONTEXT_WITH_MERGE(MSG, CALL, MERGE) \
168 size_t error_context = 0; \
169 if constexpr(diagnose) { \
170 diagnostics.add_suberror(IDiagnostics(false, name, (MSG), f)); \
171 error_context = diagnostics.num_suberrors(); \
172 } \
173 bool res = CALL; \
174 if constexpr(diagnose) { \
175 diagnostics.merge(res, error_context); \
176 } \
177 if(res) { MERGE; } \
178 return res;
179
180#define CALL_WITH_ERROR_CONTEXT(MSG, CALL) \
181 CALL_WITH_ERROR_CONTEXT_WITH_MERGE(MSG, CALL, {})
182
183}
184
185#endif
Definition diagnostics.hpp:19
CUDA void cut(size_t i)
Definition diagnostics.hpp:72
CUDA NI void print(int indent=0) const
Definition diagnostics.hpp:100
CUDA void merge(bool succeeded, size_t i)
Definition diagnostics.hpp:87
CUDA NI IDiagnostics(bool fatal, battery::string< allocator_type > ad_name, battery::string< allocator_type > description, const F2 &uninterpretable_formula, AType aty=UNTYPED)
Definition diagnostics.hpp:49
CUDA bool has_warning() const
Definition diagnostics.hpp:135
CUDA size_t num_suberrors() const
Definition diagnostics.hpp:67
battery::standard_allocator allocator_type
Definition diagnostics.hpp:21
CUDA NI IDiagnostics()
Definition diagnostics.hpp:45
CUDA bool is_fatal() const
Definition diagnostics.hpp:134
CUDA NI this_type & add_suberror(IDiagnostics &&suberror)
Definition diagnostics.hpp:61
CUDA void print(bool print_atype=true) const
Definition ast.hpp:765
Definition abstract_deps.hpp:14
int AType
Definition sort.hpp:18
#define UNTYPED
Definition sort.hpp:21