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