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