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
40 template <bool DECADE_SYNTAX>
41 struct lib_core : public base_lib<DECADE_SYNTAX>
42 {
43 using enum nlohmann::json::value_t;
44
45 using base_type = base_lib<DECADE_SYNTAX>;
46 using env_type = base_type::env_type;
47 using json_pointer = base_type::json_pointer;
48
49 private:
50
51 static inline value if_then_else(env_type& e, std::vector<value> args)
52 {
53 e.assert_args(args, 3);
54 if (e.is_true(e.eval_arg(args, 1)))
55 return e.eval_arg(args, 2);
56 return e.eval_arg(args, 3);
57 }
58
59 struct e_break : env_type::e_scope_terminator { virtual std::string_view type() const noexcept override { return "break"; } };
60 struct e_continue : env_type::e_scope_terminator { virtual std::string_view type() const noexcept override { return "continue"; } };
61
62 static inline value while_do(env_type& e, std::vector<value> args)
63 {
64 e.assert_args(args, 2);
65 value last = null_json;
66 while (e.is_true(e.eval(args[1])))
67 {
68 try
69 {
70 last = e.eval(args[2]);
71 }
72 catch (e_break const& ex)
73 {
74 if (!ex.result->is_discarded())
75 last = ex.result;
76 break;
77 }
78 catch (e_continue const& ex)
79 {
80 if (!ex.result->is_discarded())
81 last = ex.result;
82 continue;
83 }
84 }
85 return last;
86 }
87
88 static inline value while_do_rev(env_type& e, std::vector<value> args)
89 {
90 e.assert_args(args, 2);
91 std::swap(args[1], args[2]);
92 return while_do(e, std::move(args));
93 }
94
95 static inline value loop_break(env_type& e, std::vector<value> args)
96 {
97 e.assert_args(args, 0, 1);
98 e_break ex{};
99 if (args.size() == 2) ex.result = e.eval_arg(args, 1);
100 throw ex;
101 }
102
103 static inline value var_get(env_type& e, std::vector<value> args)
104 {
105 auto name = e.eval_arg(args, 1, string);
106 return e.user_var(*name);
107 }
108
109 static inline value var_set(env_type& e, std::vector<value> args)
110 {
111 auto var = e.eval_arg(args, 1);
112 if (!var.is_lval())
113 return e.report_error("trying to assign to a non-variable");
114 var.lval() = e.eval_arg(args, 2).forward();
115 return var;
116 }
117
118 static inline value new_var(env_type& e, std::vector<value> args)
119 {
120 e.assert_args(args, 2, 3);
121 auto name = e.eval_arg(args, 1, string);
122 auto val = args.size() == 3 ? e.eval_arg(args, 2) : value(null_json);
123 return &e.set_user_var(*name, std::move(val), true);
124 }
125
126 static inline value get_of(env_type& e, std::vector<value> args)
127 {
129
130 e.eval_args(args, 2);
131 const json_pointer index = base_type::make_pointer(args[1]);
132 value& container = args[2];
133 if (!container->contains(index))
134 return null_json;
135 switch (container.v.index())
136 {
137 case 0: return std::move(std::get<json>(container.v).at(index));
138 case 1: return &std::get<json*>(container.v)->at(index);
139 case 2: return &std::get<json const*>(container.v)->at(index);
140 }
141 return e.report_error("internal error: container value is invalid");
142 }
143
144 static inline value get_of_inv(env_type& e, std::vector<value> args)
145 {
146 e.assert_args(args, 2);
147 std::swap(args[1], args[2]);
148 return get_of(e, std::move(args));
149 }
150
152 static inline value eval(env_type& e, std::vector<value> args)
153 {
154 value last = null_json;
155 for (auto& arg : std::span{ args }.subspan(1))
156 last = e.eval(std::move(arg));
157 return last;
158 }
159
161 static inline value list(env_type& e, std::vector<value> args)
162 {
163 e.eval_args(args);
164 std::vector<json> result;
165 for (auto& arg : std::span{ args }.subspan(1))
166 result.push_back(arg.forward());
167 return value(std::move(result));
168 }
169
170 static inline value quote(env_type& e, std::vector<value> args) { e.assert_args(args, 1); return std::move(args[1]); }
171
172 static inline value op_eq(env_type& e, std::vector<value> args) { e.eval_args(args, 2); return *args[1] == *args[2]; }
173 static inline value op_neq(env_type& e, std::vector<value> args) { e.eval_args(args, 2); return *args[1] != *args[2]; }
174 static inline value op_gt(env_type& e, std::vector<value> args) { e.eval_args(args, 2); return *args[1] > *args[2]; }
175 static inline value op_ge(env_type& e, std::vector<value> args) { e.eval_args(args, 2); return *args[1] >= *args[2]; }
176 static inline value op_lt(env_type& e, std::vector<value> args) { e.eval_args(args, 2); return *args[1] < *args[2]; }
177 static inline value op_le(env_type& e, std::vector<value> args) { e.eval_args(args, 2); return *args[1] <= *args[2]; }
178
179 static inline value op_not(env_type& e, std::vector<value> args) { e.eval_args(args, 1); return !e.is_true(args[1]); }
180 static inline value op_and(env_type& e, std::vector<value> args) {
181 e.assert_min_args(args, 2);
182 value left;
183 for (size_t i = 1; i < args.size(); ++i)
184 {
185 left = e.eval_arg(args, i);
186 if (!e.is_true(left))
187 return left;
188 }
189 return left;
190 }
191 static inline value op_or(env_type& e, std::vector<value> args) {
192 e.assert_min_args(args, 2);
193 value left;
194 for (size_t i = 1; i < args.size(); ++i)
195 {
196 left = e.eval_arg(args, i);
197 if (e.is_true(left))
198 return left;
199 }
200 return left;
201 }
202
203 /*
204 auto perform_op()
205 {
206 if (lhs_type == value_t::number_integer && rhs_type == value_t::number_float)
207 return static_cast<number_float_t>(lhs.m_data.m_value.number_integer) op rhs.m_data.m_value.number_float;
208 else if (lhs_type == value_t::number_float && rhs_type == value_t::number_integer)
209 return lhs.m_data.m_value.number_float op static_cast<number_float_t>(rhs.m_data.m_value.number_integer);
210 else if (lhs_type == value_t::number_unsigned && rhs_type == value_t::number_float)
211 return static_cast<number_float_t>(lhs.m_data.m_value.number_unsigned) op rhs.m_data.m_value.number_float;
212 else if (lhs_type == value_t::number_float && rhs_type == value_t::number_unsigned)
213 return lhs.m_data.m_value.number_float op static_cast<number_float_t>(rhs.m_data.m_value.number_unsigned);
214 else if (lhs_type == value_t::number_unsigned && rhs_type == value_t::number_integer)
215 return static_cast<number_integer_t>(lhs.m_data.m_value.number_unsigned) op rhs.m_data.m_value.number_integer;
216 else if (lhs_type == value_t::number_integer && rhs_type == value_t::number_unsigned)
217 return lhs.m_data.m_value.number_integer op static_cast<number_integer_t>(rhs.m_data.m_value.number_unsigned);
218 }
219 */
220
221 /*
222 static inline value op_plus(env_type& e, std::vector<value> args) { e.eval_args(args, 2); return *args[1] + *args[2]; }
223 static inline value op_minus(env_type& e, std::vector<value> args) { e.eval_args(args, 2); return *args[1] - *args[2]; }
224 static inline value op_mul(env_type& e, std::vector<value> args) { e.eval_args(args, 2); return *args[1] * *args[2]; }
225 static inline value op_div(env_type& e, std::vector<value> args) { e.eval_args(args, 2); return *args[1] / *args[2]; }
226 static inline value op_mod(env_type& e, std::vector<value> args) { e.eval_args(args, 2); return *args[1] % *args[2]; }
227 */
228
229 static inline value type_of(env_type& e, std::vector<value> args) {
230 const auto val = e.eval_arg(args, 1);
231 return val->type_name();
232 }
233 static inline value size_of(env_type& e, std::vector<value> args) {
234 const auto val = e.eval_arg(args, 1);
235 const json& j = val;
236 return j.is_string() ? j.get_ref<json::string_t const&>().size() : j.size();
237 }
238
239 static inline std::string stringify(value const& arg, std::string_view fmt = "{}")
240 {
241 return ghassanpl::formats::json::visit(arg.ref(), [&](auto const& val) {
242 if constexpr (std::is_same_v<std::remove_cvref_t<decltype(val)>, nlohmann::json::array_t>)
243 {
244 auto dump = arg->dump();
245 return std::vformat(fmt, std::make_format_args(dump));
246 }
247 else if constexpr (std::is_same_v<std::remove_cvref_t<decltype(val)>, nlohmann::json::object_t>)
248 {
249 auto dump = arg->dump();
250 return std::vformat(fmt, std::make_format_args(dump));
251 }
252 else if constexpr (std::is_same_v<std::remove_cvref_t<decltype(val)>, nlohmann::json::binary_t>)
253 {
254 auto dump = arg->dump();
255 return std::vformat(fmt, std::make_format_args(dump));
256 }
257 else if constexpr (std::is_same_v<std::remove_cvref_t<decltype(val)>, nullptr_t>)
258 return std::string{ "null" };
259 else
260 return std::vformat(fmt, std::make_format_args(val));
261 });
262 }
263
264
265 static inline value str(env_type& e, std::vector<value> args)
266 {
267 auto arg = e.eval_arg(args, 1);
268 return stringify(arg);
269 }
270
271 static inline value format(env_type& e, std::vector<value> args)
272 {
273 e.assert_min_args(args, 1);
274 e.eval_args(args);
275
276 return string_ops::callback_format(args[1].ref(), [&](size_t index, std::string_view fmt, std::string& output) {
277 auto& arg = args[2 + index];
278 output += stringify(arg, fmt);
279 });
280 }
281
282 static inline value print(env_type& e, std::vector<value> args)
283 {
284 e.assert_args(args, 1);
285 auto fmted = format(e, std::move(args));
286 std::print("{}", fmted->template get_ref<nlohmann::json::string_t const&>());
287 return null_json;
288 }
289
290 static inline value println(env_type& e, std::vector<value> args)
291 {
292 e.assert_args(args, 1);
293 auto fmted = format(e, std::move(args));
294 std::println("{}", fmted->template get_ref<nlohmann::json::string_t const&>());
295 return null_json;
296 }
297
298 static inline json prefix_macro_get(env_type const&, std::vector<value> args) {
299 return json{ "get", std::string_view{args[0].ref()}.substr(1)};
300 };
301
302 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")
303 {
304 e.prefix_macros[prefix] = [get_func_name, prefix_size = prefix.size()](env_type const& e, std::vector<value> args) {
305 return json{ get_func_name, std::string{*args[0]}.substr(prefix_size) };
306 };
307 e.funcs[prefix_eval_func_name] = [prefix](env_type const& e, std::vector<value>) -> value {
308 return prefix;
309 };
310 }
311
312 public:
313
314 static void import_to(env_type& e)
315 {
316 e.funcs["list"] = list;
317 e.funcs["eval"] = eval;
318 e.funcs["break"] = loop_break;
319 set_macro_prefix_get(e);
320
321 if constexpr (DECADE_SYNTAX)
322 {
323 e.funcs["if:then:else:"] = if_then_else;
324 e.funcs[":?:::"] = if_then_else;
325 e.funcs["while:do:"] = while_do;
326 e.funcs[":while:"] = while_do_rev;
327 e.funcs["break:"] = loop_break;
328
329 e.funcs["get:"] = var_get;
330 e.funcs["get:of:"] = get_of;
331 e.funcs[":@:"] = get_of_inv;
332 e.funcs[":at:"] = get_of_inv;
333 e.funcs[":=:"] = var_set;
334 e.funcs["var:"] = new_var;
335 e.funcs["var:=:"] = new_var;
336 e.funcs["list:"] = list;
337 e.funcs["list:,:"] = list;
338 e.funcs["list:,*:"] = list;
339 e.funcs["eval:"] = eval;
340 e.funcs["eval:,:"] = eval;
341 e.funcs["eval:,*:"] = eval;
342 e.funcs[":==:"] = op_eq;
343 e.funcs[":eq:"] = op_eq;
344 e.funcs[":!=:"] = op_neq;
345 e.funcs[":neq:"] = op_neq;
346 e.funcs[":>:"] = op_gt;
347 e.funcs[":gt:"] = op_gt;
348 e.funcs[":>=:"] = op_ge;
349 e.funcs[":ge:"] = op_ge;
350 e.funcs[":<:"] = op_lt;
351 e.funcs[":lt:"] = op_lt;
352 e.funcs[":<=:"] = op_le;
353 e.funcs[":le:"] = op_le;
354 e.funcs["not:"] = op_not;
355 e.funcs[":and*:"] = op_and;
356 e.funcs[":and:"] = op_and;
357 e.funcs[":or:"] = op_or;
358 e.funcs[":or*:"] = op_or;
359 //e.funcs[":+:"] = op_plus;
360 e.funcs["type-of:"] = type_of;
361 e.funcs["typeof:"] = type_of;
362 e.funcs["size-of:"] = size_of;
363 e.funcs["sizeof:"] = size_of;
364 e.funcs["#:"] = size_of;
365
366 e.funcs["str:"] = str;
367
368 e.funcs["format:"] = format;
369 e.funcs["format:,:"] = format;
370 e.funcs["format:,*:"] = format;
371
372 e.funcs["print:"] = print;
373 e.funcs["print:,:"] = print;
374 e.funcs["print:,*:"] = print;
375
376 e.funcs["println:"] = println;
377 e.funcs["println:,:"] = println;
378 e.funcs["println:,*:"] = println;
379 }
380 }
381 };
382
383
384
398}
auto visit(nlohmann::json const &j, VISIT_FUNC &&func)
Calls func with the actual value inside j; similar to std::visit.
auto index(T &cont, RANDOM &rng=::ghassanpl::random::default_random_engine)
Returns an index of a random element in cont.
Definition random.h:331
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:605
Used with ghassanpl::eval::environment::import_lib() to add functions for basic decade to an eval env...
Definition lib_core.h:42
Represents a single evaluated value; can store an rvalue (as json), an lvalue (json*),...
Definition eval.h:44