libexpr: heap-allocate "large" integers

Change-Id: Ic391f2f1bf87f044d7a688196ba9e0ad766d65aa
This commit is contained in:
eldritch horrors
2025-10-04 16:31:45 +02:00
parent 79586575c5
commit 0e9e9fd917
8 changed files with 67 additions and 21 deletions
+1
View File
@@ -124,6 +124,7 @@ std::string showType(const Value & v)
case Value::Acb::tFloat:
case Value::Acb::tNull:
case Value::Acb::tLambda:
case Value::Acb::tInt:
return std::string(showType(v.type()));
case Value::Acb::tPrimOp:
return fmt("the built-in function '%s'", v.primOp()->name);
+10 -6
View File
@@ -175,18 +175,22 @@ protected:
Value v;
ExprLiteral(const PosIdx pos) : Expr(pos) {};
public:
ExprLiteral(const PosIdx pos, NewValueAs::integer_t, NixInt n) : Expr(pos) { v.mkInt(n); };
ExprLiteral(const PosIdx pos, NewValueAs::integer_t, NixInt::Inner n) : Expr(pos)
{
v.mkInt(n);
}
Value * maybeThunk(EvalState & state, Env & env) override;
JSON toJSON(const SymbolTable & symbols) const override;
void eval(EvalState & state, Env & env, Value & v) override;
void accept(ExprVisitor & ev, std::unique_ptr<Expr> & ptr) override { ev.visit(*this, ptr); }
};
struct ExprInt : ExprLiteral
{
Value::Int i;
ExprInt(const PosIdx pos, NixInt n) : ExprLiteral(pos), i{{Value::Acb::tInt}, n}
{
v = Value::isTaggableInteger(n) ? Value{NewValueAs::integer, n} : Value(i);
}
ExprInt(const PosIdx pos, NixInt::Inner n) : ExprInt(pos, NixInt(n)) {}
};
struct ExprFloat : ExprLiteral
{
Value::Float f;
+2 -2
View File
@@ -148,7 +148,7 @@ struct ExprState
std::unique_ptr<Expr> negate(PosIdx pos, State & state)
{
std::vector<std::unique_ptr<Expr>> args(2);
args[0] = std::make_unique<ExprLiteral>(pos, NewValueAs::integer, 0);
args[0] = std::make_unique<ExprInt>(pos, 0);
args[1] = popExprOnly();
return std::make_unique<ExprCall>(pos, state.mkInternalVar(pos, state.s.sub), std::move(args));
}
@@ -507,7 +507,7 @@ template<> struct BuildAST<grammar::v1::expr::int_> {
.pos = ps.positions[ps.at(in)],
});
}
s.emplaceExpr<ExprLiteral>(ps.at(in), NewValueAs::integer, v);
s.emplaceExpr<ExprInt>(ps.at(in), v);
}
};
+32 -9
View File
@@ -5,6 +5,7 @@
#include <climits>
#include <cstdint>
#include <functional>
#include <limits>
#include <ranges>
#include <span>
@@ -256,6 +257,7 @@ public:
struct Null;
struct Lambda;
struct Thunk;
struct Int;
static const Null NULL_ACB;
@@ -284,6 +286,12 @@ public:
struct List;
struct PrimOp;
static bool isTaggableInteger(NixInt i)
{
return i.value <= (std::numeric_limits<intptr_t>::max() >> 3)
&& i.value >= (std::numeric_limits<intptr_t>::min() >> 3);
}
/// Default constructor which is still used in the codebase but should not
/// be used in new code. Zero initializes its members.
[[deprecated]] Value()
@@ -297,11 +305,15 @@ public:
: internalType(tInt)
, _empty{ 0, 0 }
{
// the NixInt ctor here is is special because NixInt has a ctor too, so
// we're not allowed to have it as an anonymous aggreagte member. we do
// however still have the option to clear the data members using _empty
// and leaving the second word of data cleared by setting only integer.
_integer = i;
if (isTaggableInteger(i)) {
_integer = i;
} else {
internalType = tAuxiliary;
auto ip = gcAllocType<Int>();
ip->type = Acb::tInt;
ip->value = i;
_auxiliary = ip;
}
}
/// Constructs a nix language value of type "float", with the floating
@@ -666,6 +678,7 @@ public:
tNull,
tPrimOp,
tLambda,
tInt,
} type;
};
struct External : Acb
@@ -682,6 +695,11 @@ public:
{
explicit PrimOp(PrimOpDetails && p) : Acb{tPrimOp}, PrimOpDetails(std::move(p)) {}
};
struct Int : Acb
{
NixInt value;
};
struct Lambda : Acb
{
Env * env;
@@ -761,6 +779,8 @@ public:
case Acb::tPrimOp:
case Acb::tLambda:
return nFunction;
case Acb::tInt:
return nInt;
}
case tThunk:
return nThunk;
@@ -789,9 +809,7 @@ public:
inline void mkInt(NixInt n)
{
clearValue();
internalType = tInt;
_integer = n;
*this = {NewValueAs::integer, n};
}
inline void mkBool(bool b)
@@ -916,7 +934,12 @@ public:
NixInt integer() const
{
return _integer;
if (internalType == tInt) {
return _integer;
} else {
assert(internalType == tAuxiliary && _auxiliary->type == Acb::tInt);
return static_cast<const Int *>(_auxiliary)->value;
}
}
bool boolean() const
@@ -0,0 +1 @@
[ [ 0 1 3 7 15 31 63 127 255 511 1023 2047 4095 8191 16383 32767 65535 131071 262143 524287 1048575 2097151 4194303 8388607 16777215 33554431 67108863 134217727 268435455 536870911 1073741823 2147483647 4294967295 8589934591 17179869183 34359738367 68719476735 137438953471 274877906943 549755813887 1099511627775 2199023255551 4398046511103 8796093022207 17592186044415 35184372088831 70368744177663 140737488355327 281474976710655 562949953421311 1125899906842623 2251799813685247 4503599627370495 9007199254740991 18014398509481983 36028797018963967 72057594037927935 144115188075855871 288230376151711743 576460752303423487 1152921504606846975 2305843009213693951 4611686018427387903 9223372036854775807 ] [ -1 -2 -4 -8 -16 -32 -64 -128 -256 -512 -1024 -2048 -4096 -8192 -16384 -32768 -65536 -131072 -262144 -524288 -1048576 -2097152 -4194304 -8388608 -16777216 -33554432 -67108864 -134217728 -268435456 -536870912 -1073741824 -2147483648 -4294967296 -8589934592 -17179869184 -34359738368 -68719476736 -137438953472 -274877906944 -549755813888 -1099511627776 -2199023255552 -4398046511104 -8796093022208 -17592186044416 -35184372088832 -70368744177664 -140737488355328 -281474976710656 -562949953421312 -1125899906842624 -2251799813685248 -4503599627370496 -9007199254740992 -18014398509481984 -36028797018963968 -72057594037927936 -144115188075855872 -288230376151711744 -576460752303423488 -1152921504606846976 -2305843009213693952 -4611686018427387904 -9223372036854775808 ] ]
@@ -0,0 +1,8 @@
let
positive = n: acc: if n == 0 then [] else [ acc ] ++ positive (n - 1) (acc * 2 + 1);
negative = n: acc: if n == 0 then [] else [ acc ] ++ negative (n - 1) (acc * 2);
in
[
(positive 64 0)
(negative 64 (-1))
]
@@ -1,6 +1,10 @@
[[test]]
runner = "eval-okay"
[[test]]
runner = "eval-okay"
in = "in-int-range.nix"
[[test]]
runner = "eval-okay"
in = "in-override.nix"
+9 -4
View File
@@ -1,3 +1,4 @@
#include "lix/libexpr/nixexpr.hh"
#include "lix/libutil/canon-path.hh"
#include "lix/libutil/source-path.hh"
#include "lix/libutil/terminal.hh"
@@ -94,7 +95,7 @@ TEST_F(ValuePrintingTests, vThunk)
{
EvalMemory mem;
Env env;
ExprLiteral e(noPos, NewValueAs::integer, 0);
ExprInt e(noPos, 0);
Value vThunk{NewValueAs::thunk, mem, env, e};
test(vThunk, "«thunk»");
@@ -119,7 +120,9 @@ TEST_F(ValuePrintingTests, vLambda)
PosTable::Origin origin = evaluator.positions.addOrigin(std::monostate(), 1);
auto posIdx = evaluator.positions.add(origin, 0);
ExprLambda eLambda(posIdx, std::make_unique<AttrsPattern>(), std::make_unique<ExprLiteral>(noPos, NewValueAs::integer, 0));
ExprLambda eLambda(
posIdx, std::make_unique<AttrsPattern>(), std::make_unique<ExprInt>(noPos, 0)
);
eLambda.pattern->name = createSymbol("a");
Value vLambda{NewValueAs::lambda, mem, env, eLambda};
@@ -554,7 +557,9 @@ TEST_F(ValuePrintingTests, ansiColorsLambda)
PosTable::Origin origin = evaluator.positions.addOrigin(std::monostate(), 1);
auto posIdx = evaluator.positions.add(origin, 0);
ExprLambda eLambda(posIdx, std::make_unique<AttrsPattern>(), std::make_unique<ExprLiteral>(noPos, NewValueAs::integer, 0));
ExprLambda eLambda(
posIdx, std::make_unique<AttrsPattern>(), std::make_unique<ExprInt>(noPos, 0)
);
eLambda.pattern->name = createSymbol("a");
Value vLambda{NewValueAs::lambda, mem, env, eLambda};
@@ -609,7 +614,7 @@ TEST_F(ValuePrintingTests, ansiColorsThunk)
{
EvalMemory mem;
Env env;
ExprLiteral e(noPos, NewValueAs::integer, 0);
ExprInt e(noPos, 0);
Value v{NewValueAs::thunk, mem, env, e};
test(v,