7#include "json_helpers.h"
15 using json = nlohmann::json;
16 static inline const json null_json;
19 std::variant<json, json*, json const*> v;
21 value()
noexcept =
default;
22 value(value
const&)
noexcept =
default;
23 value(value&&)
noexcept =
default;
24 value& operator=(value
const&)
noexcept =
default;
25 value& operator=(value&&)
noexcept =
default;
27 template <
typename...
ARGS>
28 requires std::constructible_from<json,
ARGS...>
31 explicit(
false) value(json&&
j)
noexcept : v(std::move(
j)) {}
32 explicit(
false) value(json
const*
j)
noexcept : v(std::move(
j)) {}
33 explicit(
false) value(json*
j)
noexcept : v(std::move(
j)) {}
35 bool is_lval()
const noexcept {
return v.index() == 1; }
36 bool is_rval()
const noexcept {
return v.index() == 0; }
37 bool is_ref()
const noexcept {
return v.index() == 2; }
39 json& lval() {
return *std::get<json*>(v); }
41 void ref() && =
delete;
43 json
const& ref()
const&
47 case 0:
return std::get<json>(v);
48 case 1:
return *std::get<json*>(v);
49 case 2:
return *std::get<json const*>(v);
54 json
const& forward()
const&
63 case 0:
return std::move(std::get<json>(v));
64 case 1:
return *std::get<json*>(v);
65 case 2:
return *std::get<json const*>(v);
70 explicit(
false)
operator json
const& ()
const&
75 json
const& operator*()
const&
80 explicit(
false)
operator json () &&
82 return static_cast<value&&
>(*this).forward();
87 return static_cast<value&&
>(*this).forward();
90 json
const* operator->()
const&
noexcept {
return &ref(); }
94 template <
bool DECADE_SYNTAX = false>
101 using eval_func = std::function<value(
self_type&, std::vector<value>)>;
104 std::map<std::string, eval_func, std::less<>>
funcs;
105 eval_func unknown_func_eval;
106 std::function<value(
self_type&, std::string_view)> unknown_var_eval;
107 std::function<
void(std::string_view)> error_handler;
108 std::map<std::string, json, std::less<>> user_storage;
109 void* user_data =
nullptr;
110 std::map<std::string, eval_func, std::less<>> prefix_macros;
115 auto find_in_user_storage(
this auto&&
self, std::string_view name)
117 if (
auto it =
self.user_storage.find(name);
it !=
self.user_storage.end())
118 return std::pair{ &
self,
it };
120 return self.parent_env ?
self.parent_env->find_in_user_storage(name) : std::pair<
decltype(&
self),
decltype(
it)>{};
123 value user_var(std::string_view name)
125 auto var = find_in_user_storage(name);
127 return &
var.second->second;
128 return unknown_var_eval ? unknown_var_eval(*
this, name) : value(null_json);
131 json& set_user_var(std::string_view name, value
val,
bool force_local =
false)
142 return storage->emplace(name,
val.forward()).first->second;
143 return it->second =
val.forward();
148 if (unknown_func_eval)
149 return &unknown_func_eval;
151 return parent_env->find_unknown_func_eval();
155 eval_func
const* find_func(std::string_view name)
const
160 return parent_env->find_func(name);
161 return find_unknown_func_eval();
164 template <
typename...
ARGS>
165 json report_error(std::string_view
fmt,
ARGS&&...
args)
167 auto errstr = std::vformat(
fmt, std::make_format_args(std::forward<ARGS>(
args)...));
173 throw std::runtime_error(std::move(
errstr));
176 struct e_scope_terminator {
177 value result = json(json::value_t::discarded);
191 if constexpr (decade_syntax)
246 if (
func.is_string())
248 else if (
func.is_array())
250 auto eres = eval_args(
func.get_ref<json::array_t
const&>());
251 if (
eres.is_string())
255 return report_error(
"first element of eval array must eval to a string func name, got: {}",
func.dump());
260 return report_error(
"func with name '{}' not found",
funcname);
263 template <
typename V>
266 if constexpr (std::same_as<V, value const&>)
268 return eval(value{
val });
270 else if constexpr (std::same_as<std::remove_cvref_t<V>, json>)
272 return eval(value(std::forward<V>(
val)));
274 else if constexpr (std::same_as<std::remove_cvref_t<V>, value>)
276 if (
val->is_string())
278 if (
auto str = std::string_view{ *
val }; !str.empty())
280 for (
auto& [prefix,
macro] : prefix_macros)
282 if (str.starts_with(prefix))
283 return eval(
macro(*
this, { std::move(
val) }));
288 if (!
val->is_array())
289 return std::move(
val);
291 std::vector<value>
args;
292 switch (
val.v.index())
311 for (
auto const& a :
arr)
317 return eval_call(std::move(
args));
321 template <
typename T>
322 json safe_eval(T&& value)
326 auto result = eval(value);
327 return result.forward();
329 catch (e_scope_terminator
const&
e)
331 return report_error(
"'{}' not in loop",
e.type());
335 inline bool is_true(json
const&
val)
339 case json::value_t::boolean:
return bool(
val);
340 case json::value_t::null:
return false;
345 inline bool is_true(value
const&
val)
347 return is_true(*
val);
350 static void assert_args(std::span<value const>
args,
size_t arg_count)
353 throw std::runtime_error(std::format(
"function {} requires exactly {} arguments, {} given",
args[0]->
dump(),
arg_count,
args.size() - 1));
359 throw std::runtime_error(std::format(
"function {} requires between {} and {} arguments, {} given",
args[0]->
dump(),
min_args,
max_args,
args.size() - 1));
362 static void assert_min_args(std::span<value const>
args,
size_t arg_count)
365 throw std::runtime_error(std::format(
"function {} requires at least {} arguments, {} given",
args[0]->
dump(),
arg_count,
args.size() - 1));
368 static auto assert_arg(std::span<value const>
args,
size_t arg_num, json::value_t type = json::value_t::discarded)
371 throw std::runtime_error(std::format(
"function {} requires {} arguments, {} given",
args[0]->
dump(),
arg_num,
args.size() - 1));
373 if (type != json::value_t::discarded &&
args[
arg_num]->type() != type)
375 throw std::runtime_error(std::format(
"argument #{} to function {} must be of type {}, {} given",
382 template <std::same_as<nlohmann::json::value_t>... T>
383 static void assert_args(std::vector<value>
args, T...
arg_types)
385 static constexpr size_t arg_count =
sizeof...(T);
389 for (
size_t i = 0;
i <
types.size(); ++
i)
391 if (
types[
i] != json::value_t::discarded)
396 value eval_arg(std::vector<value>&
args,
size_t n, json::value_t type = json::value_t::discarded)
398 assert_arg(
args,
n, type);
399 return eval(std::move(
args[
n]));
402 void eval_args(std::vector<value>&
args,
size_t n)
404 assert_args(
args,
n);
409 void eval_args(std::vector<value>&
args)
414 template <
typename LIB_TYPE>
417 LIB_TYPE::import_to(*
this);
420 template <
template<
bool>
typename LIB_TYPE>
423 LIB_TYPE<decade_syntax>::import_to(*
this);
constexpr auto bit_count
Equal to the number of bits in the type.
NOTE: Decade syntax is slower to execute but more natural.
std::function< bool(json const &)> truthiness_function
eval('.test') -> eval(prefix_macros['.']('.test'))
std::map< std::string, eval_func, std::less<> > funcs
TODO: How to do const parent envs, or const vars?