ArkScript
A small, fast, functional and scripting language for video games
Utils.cpp
Go to the documentation of this file.
1#include <CLI/REPL/Utils.hpp>
2
3#include <regex>
4#include <algorithm>
5#include <numeric>
6#include <ranges>
7
10
11namespace Ark::internal
12{
13 long countOpenEnclosures(const std::string& line, const char open, const char close)
14 {
15 return std::ranges::count(line, open) - std::ranges::count(line, close);
16 }
17
18 void trimWhitespace(std::string& line)
19 {
20 const std::size_t string_begin = line.find_first_not_of(" \t");
21 if (std::string::npos != string_begin)
22 {
23 const std::size_t string_end = line.find_last_not_of(" \t");
24 line = line.substr(string_begin, string_end - string_begin + 1);
25 }
26 }
27
28 std::vector<std::string> getAllKeywords()
29 {
30 std::vector<std::string> output;
31 output.reserve(keywords.size() + Language::listInstructions.size() + Language::operators.size() + Builtins::builtins.size() + 2);
32
33 std::ranges::transform(keywords, std::back_inserter(output), [](const auto& string_view) {
34 return std::string(string_view);
35 });
36 std::ranges::transform(Language::listInstructions, std::back_inserter(output), [](const auto& string_view) {
37 return std::string(string_view);
38 });
39 std::ranges::transform(Language::operators, std::back_inserter(output), [](const auto& string_view) {
40 return std::string(string_view);
41 });
42 std::ranges::transform(std::ranges::views::keys(Builtins::builtins), std::back_inserter(output), [](const auto& string) {
43 return string;
44 });
45
46 output.emplace_back("and");
47 output.emplace_back("or");
48
49 return output;
50 }
51
52 std::vector<std::pair<std::string, replxx::Replxx::Color>> getColorPerKeyword()
53 {
54 using namespace replxx;
55 using K = std::string;
56 using V = Replxx::Color;
57
58 std::vector<std::pair<K, V>> output;
59 output.reserve(keywords.size() + Language::listInstructions.size() + Language::operators.size() + Builtins::builtins.size() + 4);
60
61 std::ranges::transform(keywords, std::back_inserter(output), [](const auto& string_view) {
62 return std::make_pair(std::string(string_view), Replxx::Color::BRIGHTRED);
63 });
64 std::ranges::transform(Language::listInstructions, std::back_inserter(output), [](const auto& string_view) {
65 return std::make_pair(std::string(string_view), Replxx::Color::GREEN);
66 });
67 std::ranges::transform(Language::operators, std::back_inserter(output), [](const auto& string_view) {
68 auto safe_op = std::string(string_view);
69 if (const auto it = safe_op.find_first_of(R"(-+=/*<>[]()?")"); it != std::string::npos)
70 safe_op.insert(it, "\\");
71 return std::make_pair(safe_op, Replxx::Color::BRIGHTBLUE);
72 });
73 std::ranges::transform(std::ranges::views::keys(Builtins::builtins), std::back_inserter(output), [](const auto& string) {
74 return std::make_pair(string, Replxx::Color::GREEN);
75 });
76
77 output.emplace_back("and", Replxx::Color::BRIGHTBLUE);
78 output.emplace_back("or", Replxx::Color::BRIGHTBLUE);
79 output.emplace_back("[\\-|+]?[0-9]+(\\.[0-9]+)?", Replxx::Color::YELLOW);
80 output.emplace_back("\".*\"", Replxx::Color::MAGENTA);
81
82 return output;
83 }
84
85 std::size_t codepointLength(const std::string& str)
86 {
87 return std::accumulate(
88 str.begin(),
89 str.end(),
90 std::size_t { 0 },
91 [](const std::size_t acc, const char c) {
92 return acc + ((c & 0xc0) != 0x80);
93 });
94 }
95
96 std::size_t contextLen(const std::string& prefix)
97 {
98 const std::string word_break = " \t\n\r\v\f=+*&^%$#@!,./?<>;`~'\"[]{}()\\|";
99 std::size_t count = 0;
100
101 for (const auto c : std::ranges::views::reverse(prefix))
102 {
103 if (word_break.find(c) != std::string::npos)
104 break;
105 ++count;
106 }
107
108 return count;
109 }
110
111 replxx::Replxx::completions_t hookCompletion(const std::vector<std::string>& words, const std::string& context, int& length)
112 {
113 replxx::Replxx::completions_t completions;
114 std::size_t utf8_context_len = contextLen(context);
115 std::size_t prefix_len = context.size() - utf8_context_len;
116
117 if (prefix_len > 0 && context[prefix_len - 1] == '\\')
118 {
119 --prefix_len;
120 ++utf8_context_len;
121 }
122
123 length = static_cast<int>(codepointLength(context.substr(prefix_len, utf8_context_len)));
124
125 const std::string prefix = context.substr(prefix_len);
126 for (const auto& e : words)
127 {
128 if (e.starts_with(prefix) == 0)
129 completions.emplace_back(e.c_str());
130 }
131
132 return completions;
133 }
134
135 void hookColor(const std::vector<std::pair<std::string, replxx::Replxx::Color>>& words_colors, const std::string& context, replxx::Replxx::colors_t& colors)
136 {
137 // highlight matching regex sequences
138 for (const auto& [regex, color] : words_colors)
139 {
140 std::size_t pos = 0;
141 std::string str = context;
142 std::smatch match;
143
144 while (std::regex_search(str, match, std::regex(regex)))
145 {
146 std::string c = match[0];
147 std::string prefix = match.prefix().str();
148 const std::size_t len = codepointLength(c);
149
150 pos += codepointLength(prefix);
151 for (std::size_t i = 0; i < len; ++i)
152 colors.at(pos + i) = color;
153
154 pos += len;
155 str = match.suffix();
156 }
157 }
158 }
159
160 replxx::Replxx::hints_t hookHint(const std::vector<std::string>& words, const std::string& context, int& length, replxx::Replxx::Color& color)
161 {
162 replxx::Replxx::hints_t hints;
163 // only show hint if prefix is at least 'n' chars long
164 // or if prefix begins with a specific character
165 const std::size_t utf8_context_len = contextLen(context);
166 const std::size_t prefix_len = context.size() - utf8_context_len;
167 length = static_cast<int>(codepointLength(context.substr(prefix_len, utf8_context_len)));
168 const std::string prefix = context.substr(prefix_len);
169
170 if (prefix.size() >= 2 || (!prefix.empty() && prefix.at(0) == '.'))
171 {
172 for (const auto& e : words)
173 {
174 if (e.compare(0, prefix.size(), prefix) == 0)
175 hints.emplace_back(e.c_str());
176 }
177 }
178
179 if (hints.size() == 1)
180 color = replxx::Replxx::Color::GREEN;
181
182 return hints;
183 }
184}
Host the declaration of all the ArkScript builtins.
replxx utilities
Common code for the compiler.
ARK_API const std::vector< std::pair< std::string, Value > > builtins
constexpr std::array< std::string_view, 9 > listInstructions
Definition Common.hpp:115
constexpr std::array< std::string_view, 24 > operators
Definition Common.hpp:150
std::vector< std::string > getAllKeywords()
Compute a list of all the language keywords and builtins.
long countOpenEnclosures(const std::string &line, char open, char close)
Count the open enclosure and its counterpart: (), {}, [].
void hookColor(const std::vector< std::pair< std::string, replxx::Replxx::Color > > &words_colors, const std::string &context, replxx::Replxx::colors_t &colors)
constexpr std::array colors
Definition Logger.cpp:8
replxx::Replxx::completions_t hookCompletion(const std::vector< std::string > &words, const std::string &context, int &length)
std::vector< std::pair< std::string, replxx::Replxx::Color > > getColorPerKeyword()
Compute a list of pairs (word -> color) to be used for coloration by the REPL.
replxx::Replxx::hints_t hookHint(const std::vector< std::string > &words, const std::string &context, int &length, replxx::Replxx::Color &color)
void trimWhitespace(std::string &line)
Remove whitespaces at the start and end of a string.
constexpr std::array< std::string_view, 9 > keywords
List of available keywords in ArkScript.
Definition Common.hpp:88