libexpr: move lambdas to auxiliary storage
Change-Id: Ibe4885f17c0ba1634ed6dbca0a45f8bd4619d69b
This commit is contained in:
@@ -26,6 +26,15 @@ inline Value::Value(app_t, EvalMemory & mem, Value & lhs, std::span<Value *> arg
|
||||
}
|
||||
}
|
||||
|
||||
inline Value::Value(lambda_t, EvalMemory & mem, Env & env, ExprLambda & lambda)
|
||||
: internalType(tAuxiliary)
|
||||
, _aux_pad(0)
|
||||
{
|
||||
auto lp = mem.allocType<Lambda>();
|
||||
*lp = Lambda{{Acb::tLambda}, &env, &lambda};
|
||||
_auxiliary = lp;
|
||||
}
|
||||
|
||||
[[gnu::always_inline]]
|
||||
void * EvalMemory::allocBytes(size_t size)
|
||||
{
|
||||
|
||||
+2
-1
@@ -108,6 +108,7 @@ std::string showType(const Value & v)
|
||||
return v.external()->showType();
|
||||
case Value::Acb::tFloat:
|
||||
case Value::Acb::tNull:
|
||||
case Value::Acb::tLambda:
|
||||
return std::string(showType(v.type()));
|
||||
case Value::Acb::tPrimOp:
|
||||
return fmt("the built-in function '%s'", v.primOp()->name);
|
||||
@@ -1415,7 +1416,7 @@ void ExprOpHasAttr::eval(EvalState & state, Env & env, Value & v)
|
||||
|
||||
void ExprLambda::eval(EvalState & state, Env & env, Value & v)
|
||||
{
|
||||
v.mkLambda(&env, this);
|
||||
v = {NewValueAs::lambda, state.ctx.mem, env, *this};
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
+15
-21
@@ -77,7 +77,6 @@ typedef enum {
|
||||
tList,
|
||||
tThunk,
|
||||
tApp,
|
||||
tLambda,
|
||||
tAuxiliary,
|
||||
} InternalType;
|
||||
|
||||
@@ -259,6 +258,7 @@ public:
|
||||
struct String;
|
||||
struct Acb;
|
||||
struct Null;
|
||||
struct Lambda;
|
||||
|
||||
static const Null NULL_ACB;
|
||||
|
||||
@@ -521,10 +521,7 @@ public:
|
||||
/// This takes the environment the lambda is closed over @ref env, and
|
||||
/// the lambda expression itself @ref lambda, which will not be evaluated
|
||||
/// until it is applied.
|
||||
Value(lambda_t, Env & env, ExprLambda & lambda)
|
||||
: internalType(tLambda)
|
||||
, _lambda({ .env = &env, .fun = &lambda })
|
||||
{ }
|
||||
Value(lambda_t, EvalMemory & mem, Env & env, ExprLambda & lambda);
|
||||
|
||||
/// Constructs an evil thunk, whose evaluation represents infinite recursion.
|
||||
explicit Value(blackhole_t)
|
||||
@@ -582,7 +579,10 @@ public:
|
||||
}
|
||||
|
||||
// type() == nFunction
|
||||
inline bool isLambda() const { return internalType == tLambda; };
|
||||
inline bool isLambda() const
|
||||
{
|
||||
return internalType == tAuxiliary && _auxiliary->type == Acb::tLambda;
|
||||
};
|
||||
inline bool isPrimOp() const
|
||||
{
|
||||
return internalType == tAuxiliary && _auxiliary->type == Acb::tPrimOp;
|
||||
@@ -690,6 +690,7 @@ public:
|
||||
tFloat,
|
||||
tNull,
|
||||
tPrimOp,
|
||||
tLambda,
|
||||
} type;
|
||||
};
|
||||
struct External : Acb
|
||||
@@ -706,6 +707,11 @@ public:
|
||||
{
|
||||
explicit PrimOp(PrimOpDetails && p) : Acb{tPrimOp}, PrimOpDetails(std::move(p)) {}
|
||||
};
|
||||
struct Lambda : Acb
|
||||
{
|
||||
Env * env;
|
||||
ExprLambda * fun;
|
||||
};
|
||||
|
||||
union
|
||||
{
|
||||
@@ -737,11 +743,6 @@ public:
|
||||
Expr * expr;
|
||||
} _thunk;
|
||||
App _app;
|
||||
struct
|
||||
{
|
||||
Env * env;
|
||||
ExprLambda * fun;
|
||||
} _lambda;
|
||||
struct {
|
||||
const Acb * _auxiliary;
|
||||
uintptr_t _aux_pad;
|
||||
@@ -765,8 +766,6 @@ public:
|
||||
case tAttrs: return nAttrs;
|
||||
case tList:
|
||||
return nList;
|
||||
case tLambda:
|
||||
return nFunction;
|
||||
case tAuxiliary:
|
||||
switch (_auxiliary->type) {
|
||||
case Acb::tExternal:
|
||||
@@ -776,6 +775,7 @@ public:
|
||||
case Acb::tNull:
|
||||
return nNull;
|
||||
case Acb::tPrimOp:
|
||||
case Acb::tLambda:
|
||||
return nFunction;
|
||||
}
|
||||
case tThunk:
|
||||
@@ -868,13 +868,6 @@ public:
|
||||
*this = {NewValueAs::app, *l, *r};
|
||||
}
|
||||
|
||||
inline void mkLambda(Env * e, ExprLambda * f)
|
||||
{
|
||||
internalType = tLambda;
|
||||
_lambda.env = e;
|
||||
_lambda.fun = f;
|
||||
}
|
||||
|
||||
inline void mkBlackhole()
|
||||
{
|
||||
internalType = tThunk;
|
||||
@@ -992,7 +985,8 @@ public:
|
||||
|
||||
const auto & lambda() const
|
||||
{
|
||||
return _lambda;
|
||||
assert(internalType == tAuxiliary && _auxiliary->type == Acb::tLambda);
|
||||
return *static_cast<const Lambda *>(_auxiliary);
|
||||
}
|
||||
|
||||
const PrimOp * primOp() const
|
||||
|
||||
@@ -110,6 +110,7 @@ TEST_F(ValuePrintingTests, vApp)
|
||||
|
||||
TEST_F(ValuePrintingTests, vLambda)
|
||||
{
|
||||
EvalMemory mem;
|
||||
Env env {
|
||||
.up = nullptr,
|
||||
.values = { }
|
||||
@@ -120,8 +121,7 @@ TEST_F(ValuePrintingTests, vLambda)
|
||||
ExprLambda eLambda(posIdx, std::make_unique<AttrsPattern>(), std::make_unique<ExprLiteral>(noPos, NewValueAs::integer, 0));
|
||||
eLambda.pattern->name = createSymbol("a");
|
||||
|
||||
Value vLambda;
|
||||
vLambda.mkLambda(&env, &eLambda);
|
||||
Value vLambda{NewValueAs::lambda, mem, env, eLambda};
|
||||
|
||||
test(vLambda, "«lambda @ «none»:1:1»");
|
||||
|
||||
@@ -546,6 +546,7 @@ TEST_F(ValuePrintingTests, ansiColorsList)
|
||||
|
||||
TEST_F(ValuePrintingTests, ansiColorsLambda)
|
||||
{
|
||||
EvalMemory mem;
|
||||
Env env {
|
||||
.up = nullptr,
|
||||
.values = { }
|
||||
@@ -556,8 +557,7 @@ TEST_F(ValuePrintingTests, ansiColorsLambda)
|
||||
ExprLambda eLambda(posIdx, std::make_unique<AttrsPattern>(), std::make_unique<ExprLiteral>(noPos, NewValueAs::integer, 0));
|
||||
eLambda.pattern->name = createSymbol("a");
|
||||
|
||||
Value vLambda;
|
||||
vLambda.mkLambda(&env, &eLambda);
|
||||
Value vLambda{NewValueAs::lambda, mem, env, eLambda};
|
||||
|
||||
test(vLambda,
|
||||
ANSI_BLUE "«lambda @ «none»:1:1»" ANSI_NORMAL,
|
||||
|
||||
Reference in New Issue
Block a user