Lattice Land Core Library
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 
14 namespace 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. */
19 class IDiagnostics {
20 public:
21  using allocator_type = battery::standard_allocator;
24 
25 private:
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 
44 public:
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 NI this_type & add_suberror(IDiagnostics &&suberror)
Definition: diagnostics.hpp:61
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 void print(bool print_atype=true) const
Definition: ast.hpp:806
Definition: abstract_deps.hpp:14
int AType
Definition: sort.hpp:18
#define UNTYPED
Definition: sort.hpp:21