Nix  2.93.0-dev
Lix: A modern, delicious implementation of the Nix package manager; unstable internal interfaces
Loading...
Searching...
No Matches
value.hh
Go to the documentation of this file.
1#pragma once
3
4#include <cassert>
5#include <climits>
6#include <functional>
7#include <ranges>
8#include <span>
9
10#include "lix/libexpr/gc-alloc.hh"
16#include "lix/libutil/checked-arithmetic.hh"
17#include "lix/libutil/concepts.hh"
18#include "lix/libutil/json-fwd.hh"
19
20namespace nix {
21
22class BindingsBuilder;
23
24
25typedef enum {
26 tInt = 1,
27 tBool,
28 tString,
29 tPath,
30 tNull,
31 tAttrs,
32 tList1,
33 tList2,
34 tListN,
35 tThunk,
36 tApp,
37 tLambda,
38 tPrimOp,
39 tPrimOpApp,
40 tExternal,
41 tFloat
42} InternalType;
43
49typedef enum {
50 nThunk,
51 nInt,
52 nFloat,
53 nBool,
54 nString,
55 nPath,
56 nNull,
57 nAttrs,
58 nList,
59 nFunction,
60 nExternal
61} ValueType;
62
63class Bindings;
64struct Env;
65struct Expr;
66struct ExprLambda;
67struct ExprBlackHole;
68struct PrimOp;
69class Symbol;
70class PosIdx;
71struct Pos;
72class StorePath;
73class Store;
74class EvalState;
75class XMLWriter;
76class Printer;
77
78using NixInt = checked::Checked<int64_t>;
79using NixFloat = double;
80
86{
87 friend std::ostream & operator << (std::ostream & str, const ExternalValueBase & v);
88 friend class Printer;
89 protected:
93 virtual std::ostream & print(std::ostream & str) const = 0;
94
95 public:
99 virtual std::string showType() const = 0;
100
104 virtual std::string typeOf() const = 0;
105
110 virtual std::string coerceToString(EvalState & state, const PosIdx & pos, NixStringContext & context, bool copyMore, bool copyToStore) const;
111
116 virtual bool operator ==(const ExternalValueBase & b) const;
117
121 virtual JSON printValueAsJSON(EvalState & state, bool strict,
122 NixStringContext & context, bool copyToStore = true) const;
123
127 virtual void printValueAsXML(EvalState & state, bool strict, bool location,
128 XMLWriter & doc, NixStringContext & context, PathSet & drvsSeen,
129 const PosIdx pos) const;
130
131 virtual ~ExternalValueBase()
132 {
133 };
134};
135
136std::ostream & operator << (std::ostream & str, const ExternalValueBase & v);
137
140extern Expr *eBlackHoleAddr;
141
143{
144 struct integer_t { };
145 constexpr static integer_t integer{};
146
147 struct floating_t { };
148 constexpr static floating_t floating{};
149
150 struct boolean_t { };
151 constexpr static boolean_t boolean{};
152
153 struct string_t { };
154 constexpr static string_t string{};
155
156 struct path_t { };
157 constexpr static path_t path{};
158
159 struct list_t { };
160 constexpr static list_t list{};
161
162 struct attrs_t { };
163 constexpr static attrs_t attrs{};
164
165 struct thunk_t { };
166 constexpr static thunk_t thunk{};
167
168 struct null_t { };
169 constexpr static null_t null{};
170
171 struct app_t { };
172 constexpr static app_t app{};
173
174 struct primop_t { };
175 constexpr static primop_t primop{};
176
177 struct primOpApp_t { };
178 constexpr static primOpApp_t primOpApp{};
179
180 struct lambda_t { };
181 constexpr static lambda_t lambda{};
182
183 struct external_t { };
184 constexpr static external_t external{};
185
186 struct blackhole_t { };
187 constexpr static blackhole_t blackhole{};
188};
189
190struct Value
191{
192private:
193 InternalType internalType;
194
195 friend std::string showType(const Value & v);
196
197public:
198
203
204 // Discount `using NewValueAs::*;`
205// NOLINTNEXTLINE(bugprone-macro-parentheses)
206#define USING_VALUETYPE(name) using name = NewValueAs::name
207 USING_VALUETYPE(integer_t);
208 USING_VALUETYPE(floating_t);
209 USING_VALUETYPE(boolean_t);
210 USING_VALUETYPE(string_t);
211 USING_VALUETYPE(path_t);
212 USING_VALUETYPE(list_t);
213 USING_VALUETYPE(attrs_t);
214 USING_VALUETYPE(thunk_t);
215 USING_VALUETYPE(primop_t);
216 USING_VALUETYPE(app_t);
217 USING_VALUETYPE(null_t);
218 USING_VALUETYPE(primOpApp_t);
219 USING_VALUETYPE(lambda_t);
220 USING_VALUETYPE(external_t);
221 USING_VALUETYPE(blackhole_t);
222#undef USING_VALUETYPE
223
226 [[deprecated]] Value()
227 : internalType(static_cast<InternalType>(0))
228 , _empty{ 0, 0 }
229 { }
230
233 Value(integer_t, NixInt i)
234 : internalType(tInt)
235 , _empty{ 0, 0 }
236 {
237 // the NixInt ctor here is is special because NixInt has a ctor too, so
238 // we're not allowed to have it as an anonymous aggreagte member. we do
239 // however still have the option to clear the data members using _empty
240 // and leaving the second word of data cleared by setting only integer.
241 integer = i;
242 }
243
246 Value(floating_t, NixFloat f)
247 : internalType(tFloat)
248 , fpoint(f)
249 , _float_pad(0)
250 { }
251
254 Value(boolean_t, bool b)
255 : internalType(tBool)
256 , boolean(b)
257 , _bool_pad(0)
258 { }
259
267 Value(string_t, char const * strPtr, char const ** contextPtr = nullptr)
268 : internalType(tString)
269 , string({ .s = strPtr, .context = contextPtr })
270 { }
271
277 Value(string_t, std::string_view copyFrom, NixStringContext const & context = {})
278 : internalType(tString)
279 , string({ .s = gcCopyStringIfNeeded(copyFrom), .context = nullptr })
280 {
281 if (context.empty()) {
282 // It stays nullptr.
283 return;
284 }
285
286 // Copy the context.
287 this->string.context = gcAllocType<char const *>(context.size() + 1);
288
289 size_t n = 0;
290 for (NixStringContextElem const & contextElem : context) {
291 this->string.context[n] = gcCopyStringIfNeeded(contextElem.to_string());
292 n += 1;
293 }
294
295 // Terminator sentinel.
296 this->string.context[n] = nullptr;
297 }
298
308 Value(string_t, char const * strPtr, NixStringContext const & context)
309 : internalType(tString)
310 , string({ .s = strPtr, .context = nullptr })
311 {
312 if (context.empty()) {
313 // It stays nullptr
314 return;
315 }
316
317 // Copy the context.
318 this->string.context = gcAllocType<char const *>(context.size() + 1);
319
320 size_t n = 0;
321 for (NixStringContextElem const & contextElem : context) {
322 this->string.context[n] = gcCopyStringIfNeeded(contextElem.to_string());
323 n += 1;
324 }
325
326 // Terminator sentinel.
327 this->string.context[n] = nullptr;
328 }
329
336 Value(path_t, char const * strPtr)
337 : internalType(tPath)
338 , _path(strPtr)
339 , _path_pad(0)
340 { }
341
347 Value(path_t, SourcePath const & path)
348 : internalType(tPath)
349 , _path(gcCopyStringIfNeeded(path.canonical().abs()))
350 , _path_pad(0)
351 { }
352
365 Value(list_t, std::span<Value *> items)
366 {
367 if (items.size() == 1) {
368 this->internalType = tList1;
369 this->smallList[0] = items[0];
370 this->smallList[1] = nullptr;
371 } else if (items.size() == 2) {
372 this->internalType = tList2;
373 this->smallList[0] = items[0];
374 this->smallList[1] = items[1];
375 } else {
376 this->internalType = tListN;
377 this->bigList.size = items.size();
378 this->bigList.elems = items.data();
379 }
380 }
381
389 template<
390 std::ranges::sized_range SizedIterableT,
392 >
393 Value(list_t, SizedIterableT & items, TransformerT const & transformer)
394 {
395 if (items.size() == 1) {
396 this->internalType = tList1;
397 this->smallList[0] = transformer(*items.begin());
398 this->smallList[1] = nullptr;
399 } else if (items.size() == 2) {
400 this->internalType = tList2;
401 auto it = items.begin();
402 this->smallList[0] = transformer(*it);
403 it++;
404 this->smallList[1] = transformer(*it);
405 } else {
406 this->internalType = tListN;
407 this->bigList.size = items.size();
408 this->bigList.elems = gcAllocType<Value *>(items.size());
409 auto it = items.begin();
410 for (size_t i = 0; i < items.size(); i++, it++) {
411 this->bigList.elems[i] = transformer(*it);
412 }
413 }
414 }
415
417 Value(null_t)
418 : internalType(tNull)
419 , _empty{0, 0}
420 { }
421
427 Value(attrs_t, Bindings * bindings)
428 : internalType(tAttrs)
429 , attrs(bindings)
430 , _attrs_pad(0)
431 { }
432
437 Value(thunk_t, Env & env, Expr & expr)
438 : internalType(tThunk)
439 , thunk({ .env = &env, .expr = &expr })
440 { }
441
445 Value(primop_t, PrimOp & primop);
446
449 Value(primOpApp_t, Value & lhs, Value & rhs)
450 : internalType(tPrimOpApp)
451 , primOpApp({ .left = &lhs, .right = &rhs })
452 { }
453
456 Value(app_t, Value & lhs, Value & rhs)
457 : internalType(tApp)
458 , app({ .left = &lhs, .right = &rhs })
459 { }
460
463 Value(external_t, ExternalValueBase & external)
464 : internalType(tExternal)
465 , external(&external)
466 , _external_pad(0)
467 { }
468
475 Value(lambda_t, Env & env, ExprLambda & lambda)
476 : internalType(tLambda)
477 , lambda({ .env = &env, .fun = &lambda })
478 { }
479
481 explicit Value(blackhole_t)
482 : internalType(tThunk)
483 , thunk({ .env = nullptr, .expr = eBlackHoleAddr })
484 { }
485
486 Value(Value const & rhs) = default;
487
490 Value(Value && rhs)
491 : internalType(rhs.internalType)
492 , _empty{ 0, 0 }
493 {
494 *this = std::move(rhs);
495 }
496
497 Value & operator=(Value const & rhs) = default;
498
502 inline Value & operator=(Value && rhs)
503 {
504 *this = static_cast<const Value &>(rhs);
505 if (this != &rhs) {
506 // Kill `rhs`, because non-destructive move lol.
507 rhs.internalType = static_cast<InternalType>(0);
508 rhs._empty[0] = 0;
509 rhs._empty[1] = 0;
510 }
511 return *this;
512 }
513
514 void print(EvalState &state, std::ostream &str, PrintOptions options = PrintOptions {});
515
516 // Functions needed to distinguish the type
517 // These should be removed eventually, by putting the functionality that's
518 // needed by callers into methods of this type
519
520 // type() == nThunk
521 inline bool isThunk() const { return internalType == tThunk; };
522 inline bool isApp() const { return internalType == tApp; };
523 inline bool isBlackhole() const
524 {
525 return internalType == tThunk && thunk.expr == eBlackHoleAddr;
526 }
527
528 // type() == nFunction
529 inline bool isLambda() const { return internalType == tLambda; };
530 inline bool isPrimOp() const { return internalType == tPrimOp; };
531 inline bool isPrimOpApp() const { return internalType == tPrimOpApp; };
532
533 union
534 {
537 uintptr_t _empty[2];
538
539 NixInt integer;
540 struct {
541 bool boolean;
542 uintptr_t _bool_pad;
543 };
544
567 struct {
568 const char * s;
569 const char * * context; // must be in sorted order
571
572 struct {
573 const char * _path;
574 uintptr_t _path_pad;
575 };
576 struct {
577 Bindings * attrs;
578 uintptr_t _attrs_pad;
579 };
580 struct {
581 size_t size;
582 Value * * elems;
583 } bigList;
584 Value * smallList[2];
585 struct {
586 Env * env;
587 Expr * expr;
588 } thunk;
589 struct {
590 Value * left, * right;
591 } app;
592 struct {
593 Env * env;
594 ExprLambda * fun;
595 } lambda;
596 struct {
597 PrimOp * primOp;
598 uintptr_t _primop_pad;
599 };
600 struct {
601 Value * left, * right;
602 } primOpApp;
603 struct {
604 ExternalValueBase * external;
605 uintptr_t _external_pad;
606 };
607 struct {
608 NixFloat fpoint;
609 uintptr_t _float_pad;
610 };
611 };
612
620 inline ValueType type(bool invalidIsThunk = false) const
621 {
622 switch (internalType) {
623 case tInt: return nInt;
624 case tBool: return nBool;
625 case tString: return nString;
626 case tPath: return nPath;
627 case tNull: return nNull;
628 case tAttrs: return nAttrs;
629 case tList1: case tList2: case tListN: return nList;
630 case tLambda: case tPrimOp: case tPrimOpApp: return nFunction;
631 case tExternal: return nExternal;
632 case tFloat: return nFloat;
633 case tThunk: case tApp: return nThunk;
634 }
635 if (invalidIsThunk)
636 return nThunk;
637 else
638 abort();
639 }
640
645 inline void clearValue()
646 {
647 app.left = app.right = 0;
648 }
649
650 inline void mkInt(NixInt::Inner n)
651 {
652 mkInt(NixInt{n});
653 }
654
655 inline void mkInt(NixInt n)
656 {
657 clearValue();
658 internalType = tInt;
659 integer = n;
660 }
661
662 inline void mkBool(bool b)
663 {
664 clearValue();
665 internalType = tBool;
666 boolean = b;
667 }
668
669 inline void mkString(const char * s, const char * * context = 0)
670 {
671 internalType = tString;
672 string.s = s;
673 string.context = context;
674 }
675
676 void mkString(std::string_view s);
677
678 void mkString(std::string_view s, const NixStringContext & context);
679
680 void mkStringMove(const char * s, const NixStringContext & context);
681
682 void mkPath(const SourcePath & path);
683
684 inline void mkPath(const char * path)
685 {
686 clearValue();
687 internalType = tPath;
688 _path = path;
689 }
690
691 inline void mkNull()
692 {
693 clearValue();
694 internalType = tNull;
695 }
696
697 inline void mkAttrs(Bindings * a)
698 {
699 clearValue();
700 internalType = tAttrs;
701 attrs = a;
702 }
703
704 Value & mkAttrs(BindingsBuilder & bindings);
705
706 inline void mkList(size_t size)
707 {
708 clearValue();
709 if (size == 1)
710 internalType = tList1;
711 else if (size == 2)
712 internalType = tList2;
713 else {
714 internalType = tListN;
715 bigList.size = size;
716 }
717 }
718
719 inline void mkThunk(Env * e, Expr & ex)
720 {
721 internalType = tThunk;
722 thunk.env = e;
723 thunk.expr = &ex;
724 }
725
726 inline void mkApp(Value * l, Value * r)
727 {
728 internalType = tApp;
729 app.left = l;
730 app.right = r;
731 }
732
733 inline void mkLambda(Env * e, ExprLambda * f)
734 {
735 internalType = tLambda;
736 lambda.env = e;
737 lambda.fun = f;
738 }
739
740 inline void mkBlackhole()
741 {
742 internalType = tThunk;
743 thunk.expr = eBlackHoleAddr;
744 }
745
746 void mkPrimOp(PrimOp * p);
747
748 inline void mkPrimOpApp(Value * l, Value * r)
749 {
750 internalType = tPrimOpApp;
751 primOpApp.left = l;
752 primOpApp.right = r;
753 }
754
758 PrimOp * primOpAppPrimOp() const;
759
760 inline void mkExternal(ExternalValueBase * e)
761 {
762 clearValue();
763 internalType = tExternal;
764 external = e;
765 }
766
767 inline void mkFloat(NixFloat n)
768 {
769 clearValue();
770 internalType = tFloat;
771 fpoint = n;
772 }
773
774 bool isList() const
775 {
776 return internalType == tList1 || internalType == tList2 || internalType == tListN;
777 }
778
779 Value * * listElems()
780 {
781 return internalType == tList1 || internalType == tList2 ? smallList : bigList.elems;
782 }
783
784 Value * const * listElems() const
785 {
786 return internalType == tList1 || internalType == tList2 ? smallList : bigList.elems;
787 }
788
789 size_t listSize() const
790 {
791 return internalType == tList1 ? 1 : internalType == tList2 ? 2 : bigList.size;
792 }
793
794 PosIdx determinePos(const PosIdx pos) const;
795
801 bool isTrivial() const;
802
803 auto listItems()
804 {
805 struct ListIterable
806 {
807 typedef Value * const * iterator;
808 iterator _begin, _end;
809 iterator begin() const { return _begin; }
810 iterator end() const { return _end; }
811 };
812 assert(isList());
813 auto begin = listElems();
814 return ListIterable { begin, begin + listSize() };
815 }
816
817 auto listItems() const
818 {
819 struct ConstListIterable
820 {
821 typedef const Value * const * iterator;
822 iterator _begin, _end;
823 iterator begin() const { return _begin; }
824 iterator end() const { return _end; }
825 };
826 assert(isList());
827 auto begin = listElems();
828 return ConstListIterable { begin, begin + listSize() };
829 }
830
831 SourcePath path() const
832 {
833 assert(internalType == tPath);
834 return SourcePath{CanonPath(_path)};
835 }
836
837 std::string_view str() const
838 {
839 assert(internalType == tString);
840 return std::string_view(string.s);
841 }
842};
843
844using ValueVector = GcVector<Value *>;
845using ValueMap = GcMap<Symbol, Value *>;
846using ValueVectorMap = std::map<Symbol, ValueVector>;
847
851typedef std::shared_ptr<Value *> RootValue;
852
853RootValue allocRootValue(Value * v);
854
855}
Definition attr-set.hh:49
Definition eval.hh:673
Definition value.hh:86
virtual JSON printValueAsJSON(EvalState &state, bool strict, NixStringContext &context, bool copyToStore=true) const
Definition value-to-json.cc:119
virtual std::string showType() const =0
virtual bool operator==(const ExternalValueBase &b) const
Definition eval.cc:2901
virtual std::string typeOf() const =0
virtual std::ostream & print(std::ostream &str) const =0
virtual std::string coerceToString(EvalState &state, const PosIdx &pos, NixStringContext &context, bool copyMore, bool copyToStore) const
Definition eval.cc:2893
virtual void printValueAsXML(EvalState &state, bool strict, bool location, XMLWriter &doc, NixStringContext &context, PathSet &drvsSeen, const PosIdx pos) const
Definition value-to-xml.cc:165
Definition pos-idx.hh:9
Definition print.cc:111
Definition xml-writer.hh:17
Definition concepts.hh:20
Options for printing Nix values.
SourcePath.
Definition eval.hh:118
Definition nixexpr.hh:333
Definition nixexpr.hh:47
Definition value.hh:171
Definition value.hh:162
Definition value.hh:186
Definition value.hh:150
Definition value.hh:183
Definition value.hh:147
Definition value.hh:144
Definition value.hh:180
Definition value.hh:159
Definition value.hh:168
Definition value.hh:156
Definition value.hh:177
Definition value.hh:174
Definition value.hh:153
Definition value.hh:165
Definition value.hh:143
Definition print-options.hh:38
Definition source-path.hh:23
Definition value.hh:191
Value(path_t, SourcePath const &path)
Definition value.hh:347
Value(floating_t, NixFloat f)
Definition value.hh:246
uintptr_t _empty[2]
Definition value.hh:537
static Value EMPTY_LIST
Definition value.hh:202
Value(boolean_t, bool b)
Definition value.hh:254
Value(string_t, char const *strPtr, char const **contextPtr=nullptr)
Definition value.hh:267
Value(null_t)
Constructs a nix language value of the singleton type "null".
Definition value.hh:417
Value(Value &&rhs)
Definition value.hh:490
Value(external_t, ExternalValueBase &external)
Definition value.hh:463
Value(path_t, char const *strPtr)
Definition value.hh:336
Value(list_t, std::span< Value * > items)
Definition value.hh:365
Value(integer_t, NixInt i)
Definition value.hh:233
Value & operator=(Value &&rhs)
Definition value.hh:502
Value()
Definition value.hh:226
Value(thunk_t, Env &env, Expr &expr)
Definition value.hh:437
Value(blackhole_t)
Constructs an evil thunk, whose evaluation represents infinite recursion.
Definition value.hh:481
Value(string_t, std::string_view copyFrom, NixStringContext const &context={})
Definition value.hh:277
ValueType type(bool invalidIsThunk=false) const
Definition value.hh:620
Value(lambda_t, Env &env, ExprLambda &lambda)
Definition value.hh:475
void clearValue()
Definition value.hh:645
Value(attrs_t, Bindings *bindings)
Definition value.hh:427
Value(list_t, SizedIterableT &items, TransformerT const &transformer)
Definition value.hh:393
Value(string_t, char const *strPtr, NixStringContext const &context)
Definition value.hh:308
Value(primOpApp_t, Value &lhs, Value &rhs)
Definition value.hh:449
PrimOp * primOpAppPrimOp() const
Definition value.cc:64
struct nix::Value::@0::@4 string
Value(app_t, Value &lhs, Value &rhs)
Definition value.hh:456
bool isTrivial() const
Definition value.cc:52
ValueType
Definition value.hh:49
std::shared_ptr< Value * > RootValue
Definition value.hh:851