#include #include #include #include #include using namespace nix; static void prim_scope(EvalState & state, const PosIdx pos, Value ** args, Value & v) { std::vector path; state.forceStringNoCtx(*args[0], pos, "'scope' path argument"); auto s = std::string(args[0]->string_view()); if (s.empty()) state.error("'scope' requires a non-empty path") .atPos(pos) .debugThrow(); size_t start = 0; while (start < s.size()) { auto dot = s.find('.', start); if (dot == std::string::npos) { path.push_back(state.symbols.create(s.substr(start))); break; } path.push_back(state.symbols.create(s.substr(start, dot - start))); start = dot + 1; } // Build nested attrset from inside out // Given path [a, b, c] and value v: { a = { b = { c = v; }; }; } Value * inner = args[1]; for (auto it = path.rbegin(); it != path.rend(); ++it) { auto attrs = state.buildBindings(1); attrs.insert(*it, inner); Value * wrapper = state.allocValue(); wrapper->mkAttrs(attrs.finish()); inner = wrapper; } v = *inner; } static RegisterPrimOp rp({ .name = "scope", .args = {"path", "value"}, .doc = R"( Construct a nested attribute set from a dotted string path and a value. Example: `scope "a.b.c" 42` evaluates to `{ a = { b = { c = 42; }; }; }`. )", .fun = prim_scope, });