Nix 2.26.3
Nix, the purely functional package manager; unstable internal interfaces
 
Loading...
Searching...
No Matches
nixexpr.hh
Go to the documentation of this file.
1#pragma once
3
4#include <map>
5#include <vector>
6
7#include "value.hh"
8#include "symbol-table.hh"
9#include "eval-error.hh"
10#include "pos-idx.hh"
11
12namespace nix {
13
14class EvalState;
15class PosTable;
16struct Env;
17struct ExprWith;
18struct StaticEnv;
19struct Value;
20
37struct DocComment {
38
43
48
56 operator bool() const { return static_cast<bool>(begin); }
57
58 std::string getInnerText(const PosTable & positions) const;
59
60};
61
65struct AttrName
66{
67 Symbol symbol;
68 Expr * expr;
69 AttrName(Symbol s) : symbol(s) {};
70 AttrName(Expr * e) : expr(e) {};
71};
72
73typedef std::vector<AttrName> AttrPath;
74
75std::string showAttrPath(const SymbolTable & symbols, const AttrPath & attrPath);
76
77
78/* Abstract syntax of Nix expressions. */
79
80struct Expr
81{
82 struct AstSymbols {
83 Symbol sub, lessThan, mul, div, or_, findFile, nixPath, body;
84 };
85
86
87 static unsigned long nrExprs;
88 Expr() {
89 nrExprs++;
90 }
91 virtual ~Expr() { };
92 virtual void show(const SymbolTable & symbols, std::ostream & str) const;
93 virtual void bindVars(EvalState & es, const std::shared_ptr<const StaticEnv> & env);
94 virtual void eval(EvalState & state, Env & env, Value & v);
95 virtual Value * maybeThunk(EvalState & state, Env & env);
96 virtual void setName(Symbol name);
97 virtual void setDocComment(DocComment docComment) { };
98 virtual PosIdx getPos() const { return noPos; }
99
100 // These are temporary methods to be used only in parser.y
101 virtual void resetCursedOr() { };
102 virtual void warnIfCursedOr(const SymbolTable & symbols, const PosTable & positions) { };
103};
104
105#define COMMON_METHODS \
106 void show(const SymbolTable & symbols, std::ostream & str) const override; \
107 void eval(EvalState & state, Env & env, Value & v) override; \
108 void bindVars(EvalState & es, const std::shared_ptr<const StaticEnv> & env) override;
109
110struct ExprInt : Expr
111{
112 Value v;
113 ExprInt(NixInt n) { v.mkInt(n); };
114 ExprInt(NixInt::Inner n) { v.mkInt(n); };
115 Value * maybeThunk(EvalState & state, Env & env) override;
116 COMMON_METHODS
117};
118
119struct ExprFloat : Expr
120{
121 Value v;
122 ExprFloat(NixFloat nf) { v.mkFloat(nf); };
123 Value * maybeThunk(EvalState & state, Env & env) override;
124 COMMON_METHODS
125};
126
127struct ExprString : Expr
128{
129 std::string s;
130 Value v;
131 ExprString(std::string &&s) : s(std::move(s)) { v.mkString(this->s.data()); };
132 Value * maybeThunk(EvalState & state, Env & env) override;
133 COMMON_METHODS
134};
135
136struct ExprPath : Expr
137{
138 ref<SourceAccessor> accessor;
139 std::string s;
140 Value v;
141 ExprPath(ref<SourceAccessor> accessor, std::string s) : accessor(accessor), s(std::move(s))
142 {
143 v.mkPath(&*accessor, this->s.c_str());
144 }
145 Value * maybeThunk(EvalState & state, Env & env) override;
146 COMMON_METHODS
147};
148
149typedef uint32_t Level;
150typedef uint32_t Displacement;
151
152struct ExprVar : Expr
153{
154 PosIdx pos;
155 Symbol name;
156
157 /* Whether the variable comes from an environment (e.g. a rec, let
158 or function argument) or from a "with".
159
160 `nullptr`: Not from a `with`.
161 Valid pointer: the nearest, innermost `with` expression to query first. */
162 ExprWith * fromWith;
163
164 /* In the former case, the value is obtained by going `level`
165 levels up from the current environment and getting the
166 `displ`th value in that environment. In the latter case, the
167 value is obtained by getting the attribute named `name` from
168 the set stored in the environment that is `level` levels up
169 from the current one.*/
170 Level level;
171 Displacement displ = 0;
172
173 ExprVar(Symbol name) : name(name) { };
174 ExprVar(const PosIdx & pos, Symbol name) : pos(pos), name(name) { };
175 Value * maybeThunk(EvalState & state, Env & env) override;
176 PosIdx getPos() const override { return pos; }
177 COMMON_METHODS
178};
179
185struct ExprInheritFrom : ExprVar
186{
187 ExprInheritFrom(PosIdx pos, Displacement displ): ExprVar(pos, {})
188 {
189 this->level = 0;
190 this->displ = displ;
191 this->fromWith = nullptr;
192 }
193
194 void bindVars(EvalState & es, const std::shared_ptr<const StaticEnv> & env) override;
195};
196
197struct ExprSelect : Expr
198{
199 PosIdx pos;
200 Expr * e, * def;
201 AttrPath attrPath;
202 ExprSelect(const PosIdx & pos, Expr * e, AttrPath attrPath, Expr * def) : pos(pos), e(e), def(def), attrPath(std::move(attrPath)) { };
203 ExprSelect(const PosIdx & pos, Expr * e, Symbol name) : pos(pos), e(e), def(0) { attrPath.push_back(AttrName(name)); };
204 PosIdx getPos() const override { return pos; }
205
214 Symbol evalExceptFinalSelect(EvalState & state, Env & env, Value & attrs);
215
216 COMMON_METHODS
217};
218
219struct ExprOpHasAttr : Expr
220{
221 Expr * e;
222 AttrPath attrPath;
223 ExprOpHasAttr(Expr * e, AttrPath attrPath) : e(e), attrPath(std::move(attrPath)) { };
224 PosIdx getPos() const override { return e->getPos(); }
225 COMMON_METHODS
226};
227
228struct ExprAttrs : Expr
229{
230 bool recursive;
231 PosIdx pos;
232 struct AttrDef {
241
242 Kind kind;
243 Expr * e;
244 PosIdx pos;
245 Displacement displ = 0; // displacement
246 AttrDef(Expr * e, const PosIdx & pos, Kind kind = Kind::Plain)
247 : kind(kind), e(e), pos(pos) { };
248 AttrDef() { };
249
250 template<typename T>
251 const T & chooseByKind(const T & plain, const T & inherited, const T & inheritedFrom) const
252 {
253 switch (kind) {
254 case Kind::Plain:
255 return plain;
256 case Kind::Inherited:
257 return inherited;
258 default:
260 return inheritedFrom;
261 }
262 }
263 };
264 typedef std::map<Symbol, AttrDef> AttrDefs;
265 AttrDefs attrs;
266 std::unique_ptr<std::vector<Expr *>> inheritFromExprs;
267 struct DynamicAttrDef {
268 Expr * nameExpr, * valueExpr;
269 PosIdx pos;
270 DynamicAttrDef(Expr * nameExpr, Expr * valueExpr, const PosIdx & pos)
271 : nameExpr(nameExpr), valueExpr(valueExpr), pos(pos) { };
272 };
273 typedef std::vector<DynamicAttrDef> DynamicAttrDefs;
274 DynamicAttrDefs dynamicAttrs;
275 ExprAttrs(const PosIdx &pos) : recursive(false), pos(pos) { };
276 ExprAttrs() : recursive(false) { };
277 PosIdx getPos() const override { return pos; }
278 COMMON_METHODS
279
280 std::shared_ptr<const StaticEnv> bindInheritSources(
281 EvalState & es, const std::shared_ptr<const StaticEnv> & env);
282 Env * buildInheritFromEnv(EvalState & state, Env & up);
283 void showBindings(const SymbolTable & symbols, std::ostream & str) const;
284};
285
286struct ExprList : Expr
287{
288 std::vector<Expr *> elems;
289 ExprList() { };
290 COMMON_METHODS
291 Value * maybeThunk(EvalState & state, Env & env) override;
292
293 PosIdx getPos() const override
294 {
295 return elems.empty() ? noPos : elems.front()->getPos();
296 }
297};
298
299struct Formal
300{
301 PosIdx pos;
302 Symbol name;
303 Expr * def;
304};
305
307{
308 typedef std::vector<Formal> Formals_;
309 Formals_ formals;
310 bool ellipsis;
311
312 bool has(Symbol arg) const
313 {
314 auto it = std::lower_bound(formals.begin(), formals.end(), arg,
315 [] (const Formal & f, const Symbol & sym) { return f.name < sym; });
316 return it != formals.end() && it->name == arg;
317 }
318
319 std::vector<Formal> lexicographicOrder(const SymbolTable & symbols) const
320 {
321 std::vector<Formal> result(formals.begin(), formals.end());
322 std::sort(result.begin(), result.end(),
323 [&] (const Formal & a, const Formal & b) {
324 std::string_view sa = symbols[a.name], sb = symbols[b.name];
325 return sa < sb;
326 });
327 return result;
328 }
329};
330
331struct ExprLambda : Expr
332{
333 PosIdx pos;
334 Symbol name;
335 Symbol arg;
336 Formals * formals;
337 Expr * body;
338 DocComment docComment;
339
340 ExprLambda(PosIdx pos, Symbol arg, Formals * formals, Expr * body)
341 : pos(pos), arg(arg), formals(formals), body(body)
342 {
343 };
344 ExprLambda(PosIdx pos, Formals * formals, Expr * body)
345 : pos(pos), formals(formals), body(body)
346 {
347 }
348 void setName(Symbol name) override;
349 std::string showNamePos(const EvalState & state) const;
350 inline bool hasFormals() const { return formals != nullptr; }
351 PosIdx getPos() const override { return pos; }
352 virtual void setDocComment(DocComment docComment) override;
353 COMMON_METHODS
354};
355
356struct ExprCall : Expr
357{
358 Expr * fun;
359 std::vector<Expr *> args;
360 PosIdx pos;
361 std::optional<PosIdx> cursedOrEndPos; // used during parsing to warn about https://github.com/NixOS/nix/issues/11118
362 ExprCall(const PosIdx & pos, Expr * fun, std::vector<Expr *> && args)
363 : fun(fun), args(args), pos(pos), cursedOrEndPos({})
364 { }
365 ExprCall(const PosIdx & pos, Expr * fun, std::vector<Expr *> && args, PosIdx && cursedOrEndPos)
366 : fun(fun), args(args), pos(pos), cursedOrEndPos(cursedOrEndPos)
367 { }
368 PosIdx getPos() const override { return pos; }
369 virtual void resetCursedOr() override;
370 virtual void warnIfCursedOr(const SymbolTable & symbols, const PosTable & positions) override;
371 COMMON_METHODS
372};
373
374struct ExprLet : Expr
375{
376 ExprAttrs * attrs;
377 Expr * body;
378 ExprLet(ExprAttrs * attrs, Expr * body) : attrs(attrs), body(body) { };
379 COMMON_METHODS
380};
381
382struct ExprWith : Expr
383{
384 PosIdx pos;
385 Expr * attrs, * body;
386 size_t prevWith;
387 ExprWith * parentWith;
388 ExprWith(const PosIdx & pos, Expr * attrs, Expr * body) : pos(pos), attrs(attrs), body(body) { };
389 PosIdx getPos() const override { return pos; }
390 COMMON_METHODS
391};
392
393struct ExprIf : Expr
394{
395 PosIdx pos;
396 Expr * cond, * then, * else_;
397 ExprIf(const PosIdx & pos, Expr * cond, Expr * then, Expr * else_) : pos(pos), cond(cond), then(then), else_(else_) { };
398 PosIdx getPos() const override { return pos; }
399 COMMON_METHODS
400};
401
402struct ExprAssert : Expr
403{
404 PosIdx pos;
405 Expr * cond, * body;
406 ExprAssert(const PosIdx & pos, Expr * cond, Expr * body) : pos(pos), cond(cond), body(body) { };
407 PosIdx getPos() const override { return pos; }
408 COMMON_METHODS
409};
410
411struct ExprOpNot : Expr
412{
413 Expr * e;
414 ExprOpNot(Expr * e) : e(e) { };
415 PosIdx getPos() const override { return e->getPos(); }
416 COMMON_METHODS
417};
418
419#define MakeBinOp(name, s) \
420 struct name : Expr \
421 { \
422 PosIdx pos; \
423 Expr * e1, * e2; \
424 name(Expr * e1, Expr * e2) : e1(e1), e2(e2) { }; \
425 name(const PosIdx & pos, Expr * e1, Expr * e2) : pos(pos), e1(e1), e2(e2) { }; \
426 void show(const SymbolTable & symbols, std::ostream & str) const override \
427 { \
428 str << "("; e1->show(symbols, str); str << " " s " "; e2->show(symbols, str); str << ")"; \
429 } \
430 void bindVars(EvalState & es, const std::shared_ptr<const StaticEnv> & env) override \
431 { \
432 e1->bindVars(es, env); e2->bindVars(es, env); \
433 } \
434 void eval(EvalState & state, Env & env, Value & v) override; \
435 PosIdx getPos() const override { return pos; } \
436 };
437
438MakeBinOp(ExprOpEq, "==")
439MakeBinOp(ExprOpNEq, "!=")
440MakeBinOp(ExprOpAnd, "&&")
441MakeBinOp(ExprOpOr, "||")
442MakeBinOp(ExprOpImpl, "->")
443MakeBinOp(ExprOpUpdate, "//")
444MakeBinOp(ExprOpConcatLists, "++")
445
446struct ExprConcatStrings : Expr
447{
448 PosIdx pos;
449 bool forceString;
450 std::vector<std::pair<PosIdx, Expr *>> * es;
451 ExprConcatStrings(const PosIdx & pos, bool forceString, std::vector<std::pair<PosIdx, Expr *>> * es)
452 : pos(pos), forceString(forceString), es(es) { };
453 PosIdx getPos() const override { return pos; }
454 COMMON_METHODS
455};
456
457struct ExprPos : Expr
458{
459 PosIdx pos;
460 ExprPos(const PosIdx & pos) : pos(pos) { };
461 PosIdx getPos() const override { return pos; }
462 COMMON_METHODS
463};
464
465/* only used to mark thunks as black holes. */
466struct ExprBlackHole : Expr
467{
468 void show(const SymbolTable & symbols, std::ostream & str) const override {}
469 void eval(EvalState & state, Env & env, Value & v) override;
470 void bindVars(EvalState & es, const std::shared_ptr<const StaticEnv> & env) override {}
471 [[noreturn]] static void throwInfiniteRecursionError(EvalState & state, Value & v);
472};
473
474extern ExprBlackHole eBlackHole;
475
476
477/* Static environments are used to map variable names onto (level,
478 displacement) pairs used to obtain the value of the variable at
479 runtime. */
480struct StaticEnv
481{
482 ExprWith * isWith;
483 const StaticEnv * up;
484
485 // Note: these must be in sorted order.
486 typedef std::vector<std::pair<Symbol, Displacement>> Vars;
487 Vars vars;
488
489 StaticEnv(ExprWith * isWith, const StaticEnv * up, size_t expectedSize = 0) : isWith(isWith), up(up) {
490 vars.reserve(expectedSize);
491 };
492
493 void sort()
494 {
495 std::stable_sort(vars.begin(), vars.end(),
496 [](const Vars::value_type & a, const Vars::value_type & b) { return a.first < b.first; });
497 }
498
499 void deduplicate()
500 {
501 auto it = vars.begin(), jt = it, end = vars.end();
502 while (jt != end) {
503 *it = *jt++;
504 while (jt != end && it->first == jt->first) *it = *jt++;
505 it++;
506 }
507 vars.erase(it, end);
508 }
509
510 Vars::const_iterator find(Symbol name) const
511 {
512 Vars::value_type key(name, 0);
513 auto i = std::lower_bound(vars.begin(), vars.end(), key);
514 if (i != vars.end() && i->first == name) return i;
515 return vars.end();
516 }
517};
518
519
520}
Definition eval.hh:182
Definition pos-idx.hh:9
Definition pos-table.hh:13
Definition symbol-table.hh:82
Definition symbol-table.hh:58
Definition ref.hh:15
PosIdx end
Definition lexer.l:5814
friend class EvalState
Definition lexer.l:5728
boost::format f(fs)
const T::key_type & key
Definition lexer.l:2763
friend class SymbolTable
Definition lexer.l:947
auto i
Definition lexer.l:2745
return s
Definition lexer.l:459
std::ostream & str
Definition lexer.l:1728
const std::string_view & name
Definition lexer.l:1709
std::unordered_map< std::string_view, std::pair< const std::string *, uint32_t > > symbols
Definition lexer.l:1010
Definition lexer.l:5999
Definition nixexpr.hh:66
Definition nixexpr.hh:37
PosIdx end
Definition nixexpr.hh:47
PosIdx begin
Definition nixexpr.hh:42
Definition eval.hh:152
Definition nixexpr.hh:232
Kind
Definition nixexpr.hh:233
@ Plain
Definition nixexpr.hh:235
@ Inherited
Definition nixexpr.hh:237
@ InheritedFrom
Definition nixexpr.hh:239
Definition nixexpr.hh:229
Definition nixexpr.hh:467
Symbol evalExceptFinalSelect(EvalState &state, Env &env, Value &attrs)
Definition eval.cc:1436
Definition nixexpr.hh:383
Definition nixexpr.hh:82
Definition nixexpr.hh:81
Definition nixexpr.hh:300
Definition nixexpr.hh:307
Definition nixexpr.hh:481
Definition value.hh:167