header_utils
Loading...
Searching...
No Matches
wilson.h
1
4
5#pragma once
6
7#include "parsing.h"
8#include "mmap.h"
9#include "json_helpers.h"
10#include <ostream>
11
13
15{
16 auto parse(std::string_view wilson_str) -> nlohmann::json;
17 auto parse_object(std::string_view wilson_str, char closing_char = '}') -> nlohmann::json;
18 auto parse_array(std::string_view wilson_str) -> nlohmann::json;
20 auto parse_word_or_string(std::string_view wilson_str) -> nlohmann::json;
22 auto parse_string_value(std::string_view wilson_str) -> std::string;
24 auto parse_string_literal(std::string_view wilson_str) -> std::string;
25
26 auto consume_string_literal(std::string_view& _str) -> std::string;
27 auto consume_string_value(std::string_view& str) -> std::string;
28 auto consume_word_or_string(std::string_view& str) -> nlohmann::json;
29 auto consume_object(std::string_view& wilson_str, char closing_char = '}') -> nlohmann::json;
30 auto consume_array(std::string_view& wilson_str, char closing_char = ']') -> nlohmann::json;
31 auto consume_value(std::string_view& wilson_str) -> nlohmann::json;
32
33 template <typename OUTFUNC>
34 void output(OUTFUNC&& out, nlohmann::json const& value);
35
36 inline void output_to_stream(std::ostream& strm, nlohmann::json const& value)
37 {
38 output([&](std::string_view val) { strm.write(val.data(), val.size()); }, value);
39 }
40
41 std::string to_string(nlohmann::json const& value);
42
43 nlohmann::json load_file(std::filesystem::path const& from, std::error_code& ec);
44 nlohmann::json try_load_file(std::filesystem::path const& from, nlohmann::json const& or_json = json::empty_json);
45}
46
48{
49 inline nlohmann::json consume_array(std::string_view& str, char closing_char)
50 {
51 auto obj = nlohmann::json::array();
52 do
53 {
54 string_ops::trim_whitespace_left(str);
56 return obj;
57
58 obj.push_back(wilson::consume_value(str));
59
60 string_ops::trim_whitespace_left(str);
61
62 if (!str.empty() && (str[0] == ',' || str[0] == ';'))
63 str.remove_prefix(1);
64
65 } while (!str.empty());
66 return obj;
67 }
68
70 inline std::string consume_string_literal(std::string_view& _str)
71 {
72 std::pair<std::string_view, std::string> result;
73 if (_str[0] == '\'')
74 result = parsing::consume_c_string<'\''>(_str);
75 else
76 result = parsing::consume_c_string<'"'>(_str);
77 return std::move(result).second;
78 }
79
81 inline std::string consume_string_value(std::string_view& str)
82 {
83 string_ops::trim_whitespace_left(str);
84 const auto first = str[0];
85 if (first == '\'' || first == '"')
86 return consume_string_literal(str);
87 else if (string_ops::ascii::isidentstart(first))
88 return std::string{ string_ops::consume_while(str, &string_ops::ascii::isident) };
89
90 return {};
91 }
92
94 inline nlohmann::json consume_word_or_string(std::string_view& str)
95 {
96 if (string_ops::ascii::isalpha(str[0]))
97 {
98 auto string = consume_string_value(str);
99 if (string == "true")
100 return true;
101 else if (string == "false")
102 return false;
103 else if (string == "null" || string == "nil")
104 return nullptr;
105 return string;
106 }
107 else
108 {
109 return consume_string_value(str);
110 }
111 }
112
113 inline nlohmann::json consume_object(std::string_view& str, char closing_char)
114 {
115 auto obj = nlohmann::json::object();
116
117 do
118 {
119 string_ops::trim_whitespace_left(str);
121 return obj;
122
123 auto key = consume_string_value(str);
124 string_ops::trim_whitespace_left(str);
125
126 if (str.empty() || string_ops::consume(str, closing_char))
127 {
128 obj[std::move(key)] = true;
129 break;
130 }
131
132 if (str[0] == ',' || str[0] == ';')
133 {
134 obj[std::move(key)] = true;
135 }
136 else
137 {
138 if (str[0] == '=' || str[0] == ':')
139 str.remove_prefix(1);
140
141 string_ops::trim_whitespace_left(str);
142
143 auto val = wilson::consume_value(str);
144 obj[std::move(key)] = std::move(val);
145 }
146
147 string_ops::trim_whitespace_left(str);
148
149 if (!str.empty() && (str[0] == ',' || str[0] == ';'))
150 str.remove_prefix(1);
151 } while (!str.empty());
152
153 return obj;
154 }
155
156 inline nlohmann::json consume_value(std::string_view& str)
157 {
158 string_ops::trim_whitespace_left(str);
159 if (str.empty()) return {};
160
161 const auto first = str[0];
162 if (string_ops::consume(str, '{'))
163 return consume_object(str);
164 else if (string_ops::consume(str, '('))
165 return consume_array(str, ')');
166 else if (string_ops::consume(str, '['))
167 return consume_array(str, ']');
168 else if (string_ops::ascii::isidentstart(first) || first == '\'' || first == '"')
169 return consume_word_or_string(str);
170 else if (string_ops::ascii::isdigit(first) || first == '-')
171 {
172 double result = 0;
173 const auto fcresult = string_ops::from_chars(str, result);
174 if (fcresult.ec == std::errc{})
175 {
176 str = string_ops::make_sv(fcresult.ptr, str.end());
177 return result;
178 }
179 }
181 return std::string(1, string_ops::consume(str));
182 }
183
184 inline auto parse(std::string_view wilson_str) -> nlohmann::json
185 {
186 const auto start = wilson_str.data();
187 return wilson::consume_value(wilson_str);
188 }
189
190 inline auto parse_object(std::string_view wilson_str, char closing_char) -> nlohmann::json
191 {
192 return wilson::consume_object(wilson_str, closing_char);
193 }
194
195 inline auto parse_array(std::string_view wilson_str) -> nlohmann::json
196 {
197 return wilson::consume_array(wilson_str);
198 }
199
200 inline auto parse_word_or_string(std::string_view wilson_str) -> nlohmann::json
201 {
203 }
204
205 inline auto parse_string_value(std::string_view wilson_str) -> std::string
206 {
208 }
209
210 inline auto parse_string_literal(std::string_view wilson_str) -> std::string
211 {
213 }
214
215 namespace detail
216 {
217 template <typename OUTFUNC, typename VAL>
218 void output_value(OUTFUNC&& func, VAL const& val)
219 {
220 char temp_buffer[32]{};
221 auto&& [end, ec] = std::to_chars(std::begin(temp_buffer), std::end(temp_buffer), val);
222 func(string_ops::make_sv(std::begin(temp_buffer), end));
223 }
224
225 template <typename OUTFUNC>
226 void output_string(OUTFUNC&& func, std::string_view strval)
227 {
228 func("\"");
229 std::string buf;
230 char temp[8]{};
231 auto start = strval.begin();
232 for (auto it = strval.begin(); it != strval.end(); ++it)
233 {
234 if (string_ops::ascii::isprint(*it) && *it != '"' && *it != '\\')
235 continue;
236 else
237 {
238 if (start != it)
239 func(string_ops::make_sv(start, it));
240
241 func("\\x");
242 auto&& [end, ec] = std::to_chars(std::begin(temp), std::end(temp), static_cast<uint8_t>(*it), 16);
243 func(string_ops::make_sv(std::begin(temp), end));
244
245 start = std::next(it);
246 }
247 }
248 if (start != strval.end())
249 func(string_ops::make_sv(start, strval.end()));
250 func("\"");
251 }
252 }
253
254 template <typename OUTFUNC>
255 void output(OUTFUNC&& out, nlohmann::json const& value)
256 {
257 switch (value.type())
258 {
259 using enum nlohmann::detail::value_t;
260 case null: out("null"); return;
261 case object:
262 out("{ ");
263 for (auto& [k, v] : value.get_ref<nlohmann::json::object_t const&>())
264 {
265 wilson::detail::output_string(out, k);
266 out(": ");
267 wilson::output(out, v);
268 out(", ");
269 }
270 out(" }");
271 return;
272 case array:
273 out("[ ");
274 for (auto& obj : value.get_ref<nlohmann::json::array_t const&>())
275 {
276 wilson::output(out, obj);
277 out(", ");
278 }
279 out(" ]");
280 return;
281 case string: wilson::detail::output_string(out, value.get_ref<nlohmann::json::string_t const&>()); return;
282 case boolean: out(value.get_ref<nlohmann::json::boolean_t const&>() ? "true" : "false"); return;
283 case number_integer: wilson::detail::output_value(out, value.get_ref<nlohmann::json::number_integer_t const&>()); return;
284 case number_unsigned: wilson::detail::output_value(out, value.get_ref<nlohmann::json::number_unsigned_t const&>()); return;
285 case number_float: wilson::detail::output_value(out, value.get_ref<nlohmann::json::number_float_t const&>()); return;
286 case binary:
287 out("[ ");
288 for (auto byte : value.get_ref<nlohmann::json::binary_t const&>())
289 {
290 wilson::detail::output_value(out, byte);
291 out(", ");
292 }
293 out(" ]");
294 return;
295 case discarded: return;
296 }
297 }
298
299 inline std::string to_string(nlohmann::json const& value)
300 {
301 std::string result;
302 wilson::output([&](std::string_view val) { result += val; }, value);
303 return result;
304 }
305
306 inline nlohmann::json load_file(std::filesystem::path const& from, std::error_code& ec)
307 {
308 const auto source = ghassanpl::make_mmap_source<char>(from, ec);
309 return ec ? nlohmann::json{} : wilson::parse(std::string_view{ source.begin(), source.end() });
310 }
311
312 inline nlohmann::json try_load_file(std::filesystem::path const& from, nlohmann::json const& or_json)
313 {
314 std::error_code ec;
315 const auto source = ghassanpl::make_mmap_source<char>(from, ec);
316 return ec ? or_json : wilson::parse(std::string_view{ source.begin(), source.end() });
317 }
318}
constexpr auto bit_count
Equal to the number of bits in the type.
Definition bits.h:33
std::string_view consume_while(std::string_view &str, FUNC &&pred)
Consumes characters from the beginning of str while they match pred(str[0]).
Definition string_ops.h:755
auto from_chars(std::string_view str, T &value, const int base=10) noexcept
A version of std::from_chars that takes a std::string_view as the first argument.
char consume(std::string_view &str)
Consumes and returns the first character in the str, or \0 if no more characters.
Definition string_ops.h:652
std::string load_file(std::filesystem::path const &from, std::error_code &ec)
Returns the contents of a text file as a string.
expected< std::string, std::error_code > try_load_file(std::filesystem::path const &from)
Returns the contents of a text file as a string.
The below code is based on Sun's libm library code, which is licensed under the following license:
auto consume_value(std::string_view &sexp_str, std::array< char, 2 > braces={ '[', ']' }) -> nlohmann::json
Consumes [list] or atom; a ',' (comma character) is considered its own atom.
Definition sexps.h:104
TODO: https://dev.stenway.com/SML/Examples.html.
Definition wilson.h:15
auto parse_string_literal(std::string_view wilson_str) -> std::string
Parses a string literal as a string value.
Definition wilson.h:210
auto consume_string_value(std::string_view &str) -> std::string
Consumes a word or a string literal returning a string value.
Definition wilson.h:81
auto parse_word_or_string(std::string_view wilson_str) -> nlohmann::json
Parses: a word as a string value or bool/null value; a "string literal" as a string value.
Definition wilson.h:200
auto parse_string_value(std::string_view wilson_str) -> std::string
Parses a word or a string literal a string value.
Definition wilson.h:205
auto consume_string_literal(std::string_view &_str) -> std::string
Consumes a string literal returning a string value.
Definition wilson.h:70
auto consume_word_or_string(std::string_view &str) -> nlohmann::json
Consumes: a word, returning a string/bool/null value; or a "string literal", returning a string value...
Definition wilson.h:94