header_utils
Loading...
Searching...
No Matches
lib_core.h
1#pragma once
2
3#include "../eval.h"
4#include <print>
5
6namespace ghassanpl::eval
7{
8 template <bool DECADE_SYNTAX>
9 struct base_lib
10 {
11 using enum nlohmann::json::value_t;
12 static constexpr nlohmann::json::value_t any = nlohmann::json::value_t::discarded;
13
14 using env_type = environment<DECADE_SYNTAX>;
15 using json_pointer = nlohmann::json::json_pointer;
16
17 static json_pointer make_pointer(json const& index)
18 {
19 json_pointer ptr;
20 switch (index.type())
21 {
22 case string: ptr /= std::string{ index }; return ptr;
23 case number_float: ptr /= int(float(index)); return ptr;
24 case number_integer: ptr /= int(index); return ptr;
25 case number_unsigned: ptr /= int(index); return ptr;
26 case array: {
27 for (auto& e : index)
28 ptr /= make_pointer(e);
29 return ptr;
30 }
31 default: break;
32 }
33 throw std::runtime_error(std::format("invalid value index type '{}'", index.type_name()));
34 }
35
36 };
37
38 template <bool DECADE_SYNTAX>
39 struct lib_core : public base_lib<DECADE_SYNTAX>
40 {
41 using enum nlohmann::json::value_t;
42
43 using base_type = base_lib<DECADE_SYNTAX>;
44 using env_type = base_type::env_type;
45 using json_pointer = base_type::json_pointer;
46
47 static inline value if_then_else(env_type& e, std::vector<value> args)
48 {
49 e.assert_args(args, 3);
50 if (e.is_true(e.eval_arg(args, 1)))
51 return e.eval_arg(args, 2);
52 return e.eval_arg(args, 3);
53 }
54
55 struct e_break : env_type::e_scope_terminator { virtual std::string_view type() const noexcept override { return "break"; } };
56 struct e_continue : env_type::e_scope_terminator { virtual std::string_view type() const noexcept override { return "continue"; } };
57
58 static inline value while_do(env_type& e, std::vector<value> args)
59 {
60 e.assert_args(args, 2);
61 value last = null_json;
62 while (e.is_true(e.eval(args[1])))
63 {
64 try
65 {
66 last = e.eval(args[2]);
67 }
68 catch (e_break const& ex)
69 {
70 if (!ex.result->is_discarded())
71 last = ex.result;
72 break;
73 }
74 catch (e_continue const& ex)
75 {
76 if (!ex.result->is_discarded())
77 last = ex.result;
78 continue;
79 }
80 }
81 return last;
82 }
83
84 static inline value while_do_rev(env_type& e, std::vector<value> args)
85 {
86 e.assert_args(args, 2);
87 std::swap(args[1], args[2]);
88 return while_do(e, std::move(args));
89 }
90
91 static inline value loop_break(env_type& e, std::vector<value> args)
92 {
93 e.assert_args(args, 0, 1);
94 e_break ex{};
95 if (args.size() == 2) ex.result = e.eval_arg(args, 1);
96 throw ex;
97 }
98
99 static inline value var_get(env_type& e, std::vector<value> args)
100 {
101 auto name = e.eval_arg(args, 1, string);
102 return e.user_var(*name);
103 }
104
105 static inline value var_set(env_type& e, std::vector<value> args)
106 {
107 auto var = e.eval_arg(args, 1);
108 if (!var.is_lval())
109 return e.report_error("trying to assign to a non-variable");
110 var.lval() = e.eval_arg(args, 2).forward();
111 return var;
112 }
113
114 static inline value new_var(env_type& e, std::vector<value> args)
115 {
116 e.assert_args(args, 2, 3);
117 auto name = e.eval_arg(args, 1, string);
118 auto val = args.size() == 3 ? e.eval_arg(args, 2) : value(null_json);
119 return &e.set_user_var(*name, std::move(val), true);
120 }
121
122 static inline value get_of(env_type& e, std::vector<value> args)
123 {
125
126 e.eval_args(args, 2);
127 const json_pointer index = base_type::make_pointer(args[1]);
128 value& container = args[2];
129 if (!container->contains(index))
130 return null_json;
131 switch (container.v.index())
132 {
133 case 0: return std::move(std::get<json>(container.v).at(index));
134 case 1: return &std::get<json*>(container.v)->at(index);
135 case 2: return &std::get<json const*>(container.v)->at(index);
136 }
137 return e.report_error("internal error: container value is invalid");
138 }
139
140 static inline value get_of_inv(env_type& e, std::vector<value> args)
141 {
142 e.assert_args(args, 2);
143 std::swap(args[1], args[2]);
144 return get_of(e, std::move(args));
145 }
146
148 static inline value eval(env_type& e, std::vector<value> args)
149 {
150 value last = null_json;
151 for (auto& arg : std::span{ args }.subspan(1))
152 last = e.eval(std::move(arg));
153 return last;
154 }
155
157 static inline value list(env_type& e, std::vector<value> args)
158 {
159 e.eval_args(args);
160 std::vector<json> result;
161 for (auto& arg : std::span{ args }.subspan(1))
162 result.push_back(arg.forward());
163 return value(std::move(result));
164 }
165
166 static inline value quote(env_type& e, std::vector<value> args) { e.assert_args(args, 1); return std::move(args[1]); }
167
168 static inline value op_eq(env_type& e, std::vector<value> args) { e.eval_args(args, 2); return *args[1] == *args[2]; }
169 static inline value op_neq(env_type& e, std::vector<value> args) { e.eval_args(args, 2); return *args[1] != *args[2]; }
170 static inline value op_gt(env_type& e, std::vector<value> args) { e.eval_args(args, 2); return *args[1] > *args[2]; }
171 static inline value op_ge(env_type& e, std::vector<value> args) { e.eval_args(args, 2); return *args[1] >= *args[2]; }
172 static inline value op_lt(env_type& e, std::vector<value> args) { e.eval_args(args, 2); return *args[1] < *args[2]; }
173 static inline value op_le(env_type& e, std::vector<value> args) { e.eval_args(args, 2); return *args[1] <= *args[2]; }
174
175 static inline value op_not(env_type& e, std::vector<value> args) { e.eval_args(args, 1); return !e.is_true(args[1]); }
176 static inline value op_and(env_type& e, std::vector<value> args) {
177 e.assert_min_args(args, 2);
178 value left;
179 for (size_t i = 1; i < args.size(); ++i)
180 {
181 left = e.eval_arg(args, i);
182 if (!e.is_true(left))
183 return left;
184 }
185 return left;
186 }
187 static inline value op_or(env_type& e, std::vector<value> args) {
188 e.assert_min_args(args, 2);
189 value left;
190 for (size_t i = 1; i < args.size(); ++i)
191 {
192 left = e.eval_arg(args, i);
193 if (e.is_true(left))
194 return left;
195 }
196 return left;
197 }
198
199 static inline value op_plus(env_type& e, std::vector<value> args) { e.eval_args(args, 2); return *args[1] + *args[2]; }
200 static inline value op_minus(env_type& e, std::vector<value> args) { e.eval_args(args, 2); return *args[1] - *args[2]; }
201 static inline value op_mul(env_type& e, std::vector<value> args) { e.eval_args(args, 2); return *args[1] * *args[2]; }
202 static inline value op_div(env_type& e, std::vector<value> args) { e.eval_args(args, 2); return *args[1] / *args[2]; }
203 static inline value op_mod(env_type& e, std::vector<value> args) { e.eval_args(args, 2); return *args[1] % *args[2]; }
204
205 static inline value type_of(env_type& e, std::vector<value> args) {
206 const auto val = e.eval_arg(args, 1);
207 return val->type_name();
208 }
209 static inline value size_of(env_type& e, std::vector<value> args) {
210 const auto val = e.eval_arg(args, 1);
211 const json& j = val;
212 return j.is_string() ? j.get_ref<json::string_t const&>().size() : j.size();
213 }
214
215 static inline std::string stringify(value const& arg, std::string_view fmt = "{}")
216 {
217 return ghassanpl::formats::json::visit(arg.ref(), [&](auto const& val) {
218 if constexpr (std::is_same_v<std::remove_cvref_t<decltype(val)>, nlohmann::json::array_t>)
219 return std::vformat(fmt, std::make_format_args(arg->dump()));
220 else if constexpr (std::is_same_v<std::remove_cvref_t<decltype(val)>, nlohmann::json::object_t>)
221 return std::vformat(fmt, std::make_format_args(arg->dump()));
222 else if constexpr (std::is_same_v<std::remove_cvref_t<decltype(val)>, nlohmann::json::binary_t>)
223 return std::vformat(fmt, std::make_format_args(arg->dump()));
224 else if constexpr (std::is_same_v<std::remove_cvref_t<decltype(val)>, nullptr_t>)
225 return "null"s;
226 else
227 return std::vformat(fmt, std::make_format_args(val));
228 });
229 }
230
231
232 static inline value str(env_type& e, std::vector<value> args)
233 {
234 auto arg = e.eval_arg(args, 1);
235 return stringify(arg);
236 }
237
238 static inline value format(env_type& e, std::vector<value> args)
239 {
240 e.assert_min_args(args, 1);
241 e.eval_args(args);
242
243 return string_ops::callback_format(args[1].ref(), [&](size_t index, std::string_view fmt, std::string& output) {
244 auto& arg = args[2 + index];
245 output += stringify(arg, fmt);
246 });
247 }
248
249 static inline value print(env_type& e, std::vector<value> args)
250 {
251 e.assert_args(args, 1);
252 auto fmted = format(e, std::move(args));
253 std::print("{}", fmted->template get_ref<nlohmann::json::string_t const&>());
254 return null_json;
255 }
256
257 static inline value println(env_type& e, std::vector<value> args)
258 {
259 e.assert_args(args, 1);
260 auto fmted = format(e, std::move(args));
261 std::println("{}", fmted->template get_ref<nlohmann::json::string_t const&>());
262 return null_json;
263 }
264
265 static inline json prefix_macro_get(env_type const&, std::vector<value> args) {
266 return json{ "get", string_view{args[0]}.substr(1) };
267 };
268
269 static inline void set_macro_prefix_get(env_type& e, std::string const& prefix = ".", std::string const& prefix_eval_func_name = "dot", std::string const& get_func_name = "get")
270 {
271 e.prefix_macros[prefix] = [get_func_name, prefix_size = prefix.size()](env_type const& e, std::vector<value> args) {
272 return json{ get_func_name, std::string{*args[0]}.substr(prefix_size) };
273 };
274 e.funcs[prefix_eval_func_name] = [prefix](env_type const& e, std::vector<value>) -> value {
275 return prefix;
276 };
277 }
278
279 static void import_to(env_type& e)
280 {
281 e.funcs["list"] = list;
282 e.funcs["eval"] = eval;
283 e.funcs["break"] = loop_break;
284 set_macro_prefix_get(e);
285
286 if constexpr (DECADE_SYNTAX)
287 {
288 e.funcs["if:then:else:"] = if_then_else;
289 e.funcs[":?:::"] = if_then_else;
290 e.funcs["while:do:"] = while_do;
291 e.funcs[":while:"] = while_do_rev;
292 e.funcs["break:"] = loop_break;
293
294 e.funcs["get:"] = var_get;
295 e.funcs["get:of:"] = get_of;
296 e.funcs[":@:"] = get_of_inv;
297 e.funcs[":at:"] = get_of_inv;
298 e.funcs[":=:"] = var_set;
299 e.funcs["var:"] = new_var;
300 e.funcs["var:=:"] = new_var;
301 e.funcs["list:"] = list;
302 e.funcs["list:,:"] = list;
303 e.funcs["list:,*:"] = list;
304 e.funcs["eval:"] = eval;
305 e.funcs["eval:,:"] = eval;
306 e.funcs["eval:,*:"] = eval;
307 e.funcs[":==:"] = op_eq;
308 e.funcs[":eq:"] = op_eq;
309 e.funcs[":!=:"] = op_neq;
310 e.funcs[":neq:"] = op_neq;
311 e.funcs[":>:"] = op_gt;
312 e.funcs[":gt:"] = op_gt;
313 e.funcs[":>=:"] = op_ge;
314 e.funcs[":ge:"] = op_ge;
315 e.funcs[":<:"] = op_lt;
316 e.funcs[":lt:"] = op_lt;
317 e.funcs[":<=:"] = op_le;
318 e.funcs[":le:"] = op_le;
319 e.funcs["not:"] = op_not;
320 e.funcs[":and*:"] = op_and;
321 e.funcs[":and:"] = op_and;
322 e.funcs[":or:"] = op_or;
323 e.funcs[":or*:"] = op_or;
324 e.funcs[":+:"] = op_plus;
325 e.funcs["type-of:"] = type_of;
326 e.funcs["typeof:"] = type_of;
327 e.funcs["size-of:"] = size_of;
328 e.funcs["sizeof:"] = size_of;
329 e.funcs["#:"] = size_of;
330
331 e.funcs["str:"] = str;
332
333 e.funcs["format:"] = format;
334 e.funcs["format:,:"] = format;
335 e.funcs["format:,*:"] = format;
336
337 e.funcs["print:"] = print;
338 e.funcs["print:,:"] = print;
339 e.funcs["print:,*:"] = print;
340
341 e.funcs["println:"] = println;
342 e.funcs["println:,:"] = println;
343 e.funcs["println:,*:"] = println;
344 }
345 }
346 };
347
348
349
363}
constexpr auto bit_count
Equal to the number of bits in the type.
Definition bits.h:33
auto visit(nlohmann::json const &j, VISIT_FUNC &&func)
Calls func with the actual value inside j; similar to std::visit
std::string_view prefix(std::string_view str, size_t count) noexcept
Returns a substring containing the count leftmost characters of str. Always valid,...
Definition string_ops.h:571