Files
lix/lix/libexpr/json-to-value.cc
T
skye be3a40e5dc libexpr: Replace Value::mkString with constructor calls
Change-Id: I55bba546eb090728a71734450a2a5f496a6a6964
2026-02-28 15:53:10 -05:00

197 lines
5.1 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#include "lix/libexpr/json-to-value.hh"
#include "gc-alloc.hh"
#include "lix/libexpr/value.hh"
#include "lix/libexpr/eval.hh"
#include "lix/libutil/json.hh"
#include <limits>
namespace nix {
// for more information, refer to
// https://github.com/nlohmann/json/blob/master/include/nlohmann/detail/input/json_sax.hpp
class JSONSax : nlohmann::json_sax<JSON> {
class JSONState {
protected:
std::unique_ptr<JSONState> parent;
RootValue v;
public:
virtual std::unique_ptr<JSONState> resolve(EvalState &)
{
assert(false && "tried to close toplevel json parser state");
}
explicit JSONState(std::unique_ptr<JSONState> && p) : parent(std::move(p)) {}
JSONState() = default;
JSONState(JSONState & p) = delete;
Value & value()
{
if (!v) {
v = allocRootValue({});
}
return *v;
}
virtual ~JSONState() {}
virtual void add() {}
};
class JSONObjectState : public JSONState {
using JSONState::JSONState;
GcMap<Symbol, Value> attrs;
Symbol _key;
std::unique_ptr<JSONState> resolve(EvalState & state) override
{
auto attrs2 = state.ctx.buildBindings(attrs.size());
for (auto & i : attrs)
attrs2.insert(i.first, i.second);
parent->value() = {NewValueAs::attrs, attrs2.alreadySorted()};
return std::move(parent);
}
void add() override
{
attrs.insert_or_assign(_key, value());
v = nullptr;
}
public:
void key(string_t & name, EvalState & state)
{
_key = state.ctx.symbols.create(name);
}
};
class JSONListState : public JSONState {
GcVector<Value> values;
std::unique_ptr<JSONState> resolve(EvalState & state) override
{
auto list = state.ctx.mem.newList(values.size());
parent->value() = {NewValueAs::list, list};
for (size_t n = 0; n < values.size(); ++n) {
list->elems[n] = values[n];
}
return std::move(parent);
}
void add() override
{
values.push_back(*v);
v = nullptr;
}
public:
JSONListState(std::unique_ptr<JSONState> && p, std::size_t reserve) : JSONState(std::move(p))
{
values.reserve(reserve);
}
};
EvalState & state;
std::unique_ptr<JSONState> rs;
public:
JSONSax(EvalState & state) : state(state), rs(new JSONState()) {};
Value result()
{
return rs->value();
}
bool null() override
{
rs->value().mkNull();
rs->add();
return true;
}
bool boolean(bool val) override
{
rs->value() = {NewValueAs::boolean, val};
rs->add();
return true;
}
bool number_integer(number_integer_t val) override
{
rs->value() = {NewValueAs::integer, val};
rs->add();
return true;
}
bool number_unsigned(number_unsigned_t val_) override
{
if (val_ > std::numeric_limits<NixInt::Inner>::max()) {
// Parse as a float for consistency with signed integers
// and interoperability with JSONs single numeric type.
return number_float(static_cast<number_float_t>(val_), "");
}
NixInt::Inner val = val_;
rs->value() = {NewValueAs::integer, val};
rs->add();
return true;
}
bool number_float(number_float_t val, const string_t & s) override
{
rs->value() = {NewValueAs::floating, val};
rs->add();
return true;
}
bool string(string_t & val) override
{
rs->value() = {NewValueAs::string, val};
rs->add();
return true;
}
#if NLOHMANN_JSON_VERSION_MAJOR >= 3 && NLOHMANN_JSON_VERSION_MINOR >= 8
bool binary(binary_t&) override
{
// This function ought to be unreachable
assert(false);
return true;
}
#endif
bool start_object(std::size_t len) override
{
rs = std::make_unique<JSONObjectState>(std::move(rs));
return true;
}
bool key(string_t & name) override
{
dynamic_cast<JSONObjectState*>(rs.get())->key(name, state);
return true;
}
bool end_object() override {
rs = rs->resolve(state);
rs->add();
return true;
}
bool end_array() override {
return end_object();
}
bool start_array(size_t len) override {
rs = std::make_unique<JSONListState>(std::move(rs),
len != std::numeric_limits<size_t>::max() ? len : 128);
return true;
}
bool
parse_error(std::size_t, const std::string &, const nlohmann::detail::exception & ex) override
{
throw JSONParseError("%s", ex.what());
}
};
void parseJSON(EvalState & state, const std::string_view & s_, Value & v)
{
JSONSax parser(state);
bool res = JSON::sax_parse(s_, &parser);
if (!res)
throw JSONParseError("Invalid JSON Value");
v = parser.result();
}
}