Nix  2.93.0-dev
Lix: A modern, delicious implementation of the Nix 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
10#include "lix/libutil/json.hh"
16
17namespace nix {
18
19struct Env;
20struct Value;
21class Evaluator;
22struct ExprWith;
23struct StaticEnv;
24
25
30{
31 PosIdx pos;
32 Symbol symbol;
33 std::unique_ptr<Expr> expr;
34 AttrName(PosIdx pos, Symbol s);
35 AttrName(PosIdx pos, std::unique_ptr<Expr> e);
36};
37
38typedef std::vector<AttrName> AttrPath;
39
40std::string showAttrPath(const SymbolTable & symbols, const AttrPath & attrPath);
41JSON printAttrPathToJson(const SymbolTable & symbols, const AttrPath & attrPath);
42
43
44/* Abstract syntax of Nix expressions. */
45
46struct Expr
47{
48protected:
49 Expr(Expr &&) = default;
50 Expr & operator=(Expr &&) = default;
51 Expr(const PosIdx pos) : pos(pos) {};
52
53public:
54 struct AstSymbols {
55 Symbol sub, lessThan, mul, div, or_, findFile, nixPath, body, overrides;
56 };
57
58 PosIdx pos;
59
60 Expr() = default;
61 Expr(const Expr &) = delete;
62 Expr & operator=(const Expr &) = delete;
63 virtual ~Expr() { };
64
65 virtual JSON toJSON(const SymbolTable & symbols) const;
66 virtual void bindVars(Evaluator & es, const std::shared_ptr<const StaticEnv> & env);
67 virtual void eval(EvalState & state, Env & env, Value & v);
68 virtual Value * maybeThunk(EvalState & state, Env & env);
69 virtual void setName(Symbol name);
70 PosIdx getPos() const { return pos; }
71};
72
73#define COMMON_METHODS \
74 JSON toJSON(const SymbolTable & symbols) const override; \
75 void eval(EvalState & state, Env & env, Value & v) override; \
76 void bindVars(Evaluator & es, const std::shared_ptr<const StaticEnv> & env) override;
77
79{
80protected:
81 Value v;
82 ExprLiteral(const PosIdx pos) : Expr(pos) {};
83public:
84
85 ExprLiteral(const PosIdx pos, NewValueAs::integer_t, NixInt n) : Expr(pos) { v.mkInt(n); };
86 ExprLiteral(const PosIdx pos, NewValueAs::integer_t, NixInt::Inner n) : Expr(pos) { v.mkInt(n); };
87 ExprLiteral(const PosIdx pos, NewValueAs::floating_t, NixFloat nf) : Expr(pos) { v.mkFloat(nf); };
88 Value * maybeThunk(EvalState & state, Env & env) override;
89 COMMON_METHODS
90};
91
93{
94 std::string s;
95 ExprString(const PosIdx pos, std::string &&s) : ExprLiteral(pos), s(std::move(s)) { v.mkString(this->s.data()); };
96};
97
99{
100 std::string s;
101 ExprPath(const PosIdx pos, std::string s) : ExprLiteral(pos), s(std::move(s)) { v.mkPath(this->s.c_str()); };
102};
103
104typedef uint32_t Level;
105typedef uint32_t Displacement;
106
107struct ExprVar : Expr
108{
109 Symbol name;
110
111 /* Whether the variable comes from an environment (e.g. a rec, let
112 or function argument) or from a "with".
113
114 `nullptr`: Not from a `with`.
115 Valid pointer: the nearest, innermost `with` expression to query first. */
116 ExprWith * fromWith;
117
118 /* In the former case, the value is obtained by going `level`
119 levels up from the current environment and getting the
120 `displ`th value in that environment. In the latter case, the
121 value is obtained by getting the attribute named `name` from
122 the set stored in the environment that is `level` levels up
123 from the current one.*/
124 Level level;
125 Displacement displ;
126
127 /* Variables like `__sub` as generated from expressions like `5 - 3` shouldn't be overridden.
128 * This is implemented by having a blessed "root" env that contains the definitions (usually `builtins`)
129 * and checking that this var only binds against that env.
130 */
131 bool needsRoot;
132
133 ExprVar(Symbol name) : name(name), needsRoot(false) { };
134 ExprVar(const PosIdx & pos, Symbol name, bool needsRoot = false) : Expr(pos), name(name), needsRoot(needsRoot) { };
135 Value * maybeThunk(EvalState & state, Env & env) override;
136 COMMON_METHODS
137};
138
145{
146 ref<Expr> fromExpr;
147
148 ExprInheritFrom(PosIdx pos, Displacement displ, ref<Expr> fromExpr)
149 : ExprVar(pos, {}), fromExpr(fromExpr)
150 {
151 this->level = 0;
152 this->displ = displ;
153 this->fromWith = nullptr;
154 }
155
156 JSON toJSON(SymbolTable const & symbols) const override;
157 void bindVars(Evaluator & es, const std::shared_ptr<const StaticEnv> & env) override;
158};
159
161{
163 std::unique_ptr<Expr> e;
164
168 std::unique_ptr<Expr> def;
169
171 AttrPath attrPath;
172
173 ExprSelect(const PosIdx & pos, std::unique_ptr<Expr> e, AttrPath attrPath, std::unique_ptr<Expr> def) : Expr(pos), e(std::move(e)), def(std::move(def)), attrPath(std::move(attrPath)) { };
174 ExprSelect(const PosIdx & pos, std::unique_ptr<Expr> e, const PosIdx namePos, Symbol name) : Expr(pos), e(std::move(e)) { attrPath.push_back(AttrName(namePos, name)); };
175 COMMON_METHODS
176};
177
179{
180 std::unique_ptr<Expr> e;
181 AttrPath attrPath;
182 ExprOpHasAttr(const PosIdx & pos, std::unique_ptr<Expr> e, AttrPath attrPath) : Expr(pos), e(std::move(e)), attrPath(std::move(attrPath)) { };
183 COMMON_METHODS
184};
185
186/* Helper struct to contain the data shared across lets and sets */
188{
189 ExprAttrs() = default;
190 ExprAttrs(const ExprAttrs &) = delete;
191 ExprAttrs & operator=(const ExprAttrs &) = delete;
192 ExprAttrs(ExprAttrs &&) = default;
193 ExprAttrs & operator=(ExprAttrs &&) = default;
194 virtual ~ExprAttrs() = default;
195
196 struct AttrDef {
197 enum class Kind {
199 Plain,
201 Inherited,
204 };
205
206 Kind kind;
207 std::unique_ptr<Expr> e;
208 PosIdx pos;
209 Displacement displ; // displacement
210 AttrDef(std::unique_ptr<Expr> e, const PosIdx & pos, Kind kind = Kind::Plain)
211 : kind(kind), e(std::move(e)), pos(pos) { };
212 AttrDef() { };
213
214 template<typename T>
215 const T & chooseByKind(const T & plain, const T & inherited, const T & inheritedFrom) const
216 {
217 switch (kind) {
218 case Kind::Plain:
219 return plain;
220 case Kind::Inherited:
221 return inherited;
222 default:
224 return inheritedFrom;
225 }
226 }
227 };
228 typedef std::map<Symbol, AttrDef> AttrDefs;
229 AttrDefs attrs;
230 std::unique_ptr<std::vector<ref<Expr>>> inheritFromExprs;
232 std::unique_ptr<Expr> nameExpr, valueExpr;
233 PosIdx pos;
234 DynamicAttrDef(std::unique_ptr<Expr> nameExpr, std::unique_ptr<Expr> valueExpr, const PosIdx & pos)
235 : nameExpr(std::move(nameExpr)), valueExpr(std::move(valueExpr)), pos(pos) { };
236 };
237 typedef std::vector<DynamicAttrDef> DynamicAttrDefs;
238 DynamicAttrDefs dynamicAttrs;
239
240 std::shared_ptr<const StaticEnv> bindInheritSources(
241 Evaluator & es, const std::shared_ptr<const StaticEnv> & env);
242 Env * buildInheritFromEnv(EvalState & state, Env & up);
243 void addBindingsToJSON(JSON & out, const SymbolTable & symbols) const;
244};
245
247 bool recursive = false;
248
249 ExprSet(const PosIdx &pos, bool recursive = false) : Expr(pos), recursive(recursive) { };
250 ExprSet() { };
251 COMMON_METHODS
252};
253
255{
256 std::vector<std::unique_ptr<Expr>> elems;
257 ExprList(PosIdx pos) : Expr(pos) { };
258 COMMON_METHODS
259 Value * maybeThunk(EvalState & state, Env & env) override;
260};
261
262struct Pattern {
266
267 Pattern() = default;
268 explicit Pattern(Symbol name) : name(name) { }
269 virtual ~Pattern() = default;
270
271 virtual std::shared_ptr<const StaticEnv> buildEnv(const StaticEnv * up) = 0;
272 virtual void bindVars(Evaluator & es, const std::shared_ptr<const StaticEnv> & env) = 0;
273 virtual Env & match(ExprLambda & lambda, EvalState & state, Env & up, Value * arg, const PosIdx pos) = 0;
274
275 virtual void addBindingsToJSON(JSON & out, const SymbolTable & symbols) const = 0;
276};
277
280{
281 SimplePattern() = default;
283 assert(name);
284 }
285
286 virtual std::shared_ptr<const StaticEnv> buildEnv(const StaticEnv * up) override;
287 virtual void bindVars(Evaluator & es, const std::shared_ptr<const StaticEnv> & env) override;
288 virtual Env & match(ExprLambda & lambda, EvalState & state, Env & up, Value * arg, const PosIdx pos) override;
289
290 virtual void addBindingsToJSON(JSON & out, const SymbolTable & symbols) const override;
291};
292
295{
296 struct Formal
297 {
298 PosIdx pos;
299 Symbol name;
300 std::unique_ptr<Expr> def;
301 };
302
303 typedef std::vector<Formal> Formals_;
304 Formals_ formals;
305 bool ellipsis;
306
307 virtual std::shared_ptr<const StaticEnv> buildEnv(const StaticEnv * up) override;
308 virtual void bindVars(Evaluator & es, const std::shared_ptr<const StaticEnv> & env) override;
309 virtual Env & match(ExprLambda & lambda, EvalState & state, Env & up, Value * arg, const PosIdx pos) override;
310
311 virtual void addBindingsToJSON(JSON & out, const SymbolTable & symbols) const override;
312
313 bool has(Symbol arg) const
314 {
315 auto it = std::lower_bound(formals.begin(), formals.end(), arg,
316 [] (const Formal & f, const Symbol & sym) { return f.name < sym; });
317 return it != formals.end() && it->name == arg;
318 }
319
320 std::vector<std::reference_wrapper<const Formal>> lexicographicOrder(const SymbolTable & symbols) const
321 {
322 std::vector<std::reference_wrapper<const Formal>> result(formals.begin(), formals.end());
323 std::sort(result.begin(), result.end(),
324 [&] (const Formal & a, const Formal & b) {
325 std::string_view sa = symbols[a.name], sb = symbols[b.name];
326 return sa < sb;
327 });
328 return result;
329 }
330};
331
333{
338 std::unique_ptr<Pattern> pattern;
339 std::unique_ptr<Expr> body;
340 ExprLambda(PosIdx pos, std::unique_ptr<Pattern> pattern, std::unique_ptr<Expr> body)
341 : Expr(pos), pattern(std::move(pattern)), body(std::move(body))
342 {
343 }
344 void setName(Symbol name) override;
345 std::string showNamePos(const EvalState & state) const;
346
350 inline std::string getName(SymbolTable const & symbols) const
351 {
352 if (this->name) {
353 return symbols[this->name];
354 }
355
356 return "anonymous lambda";
357 }
358
362 inline std::string getQuotedName(SymbolTable const & symbols) const
363 {
364 if (this->name) {
365 return concatStrings("'", symbols[this->name], "'");
366 }
367
368 return "anonymous lambda";
369 }
370
371 COMMON_METHODS
372};
373
375{
376 std::unique_ptr<Expr> fun;
377 std::vector<std::unique_ptr<Expr>> args;
378 ExprCall(const PosIdx & pos, std::unique_ptr<Expr> fun, std::vector<std::unique_ptr<Expr>> && args)
379 : Expr(pos), fun(std::move(fun)), args(std::move(args))
380 { }
381 COMMON_METHODS
382};
383
385{
386 std::unique_ptr<Expr> body;
387 COMMON_METHODS
388};
389
391{
392 std::unique_ptr<Expr> attrs, body;
393 size_t prevWith;
394 ExprWith * parentWith;
395 ExprWith(const PosIdx & pos, std::unique_ptr<Expr> attrs, std::unique_ptr<Expr> body) : Expr(pos), attrs(std::move(attrs)), body(std::move(body)) { };
396 COMMON_METHODS
397};
398
399struct ExprIf : Expr
400{
401 std::unique_ptr<Expr> cond, then, else_;
402 ExprIf(const PosIdx & pos, std::unique_ptr<Expr> cond, std::unique_ptr<Expr> then, std::unique_ptr<Expr> else_) : Expr(pos), cond(std::move(cond)), then(std::move(then)), else_(std::move(else_)) { };
403 COMMON_METHODS
404};
405
407{
408 std::unique_ptr<Expr> cond, body;
409 ExprAssert(const PosIdx & pos, std::unique_ptr<Expr> cond, std::unique_ptr<Expr> body) : Expr(pos), cond(std::move(cond)), body(std::move(body)) { };
410 COMMON_METHODS
411};
412
414{
415 std::unique_ptr<Expr> e;
416 ExprOpNot(const PosIdx & pos, std::unique_ptr<Expr> e) : Expr(pos), e(std::move(e)) { };
417 COMMON_METHODS
418};
419
420#define MakeBinOp(name, s) \
421 struct name : Expr \
422 { \
423 std::unique_ptr<Expr> e1, e2; \
424 name(std::unique_ptr<Expr> e1, std::unique_ptr<Expr> e2) : e1(std::move(e1)), e2(std::move(e2)) { }; \
425 name(const PosIdx & pos, std::unique_ptr<Expr> e1, std::unique_ptr<Expr> e2) : Expr(pos), e1(std::move(e1)), e2(std::move(e2)) { }; \
426 JSON toJSON(const SymbolTable & symbols) const override \
427 { \
428 return { \
429 {"_type", #name}, \
430 {"e1", e1->toJSON(symbols)}, \
431 {"e2", e2->toJSON(symbols)} \
432 };\
433 } \
434 void bindVars(Evaluator & es, const std::shared_ptr<const StaticEnv> & env) override \
435 { \
436 e1->bindVars(es, env); e2->bindVars(es, env); \
437 } \
438 void eval(EvalState & state, Env & env, Value & v) override; \
439 };
440
441MakeBinOp(ExprOpEq, "==")
442MakeBinOp(ExprOpNEq, "!=")
443MakeBinOp(ExprOpAnd, "&&")
444MakeBinOp(ExprOpOr, "||")
445MakeBinOp(ExprOpImpl, "->")
446MakeBinOp(ExprOpUpdate, "//")
447MakeBinOp(ExprOpConcatLists, "++")
448
449struct ExprConcatStrings : Expr
450{
451 bool forceString;
452 std::vector<std::pair<PosIdx, std::unique_ptr<Expr>>> es;
453 ExprConcatStrings(const PosIdx & pos, bool forceString, std::vector<std::pair<PosIdx, std::unique_ptr<Expr>>> es)
454 : Expr(pos), forceString(forceString), es(std::move(es)) { };
455 COMMON_METHODS
456};
457
458struct ExprPos : Expr
459{
460 ExprPos(const PosIdx & pos) : Expr(pos) { };
461 COMMON_METHODS
462};
463
464/* only used to mark thunks as black holes. */
466{
467 void eval(EvalState & state, Env & env, Value & v) override;
468 void bindVars(Evaluator & es, const std::shared_ptr<const StaticEnv> & env) override {}
469};
470
471extern ExprBlackHole eBlackHole;
472
473
474/* Static environments are used to map variable names onto (level,
475 displacement) pairs used to obtain the value of the variable at
476 runtime. */
478{
479 ExprWith * isWith;
480 const StaticEnv * up;
481
482 // Note: these must be in sorted order.
483 typedef std::vector<std::pair<Symbol, Displacement>> Vars;
484 Vars vars;
485
486 /* See ExprVar::needsRoot */
487 bool isRoot = false;
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:673
Definition eval.hh:539
Definition pos-idx.hh:9
Definition symbol-table.hh:75
Definition symbol-table.hh:52
Definition ref.hh:17
This file defines two main structs/classes used in nix error handling.
Pos and AbstractPos.
Definition nixexpr.hh:30
Definition nixexpr.hh:297
Definition nixexpr.hh:295
virtual Env & match(ExprLambda &lambda, EvalState &state, Env &up, Value *arg, const PosIdx pos) override
Definition eval.cc:1499
Definition eval.hh:118
Definition nixexpr.hh:407
Definition nixexpr.hh:196
Kind
Definition nixexpr.hh:197
Definition nixexpr.hh:231
Definition nixexpr.hh:188
Definition nixexpr.hh:466
Definition nixexpr.hh:375
Definition nixexpr.hh:400
Definition nixexpr.hh:145
Definition nixexpr.hh:333
Symbol name
Definition nixexpr.hh:337
std::string getQuotedName(SymbolTable const &symbols) const
Definition nixexpr.hh:362
std::string getName(SymbolTable const &symbols) const
Definition nixexpr.hh:350
Definition nixexpr.hh:385
Definition nixexpr.hh:255
Definition nixexpr.hh:79
Definition nixexpr.hh:179
Definition nixexpr.hh:414
Definition nixexpr.hh:99
Definition nixexpr.hh:459
Definition nixexpr.hh:161
std::unique_ptr< Expr > e
Definition nixexpr.hh:163
AttrPath attrPath
Definition nixexpr.hh:171
std::unique_ptr< Expr > def
Definition nixexpr.hh:168
Definition nixexpr.hh:246
Definition nixexpr.hh:93
Definition nixexpr.hh:108
Definition nixexpr.hh:391
Definition nixexpr.hh:54
Definition nixexpr.hh:47
Definition value.hh:147
Definition value.hh:144
Definition nixexpr.hh:262
Symbol name
Definition nixexpr.hh:265
Definition nixexpr.hh:280
Definition nixexpr.hh:478
Definition value.hh:191