nixd
Loading...
Searching...
No Matches
Value.cpp
Go to the documentation of this file.
1#include "nixt/Value.h"
2
3#include <nix/attr-path.hh>
4#include <nix/nixexpr.hh>
5#include <nix/symbol-table.hh>
6#include <nix/value.hh>
7
8using namespace nixt;
9
10std::optional<nix::Value> nixt::getField(nix::EvalState &State, nix::Value &V,
11 std::string_view Field) {
12 State.forceValue(V, nix::noPos);
13 if (V.type() != nix::ValueType::nAttrs)
14 return std::nullopt;
15
16 nix::Symbol SFiled = State.symbols.create(Field);
17 if (auto *It = V.attrs->find(SFiled); It != V.attrs->end())
18 return *It->value;
19
20 return std::nullopt;
21}
22
23std::optional<std::string_view> nixt::getFieldString(nix::EvalState &State,
24 nix::Value &V,
25 std::string_view Field) {
26 if (auto OptV = getField(State, V, Field)) {
27 State.forceValue(*OptV, nix::noPos);
28 if (OptV->type() == nix::ValueType::nString) {
29 return State.forceStringNoCtx(*OptV, nix::noPos,
30 "nixt::getFieldString()");
31 }
32 }
33 return std::nullopt;
34}
35
36bool nixt::checkField(nix::EvalState &State, nix::Value &V,
37 std::string_view Field, std::string_view Pred) {
38 return getFieldString(State, V, Field) == Pred;
39}
40
41bool nixt::checkType(nix::EvalState &State, nix::Value &V,
42 std::string_view Pred) {
43 return checkField(State, V, "_type", Pred);
44}
45
46bool nixt::isOption(nix::EvalState &State, nix::Value &V) {
47 return checkType(State, V, "option");
48};
49
50bool nixt::isDerivation(nix::EvalState &State, nix::Value &V) {
51 return checkField(State, V, "type", "derivation");
52}
53
54std::string nixt::attrPathStr(nix::EvalState &State, nix::Value &V,
55 const std::string &AttrPath) {
56 auto &AutoArgs = *State.allocBindings(0);
57 auto [VPath, Pos] = nix::findAlongAttrPath(State, AttrPath, AutoArgs, V);
58 State.forceValue(*VPath, Pos);
59 return std::string(State.forceStringNoCtx(*VPath, nix::noPos, ""));
60}
61
62std::vector<nix::Symbol>
63nixt::toSymbols(nix::SymbolTable &STable,
64 const std::vector<std::string> &Names) {
65 std::vector<nix::Symbol> Res;
66 Res.reserve(Names.size());
67 for (const auto &Name : Names) {
68 Res.emplace_back(STable.create(Name));
69 }
70 return Res;
71}
72
73std::vector<nix::Symbol>
74nixt::toSymbols(nix::SymbolTable &STable,
75 const std::vector<std::string_view> &Names) {
76 std::vector<nix::Symbol> Res;
77 Res.reserve(Names.size());
78 for (const auto &Name : Names) {
79 Res.emplace_back(STable.create(Name));
80 }
81 return Res;
82}
83
84nix::Value &nixt::selectAttr(nix::EvalState &State, nix::Value &V,
85 nix::Symbol Attr) {
86 State.forceValue(V, nix::noPos);
87
88 if (V.type() != nix::ValueType::nAttrs)
89 throw nix::TypeError("value is not an attrset");
90
91 assert(V.attrs && "nix must allocate non-null attrs!");
92 auto *Nested = V.attrs->find(Attr);
93 if (Nested == V.attrs->end())
94 throw nix::AttrPathNotFound("attrname " + State.symbols[Attr] +
95 " not found in attrset");
96
97 assert(Nested->value && "nix must allocate non-null nested value!");
98 return *Nested->value;
99}
100
101/// \brief Given an attrpath in nix::Value \p V, select it
102nix::Value &nixt::selectAttrPath(nix::EvalState &State, nix::Value &V,
103 std::vector<nix::Symbol>::const_iterator Begin,
104 std::vector<nix::Symbol>::const_iterator End) {
105 // If the attrpath is emtpy, return value itself.
106 if (Begin == End)
107 return V;
108
109 // Otherwise, select it.
110 nix::Value &Nested = selectAttr(State, V, *Begin);
111 return selectAttrPath(State, Nested, ++Begin, End);
112}
113
114namespace {
115
116/// \brief Check if the \p Type is a submodule.
117bool isTypeSubmodule(nix::EvalState &State, nix::Value &Type) {
118 return checkField(State, Type, "name", "submodule");
119}
120
121nix::Value *trySelectAttr(nix::EvalState &State, nix::Value &V, nix::Symbol S) {
122 try {
123 nix::Value &Type = selectAttr(State, V, State.sType);
124 return &Type;
125 } catch (nix::TypeError &) {
126 // The value is not an attrset, thus it definitely cannot be a submodule.
127 return nullptr;
128 } catch (nix::AttrPathNotFound &) {
129 // The value has no "type" field.
130 return nullptr;
131 }
132 return nullptr;
133}
134
135/// \brief Get the type of an option.
136nix::Value *tryGetSubmoduleType(nix::EvalState &State, nix::Value &V) {
137 if (nix::Value *Type = trySelectAttr(State, V, State.sType))
138 return isTypeSubmodule(State, *Type) ? Type : nullptr;
139 return nullptr;
140}
141
142/// \brief Do proper operations to get options declaration on submodule type.
143nix::Value getSubOptions(nix::EvalState &State, nix::Value &Type) {
144 // For example, programs.nixvim has all options nested into this attrpath.
145 nix::Value &GetSubOptions =
146 selectAttr(State, Type, State.symbols.create("getSubOptions"));
147
148 nix::Value EmptyList;
149 EmptyList.mkList(0);
150 // Invoke "GetSubOptions"
151 nix::Value VResult;
152 State.callFunction(GetSubOptions, EmptyList, VResult, nix::noPos);
153 return VResult;
154}
155
156} // namespace
157
158nix::Value nixt::selectOptions(nix::EvalState &State, nix::Value &V,
159 std::vector<nix::Symbol>::const_iterator Begin,
160 std::vector<nix::Symbol>::const_iterator End) {
161 // Always try to mangle the value if it is a submodule
162 if (nix::Value *SubType = tryGetSubmoduleType(State, V))
163 // Invoke getSubOptions on that type, and reset the value to it.
164 V = getSubOptions(State, *SubType);
165
166 if (Begin == End)
167 return V;
168
169 if (isOption(State, V)) {
170 // If currently "V" is an option, it can still be submodules.
171 //
172 // e.g. users.users <-- the main option stops at here.
173 // networking.interfaces
174 //
175 // Take care of such case.
176 nix::Value &Type = selectAttr(State, V, State.sType);
177 if (checkField(State, Type, "name", "attrsOf")) {
178 nix::Value NestedTypes =
179 selectAttr(State, Type, State.symbols.create("nestedTypes"));
180 nix::Value ElemType =
181 selectAttr(State, NestedTypes, State.symbols.create("elemType"));
182
183 if (isTypeSubmodule(State, ElemType)) {
184 nix::Value ElemOptions = getSubOptions(State, ElemType);
185 return selectOptions(State, ElemOptions, ++Begin, End);
186 }
187 }
188 }
189
190 // Otherwise, simply select it.
191 nix::Value &Nested = selectAttr(State, V, *Begin);
192 return selectOptions(State, Nested, ++Begin, End);
193}
Access EvalCache in nix::EvalState.
Definition ArrayRef.h:7
std::optional< std::string_view > getFieldString(nix::EvalState &State, nix::Value &V, std::string_view Field)
Definition Value.cpp:23
nix::Value & selectAttrPath(nix::EvalState &State, nix::Value &V, std::vector< nix::Symbol >::const_iterator Begin, std::vector< nix::Symbol >::const_iterator End)
Given an attrpath in nix::Value V, select it.
Definition Value.cpp:102
bool isOption(nix::EvalState &State, nix::Value &V)
Definition Value.cpp:46
bool checkField(nix::EvalState &State, nix::Value &V, std::string_view Field, std::string_view Pred)
Check if value V is an attrset, has the field, and equals to Pred.
Definition Value.cpp:36
bool checkType(nix::EvalState &State, nix::Value &V, std::string_view Pred)
Check if value is an attrset, and it's "_type" equals to Pred.
Definition Value.cpp:41
std::string attrPathStr(nix::EvalState &State, nix::Value &V, const std::string &AttrPath)
Definition Value.cpp:54
bool isDerivation(nix::EvalState &State, nix::Value &V)
Definition Value.cpp:50
nix::Value selectOptions(nix::EvalState &State, nix::Value &V, std::vector< nix::Symbol >::const_iterator Begin, std::vector< nix::Symbol >::const_iterator End)
Select the option declaration list, V, dive into "submodules".
Definition Value.cpp:158
std::vector< nix::Symbol > toSymbols(nix::SymbolTable &STable, const std::vector< std::string > &Names)
Transform a vector of string into a vector of nix symbols.
Definition Value.cpp:63
nix::Value & selectAttr(nix::EvalState &State, nix::Value &V, nix::Symbol Attr)
Select attribute Attr.
Definition Value.cpp:84
std::optional< nix::Value > getField(nix::EvalState &State, nix::Value &V, std::string_view Field)
Definition Value.cpp:10