diff options
Diffstat (limited to 'third_party/nix/src/libexpr/primops/fromTOML.cc')
-rw-r--r-- | third_party/nix/src/libexpr/primops/fromTOML.cc | 94 |
1 files changed, 94 insertions, 0 deletions
diff --git a/third_party/nix/src/libexpr/primops/fromTOML.cc b/third_party/nix/src/libexpr/primops/fromTOML.cc new file mode 100644 index 000000000000..e3d2a4940769 --- /dev/null +++ b/third_party/nix/src/libexpr/primops/fromTOML.cc @@ -0,0 +1,94 @@ +#include "cpptoml/cpptoml.h" +#include "libexpr/eval-inline.hh" +#include "libexpr/primops.hh" + +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) { + (void)i; + 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.list)[j] = state.allocValue()), i2->get()[j]); + } + } else { + visit(v2, i.second); + } + } + } + + 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.list)[i] = state.allocValue()), t2->get()[i]); + } + } + + // 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.list)[j] = state.allocValue()), t2->get()[j]); + } + } + + else if (t->is_value()) { + if (auto val = t->as<int64_t>()) { + 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); + +} // namespace nix |