ArkScript
A small, fast, functional and scripting language for video games
makeErrorCtx.cpp
Go to the documentation of this file.
2 
3 #include <vector>
4 #include <iomanip>
5 #include <termcolor/termcolor.hpp>
6 
7 #include <Ark/Constants.hpp>
8 #include <Ark/Files.hpp>
9 #include <Ark/Utils.hpp>
10 
11 namespace Ark::internal
12 {
13  void makeContext(std::ostream& os, const std::string& code, std::size_t line, std::size_t col_start, std::size_t sym_size)
14  {
15  os << termcolor::colorize;
16  std::vector<std::string> ctx = Utils::splitString(code, '\n');
17 
18  std::size_t col_end = std::min<std::size_t>(col_start + sym_size, ctx[line].size());
19  std::size_t first = line >= 3 ? line - 3 : 0;
20  std::size_t last = (line + 3) <= ctx.size() ? line + 3 : ctx.size();
21  LineColorContextCounts line_color_context_counts;
22 
23  for (std::size_t loop = first; loop < last; ++loop)
24  {
25  std::string current_line = colorizeLine(ctx[loop], line_color_context_counts);
26  os << termcolor::green << std::setw(5) << (loop + 1) << termcolor::reset << " | " << current_line << "\n";
27 
28  if (loop == line)
29  {
30  os << " | ";
31 
32  // padding of spaces
33  for (std::size_t i = 0; i < col_start; ++i)
34  os << " ";
35 
36  // underline the error
37  os << termcolor::red;
38  for (std::size_t i = col_start; i < col_end; ++i)
39  os << "^";
40 
41  os << termcolor::reset << "\n";
42  }
43  }
44  }
45 
46  std::string colorizeLine(const std::string& line, LineColorContextCounts& line_color_context_counts)
47  {
48  constexpr std::array<std::ostream& (*)(std::ostream & stream), 3> pairing_color {
49  termcolor::bright_blue,
50  termcolor::bright_green,
51  termcolor::bright_yellow
52  };
53  std::size_t pairing_color_size = pairing_color.size();
54 
55  std::stringstream colorized_line;
56  colorized_line << termcolor::colorize;
57 
58  for (const char& c : line)
59  {
60  if (isPairableChar(c))
61  {
62  std::size_t pairing_color_index = 0;
63 
64  switch (c)
65  {
66  case '(':
67  pairing_color_index = std::abs(line_color_context_counts.open_parentheses) % pairing_color_size;
68  line_color_context_counts.open_parentheses++;
69  break;
70  case ')':
71  line_color_context_counts.open_parentheses--;
72  pairing_color_index = std::abs(line_color_context_counts.open_parentheses) % pairing_color_size;
73  break;
74  case '[':
75  pairing_color_index = std::abs(line_color_context_counts.open_square_braces) % pairing_color_size;
76  line_color_context_counts.open_square_braces++;
77  break;
78  case ']':
79  line_color_context_counts.open_square_braces--;
80  pairing_color_index = std::abs(line_color_context_counts.open_square_braces) % pairing_color_size;
81  break;
82  case '{':
83  pairing_color_index = std::abs(line_color_context_counts.open_curly_braces) % pairing_color_size;
84  line_color_context_counts.open_curly_braces++;
85  break;
86  case '}':
87  line_color_context_counts.open_curly_braces--;
88  pairing_color_index = std::abs(line_color_context_counts.open_curly_braces) % pairing_color_size;
89  break;
90  }
91 
92  colorized_line << pairing_color[pairing_color_index] << c << termcolor::reset;
93  }
94  else
95  colorized_line << c;
96  }
97 
98  return colorized_line.str();
99  }
100 
101  std::string makeNodeBasedErrorCtx(const std::string& message, const Node& node)
102  {
103  std::stringstream ss;
104  ss << message << "\n";
105  if (node.filename() != ARK_NO_NAME_FILE)
106  ss << "In file " << node.filename() << "\n";
107  ss << "On line " << (node.line() + 1) << ":" << node.col() << ", got `" << node << "'\n";
108 
109  std::size_t ssize = 1;
110  if (node.nodeType() == NodeType::Symbol || node.nodeType() == NodeType::String || node.nodeType() == NodeType::Spread)
111  ssize = node.string().size();
112 
113  if (node.filename() != ARK_NO_NAME_FILE)
114  makeContext(ss, Utils::readFile(node.filename()), node.line(), node.col(), ssize);
115 
116  return ss.str();
117  }
118 
119  std::string makeTokenBasedErrorCtx(const std::string& match, std::size_t line, std::size_t col, const std::string& code)
120  {
121  std::stringstream ss;
122  ss << "On line " << (line + 1) << ":" << col << "\n";
123  makeContext(ss, code, line, col, match.size());
124 
125  return ss.str();
126  }
127 }
Constants used by ArkScript.
#define ARK_NO_NAME_FILE
Definition: Constants.hpp:26
Lots of utilities about the filesystem.
Lots of utilities about string, filesystem and more.
A node of an Abstract Syntax Tree for ArkScript.
Definition: Node.hpp:29
NodeType nodeType() const noexcept
Return the node type.
Definition: Node.cpp:126
const std::string & filename() const noexcept
Return the filename in which this node was created.
Definition: Node.cpp:174
const std::string & string() const noexcept
Return the string held by the value (if the node type allows it)
Definition: Node.cpp:92
std::size_t col() const noexcept
Get the column at which this node was created.
Definition: Node.cpp:169
std::size_t line() const noexcept
Get the line at which this node was created.
Definition: Node.cpp:164
Create string error context for AST errors.
std::string readFile(const std::string &name)
Helper to read a file.
Definition: Files.hpp:48
std::vector< std::string > splitString(const std::string &source, char sep)
Cut a string into pieces, given a character separator.
Definition: Utils.hpp:34
bool isPairableChar(const char c)
Check if the character passed in can be paired (parentheses, curly braces, or square braces)
std::string colorizeLine(const std::string &line, LineColorContextCounts &line_color_context_counts)
Add colors to highlight matching parentheses/curly braces/square braces on a line.
void makeContext(std::ostream &os, const std::string &code, std::size_t line, std::size_t col_start, std::size_t sym_size)
std::string makeTokenBasedErrorCtx(const std::string &match, std::size_t line, std::size_t col, const std::string &code)
Construct an error message based on a given match in the code.
std::string makeNodeBasedErrorCtx(const std::string &message, const Node &node)
Construct an error message based on a given node.