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/proxy.hpp>
6
7#include <Ark/Constants.hpp>
8#include <Ark/Files.hpp>
9#include <Ark/Utils.hpp>
10
11namespace 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\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.