aboutsummaryrefslogtreecommitdiff
path: root/src/libexpr/primops/fromTOML.cc
diff options
context:
space:
mode:
authorEelco Dolstra <edolstra@gmail.com>2018-07-03 18:15:59 +0200
committerEelco Dolstra <edolstra@gmail.com>2018-07-03 18:39:36 +0200
commit3b1f54cf06b6127a14479d18db8f08dc4c05d57a (patch)
treede6b77ac069b28b6af3d74ab0104518a7a1839d4 /src/libexpr/primops/fromTOML.cc
parenta92ed973e569324b55cddb128f6f638f3ea1985c (diff)
Add a fromTOML primop
This is primarily useful for processing Cargo.lock files.
Diffstat (limited to 'src/libexpr/primops/fromTOML.cc')
-rw-r--r--src/libexpr/primops/fromTOML.cc77
1 files changed, 77 insertions, 0 deletions
diff --git a/src/libexpr/primops/fromTOML.cc b/src/libexpr/primops/fromTOML.cc
new file mode 100644
index 000000000..b04d7c407
--- /dev/null
+++ b/src/libexpr/primops/fromTOML.cc
@@ -0,0 +1,77 @@
+#include "primops.hh"
+#include "eval-inline.hh"
+
+#include <cpptoml.h>
+
+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;
+ for (auto & i : *t2) size++;
+
+ 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]);
+ }
+
+ else if (t->is_value()) {
+ if (auto val = t->as<NixInt>())
+ 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) {
+ throw EvalError("while parsing a TOML string at %s: %s", pos, e.what());
+ }
+}
+
+static RegisterPrimOp r("fromTOML", 1, prim_fromTOML);
+
+}