User Guide
code_printer.cpp
Go to the documentation of this file.
1 /*
2  * Copyright 2023 Blue Brain Project, EPFL.
3  * See the top-level LICENSE file for details.
4  *
5  * SPDX-License-Identifier: Apache-2.0
6  */
7 
9 #include "utils/blame.hpp"
10 #include "utils/string_utils.hpp"
11 #include <memory>
12 
13 namespace nmodl {
14 namespace printer {
15 
16 CodePrinter::CodePrinter(const std::string& filename, std::unique_ptr<utils::Blame> blame)
17  : blame_printer(std::move(blame)) {
18  if (filename.empty()) {
19  throw std::runtime_error("Empty filename for CodePrinter");
20  }
21 
22  ofs.open(filename.c_str());
23 
24  if (ofs.fail()) {
25  auto msg = "Error while opening file '" + filename + "' for CodePrinter";
26  throw std::runtime_error(msg);
27  }
28 
29  sbuf = ofs.rdbuf();
30  result = std::make_unique<std::ostream>(sbuf);
31 }
32 
34  add_text('{');
35  add_newline();
36  indent_level++;
37 }
38 
39 void CodePrinter::push_block(const std::string& expression) {
40  add_indent();
41  add_text(expression, " {");
42  add_newline();
43  indent_level++;
44 }
45 
46 void CodePrinter::chain_block(std::string const& expression) {
47  --indent_level;
48  add_indent();
49  add_text("} ", expression, " {");
50  add_newline();
51  ++indent_level;
52 }
53 
55  add_text(std::string(indent_level * NUM_SPACES, ' '));
56 }
57 
58 void CodePrinter::add_multi_line(const std::string& text) {
59  const auto& lines = stringutils::split_string(text, '\n');
60 
61  int prefix_length{};
62  int start_line{};
63  while (start_line < lines.size()) {
64  const auto& line = lines[start_line];
65  // skip first empty line, if any
66  if (line.empty()) {
67  ++start_line;
68  continue;
69  }
70  // The common indentation of all blocks if the number of spaces
71  // at the beginning of the first non-empty line.
72  for (auto line_it = line.begin(); line_it != line.end() && *line_it == ' '; ++line_it) {
73  prefix_length += 1;
74  }
75  break;
76  }
77 
78  for (const auto& line: lines) {
79  if (line.size() < prefix_length) {
80  // ignore lines made of ' ' characters
81  if (std::find_if_not(line.begin(), line.end(), [](char c) { return c == ' '; }) !=
82  line.end()) {
83  throw std::invalid_argument("Indentation mismatch");
84  }
85  } else {
86  add_line(line.substr(prefix_length));
87  }
88  }
89 }
90 
91 void CodePrinter::add_newline(std::size_t n) {
92  for (std::size_t i = 0; i < n; ++i) {
93  add_text('\n');
94  ++current_line;
95  }
96 }
97 
99  pop_block_nl(1);
100 }
101 
102 void CodePrinter::pop_block_nl(std::size_t num_newlines) {
103  indent_level--;
104  add_indent();
105  add_text('}');
106  add_newline(num_newlines);
107 }
108 
109 void CodePrinter::pop_block(const std::string_view& suffix, std::size_t num_newlines) {
110  pop_block_nl(0);
111  add_text(suffix);
112  add_newline(num_newlines);
113 }
114 
116  if (blame_printer != nullptr) {
117  (*blame_printer)(std::cout, current_line);
118  }
119 }
120 
121 
122 } // namespace printer
123 } // namespace nmodl
nmodl::printer::CodePrinter::add_indent
void add_indent()
print whitespaces for indentation
Definition: code_printer.cpp:54
nmodl::printer::CodePrinter::add_multi_line
void add_multi_line(const std::string &)
Definition: code_printer.cpp:58
nmodl::printer::CodePrinter::blame
void blame()
Blame when on the requested line.
Definition: code_printer.cpp:115
nmodl::printer::CodePrinter::add_text
void add_text(Args &&... args)
Definition: code_printer.hpp:82
nmodl::printer::CodePrinter::sbuf
std::streambuf * sbuf
Definition: code_printer.hpp:47
nmodl::printer::CodePrinter::pop_block_nl
void pop_block_nl(std::size_t num_newlines=0)
same as pop_block but control the number of NL characters (0 or more) with num_newlines parameter
Definition: code_printer.cpp:102
nmodl
encapsulates code generation backend implementations
Definition: ast_common.hpp:26
string_utils.hpp
Implement string manipulation functions.
nmodl::printer::CodePrinter::NUM_SPACES
const size_t NUM_SPACES
Definition: code_printer.hpp:52
nmodl::printer::CodePrinter::result
std::unique_ptr< std::ostream > result
Definition: code_printer.hpp:48
nmodl::printer::CodePrinter::add_line
void add_line(Args &&... args)
Definition: code_printer.hpp:88
nmodl::printer::CodePrinter::chain_block
void chain_block(std::string const &expression)
end a block and immediately start a new one (i.e. "[indent-1]} [expression] {\n")
Definition: code_printer.cpp:46
nmodl::printer::CodePrinter::blame_printer
std::unique_ptr< utils::Blame > blame_printer
Definition: code_printer.hpp:50
code_printer.hpp
Helper class for printing C/C++ code.
nmodl::printer::CodePrinter::CodePrinter
CodePrinter(std::unique_ptr< utils::Blame > blame)
Definition: code_printer.hpp:55
blame.hpp
nmodl::printer::CodePrinter::indent_level
size_t indent_level
Definition: code_printer.hpp:51
nmodl::printer::CodePrinter::pop_block
void pop_block()
end of current block scope (i.e. end with "}") and adds one NL character
Definition: code_printer.cpp:98
nmodl::stringutils::split_string
static std::vector< std::string > split_string(const std::string &text, char delimiter)
Split a text in a list of words, using a given delimiter character.
Definition: string_utils.hpp:116
nmodl::printer::CodePrinter::current_line
size_t current_line
Definition: code_printer.hpp:49
nmodl::printer::CodePrinter::push_block
void push_block()
start a block scope without indentation (i.e. "{\n")
Definition: code_printer.cpp:33
nmodl::printer::CodePrinter::add_newline
void add_newline(std::size_t n=1)
Definition: code_printer.cpp:91
nmodl::printer::CodePrinter::ofs
std::ofstream ofs
Definition: code_printer.hpp:46