User Guide
blame.cpp
Go to the documentation of this file.
1 #include "blame.hpp"
2 
3 #include "string_utils.hpp"
4 #include "utils/fmt.h"
5 #include <filesystem>
6 #include <stdexcept>
7 #include <string>
8 
9 #if NMODL_ENABLE_BACKWARD
10 #include <backward.hpp>
11 #endif
12 
13 namespace nmodl {
14 namespace utils {
15 
16 class NoBlame: public Blame {
17  public:
18  using Blame::Blame;
19 
20  protected:
21  std::string format() const override {
22  return "";
23  }
24 };
25 
26 #if NMODL_ENABLE_BACKWARD
27 size_t first_relevant_trace(backward::TraceResolver& tr, const backward::StackTrace& st) {
28  std::vector<std::string> stop_at{"printer/code_printer.cpp", "printer/code_printer.hpp"};
29  int start_from = int(st.size()) - 2;
30  for (int i = start_from; i >= 0; --i) {
31  backward::ResolvedTrace trace = tr.resolve(st[i]);
32  const std::string& filename = trace.source.filename;
33 
34  for (const auto& f: stop_at) {
35  if (stringutils::ends_with(filename, f)) {
36  return i + 1;
37  }
38  }
39  }
40 
41  throw std::runtime_error("Failed to determine relevant trace.");
42 }
43 
44 class BackwardTracePrinter {
45  public:
46  std::string format(const backward::ResolvedTrace& trace, const std::string& trace_label) const {
47  const std::string& filename = trace.source.filename;
48  size_t linenumber = trace.source.line;
49 
50  auto pad = std::string(trace_label.size(), ' ');
51 
52  std::stringstream sout;
53 
54  sout << fmt::format("{} Source: \"{}\", line {}, in {}\n",
55  trace_label,
56  filename,
57  linenumber,
58  trace.source.function);
59 
60  if (std::filesystem::exists(trace.source.filename) && trace.source.line != 0) {
61  auto snippet = snippets.get_snippet(filename, linenumber, 3);
62  for (auto line: snippet) {
63  sout << fmt::format("{} {}{:>5d}: {}\n",
64  pad,
65  linenumber == line.first ? ">" : " ",
66  line.first,
67  line.second);
68  }
69  }
70 
71  return sout.str();
72  }
73 
74  mutable backward::SnippetFactory snippets;
75 };
76 
77 class ShortBlame: public Blame {
78  public:
79  using Blame::Blame;
80 
81  protected:
82  std::string format() const override {
83  backward::StackTrace st;
84  st.load_here(32);
85 
86  backward::TraceResolver tr;
87 
88  size_t trace_id = first_relevant_trace(tr, st);
89  backward::ResolvedTrace trace = tr.resolve(st[trace_id]);
90 
91  return trace_printer.format(trace, "");
92  }
93 
94  BackwardTracePrinter trace_printer;
95 };
96 
97 
98 class DetailedBlame: public Blame {
99  public:
100  using Blame::Blame;
101 
102  protected:
103  std::string format() const override {
104  backward::StackTrace st;
105  st.load_here(32);
106 
107  backward::TraceResolver tr;
108 
109  size_t first_trace_id = first_relevant_trace(tr, st);
110 
111  std::string full_trace = "\n\n --- Backtrace ----------------\n";
112  for (int i = st.size() - 1; i >= first_trace_id; --i) {
113  backward::ResolvedTrace trace = tr.resolve(st[i]);
114  full_trace += trace_printer.format(trace, std::to_string(i) + ":");
115  }
116  return full_trace;
117  }
118 
119  BackwardTracePrinter trace_printer;
120 };
121 
122 
123 #else
126 #endif
127 
128 std::unique_ptr<Blame> make_blame(size_t blame_line, BlameLevel blame_level) {
129  if (blame_level == BlameLevel::Short) {
130  return std::make_unique<ShortBlame>(blame_line);
131  } else if (blame_level == BlameLevel::Detailed) {
132  return std::make_unique<DetailedBlame>(blame_line);
133  } else {
134  throw std::runtime_error("Unknown blame_level.");
135  }
136 }
137 
138 } // namespace utils
139 } // namespace nmodl
nmodl::utils::Blame::Blame
Blame(size_t blame_line)
Definition: blame.hpp:11
nmodl::utils::DetailedBlame
NoBlame DetailedBlame
Definition: blame.cpp:125
nmodl
encapsulates code generation backend implementations
Definition: ast_common.hpp:26
string_utils.hpp
Implement string manipulation functions.
nmodl::utils::NoBlame
Definition: blame.cpp:16
nmodl::utils::Blame
Definition: blame.hpp:9
nmodl::utils::make_blame
std::unique_ptr< Blame > make_blame(size_t blame_line, BlameLevel blame_level)
Definition: blame.cpp:128
nmodl::symtab::syminfo::to_string
std::string to_string(const T &obj)
Definition: symbol_properties.hpp:282
nmodl::utils::BlameLevel::Short
@ Short
blame.hpp
nmodl::utils::NoBlame::format
std::string format() const override
Definition: blame.cpp:21
nmodl::stringutils::ends_with
static bool ends_with(const std::string &haystack, const std::string &needle)
Check if haystack ends with needle.
Definition: string_utils.hpp:135
nmodl::utils::BlameLevel::Detailed
@ Detailed
fmt.h
nmodl::utils::ShortBlame
NoBlame ShortBlame
Definition: blame.cpp:124
nmodl::utils::BlameLevel
BlameLevel
Definition: blame.hpp:30