2018-07-03 19:15:59 +03:00
|
|
|
#include "primops.hh"
|
|
|
|
#include "eval-inline.hh"
|
|
|
|
|
2020-03-30 15:29:29 +03:00
|
|
|
#include "../../cpptoml/cpptoml.h"
|
2018-07-03 19:15:59 +03:00
|
|
|
|
|
|
|
namespace nix {
|
|
|
|
|
|
|
|
static void prim_fromTOML(EvalState & state, const Pos & pos, Value * * args, Value & v)
|
|
|
|
{
|
|
|
|
using namespace cpptoml;
|
|
|
|
|
|
|
|
auto toml = state.forceStringNoCtx(*args[0], pos);
|
|
|
|
|
|
|
|
std::istringstream tomlStream(toml);
|
|
|
|
|
|
|
|
std::function<void(Value &, std::shared_ptr<base>)> visit;
|
|
|
|
|
|
|
|
visit = [&](Value & v, std::shared_ptr<base> t) {
|
|
|
|
|
|
|
|
if (auto t2 = t->as_table()) {
|
|
|
|
|
|
|
|
size_t size = 0;
|
2018-07-11 22:05:09 +03:00
|
|
|
for (auto & i : *t2) { (void) i; size++; }
|
2018-07-03 19:15:59 +03:00
|
|
|
|
|
|
|
state.mkAttrs(v, size);
|
|
|
|
|
|
|
|
for (auto & i : *t2) {
|
|
|
|
auto & v2 = *state.allocAttr(v, state.symbols.create(i.first));
|
|
|
|
|
|
|
|
if (auto i2 = i.second->as_table_array()) {
|
|
|
|
size_t size2 = i2->get().size();
|
|
|
|
state.mkList(v2, size2);
|
|
|
|
for (size_t j = 0; j < size2; ++j)
|
|
|
|
visit(*(v2.listElems()[j] = state.allocValue()), i2->get()[j]);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
visit(v2, i.second);
|
|
|
|
}
|
|
|
|
|
|
|
|
v.attrs->sort();
|
|
|
|
}
|
|
|
|
|
|
|
|
else if (auto t2 = t->as_array()) {
|
|
|
|
size_t size = t2->get().size();
|
|
|
|
|
|
|
|
state.mkList(v, size);
|
|
|
|
|
|
|
|
for (size_t i = 0; i < size; ++i)
|
|
|
|
visit(*(v.listElems()[i] = state.allocValue()), t2->get()[i]);
|
|
|
|
}
|
|
|
|
|
2019-06-24 18:09:09 +03:00
|
|
|
// Handle cases like 'a = [[{ a = true }]]', which IMHO should be
|
|
|
|
// parsed as a array containing an array containing a table,
|
|
|
|
// but instead are parsed as an array containing a table array
|
|
|
|
// containing a table.
|
|
|
|
else if (auto t2 = t->as_table_array()) {
|
|
|
|
size_t size = t2->get().size();
|
|
|
|
|
|
|
|
state.mkList(v, size);
|
|
|
|
|
|
|
|
for (size_t j = 0; j < size; ++j)
|
|
|
|
visit(*(v.listElems()[j] = state.allocValue()), t2->get()[j]);
|
|
|
|
}
|
|
|
|
|
2018-07-03 19:15:59 +03:00
|
|
|
else if (t->is_value()) {
|
2018-07-11 22:12:18 +03:00
|
|
|
if (auto val = t->as<int64_t>())
|
2018-07-03 19:15:59 +03:00
|
|
|
mkInt(v, val->get());
|
|
|
|
else if (auto val = t->as<NixFloat>())
|
|
|
|
mkFloat(v, val->get());
|
|
|
|
else if (auto val = t->as<bool>())
|
|
|
|
mkBool(v, val->get());
|
|
|
|
else if (auto val = t->as<std::string>())
|
|
|
|
mkString(v, val->get());
|
|
|
|
else
|
|
|
|
throw EvalError("unsupported value type in TOML");
|
|
|
|
}
|
|
|
|
|
|
|
|
else abort();
|
|
|
|
};
|
|
|
|
|
|
|
|
try {
|
|
|
|
visit(v, parser(tomlStream).parse());
|
|
|
|
} catch (std::runtime_error & e) {
|
2020-06-15 15:06:58 +03:00
|
|
|
throw EvalError({
|
|
|
|
.hint = hintfmt("while parsing a TOML string: %s", e.what()),
|
2020-06-24 00:30:13 +03:00
|
|
|
.errPos = pos
|
2020-06-15 15:06:58 +03:00
|
|
|
});
|
2018-07-03 19:15:59 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static RegisterPrimOp r("fromTOML", 1, prim_fromTOML);
|
|
|
|
|
|
|
|
}
|