1
0
Fork 0
mirror of https://github.com/NixOS/nix synced 2025-06-25 02:21:16 +02:00

libexpr: Add and use lambda getter

This commit is contained in:
Sergei Zimmerman 2025-06-12 19:42:50 +00:00
parent 371fcf91c3
commit 6587e7bcff
No known key found for this signature in database
GPG key ID: A9B0B557CA632325
11 changed files with 36 additions and 33 deletions

View file

@ -484,7 +484,7 @@ ProcessLineResult NixRepl::processLine(std::string line)
auto path = state->coerceToPath(noPos, v, context, "while evaluating the filename to edit"); auto path = state->coerceToPath(noPos, v, context, "while evaluating the filename to edit");
return {path, 0}; return {path, 0};
} else if (v.isLambda()) { } else if (v.isLambda()) {
auto pos = state->positions[v.payload.lambda.fun->pos]; auto pos = state->positions[v.lambda().fun->pos];
if (auto path = std::get_if<SourcePath>(&pos.origin)) if (auto path = std::get_if<SourcePath>(&pos.origin))
return {*path, pos.line}; return {*path, pos.line};
else else

View file

@ -667,8 +667,8 @@ namespace nix {
auto v = eval("derivation"); auto v = eval("derivation");
ASSERT_EQ(v.type(), nFunction); ASSERT_EQ(v.type(), nFunction);
ASSERT_TRUE(v.isLambda()); ASSERT_TRUE(v.isLambda());
ASSERT_NE(v.payload.lambda.fun, nullptr); ASSERT_NE(v.lambda().fun, nullptr);
ASSERT_TRUE(v.payload.lambda.fun->hasFormals()); ASSERT_TRUE(v.lambda().fun->hasFormals());
} }
TEST_F(PrimOpTest, currentTime) { TEST_F(PrimOpTest, currentTime) {

View file

@ -204,7 +204,7 @@ FrameInfo SampleStack::getFrameInfoFromValueAndPos(const Value & v, std::span<Va
/* NOTE: No actual references to garbage collected values are not held in /* NOTE: No actual references to garbage collected values are not held in
the profiler. */ the profiler. */
if (v.isLambda()) if (v.isLambda())
return LambdaFrameInfo{.expr = v.payload.lambda.fun, .callPos = pos}; return LambdaFrameInfo{.expr = v.lambda().fun, .callPos = pos};
else if (v.isPrimOp()) { else if (v.isPrimOp()) {
return getPrimOpFrameInfo(*v.primOp(), args, pos); return getPrimOpFrameInfo(*v.primOp(), args, pos);
} else if (v.isPrimOpApp()) } else if (v.isPrimOpApp())

View file

@ -147,7 +147,7 @@ PosIdx Value::determinePos(const PosIdx pos) const
#pragma GCC diagnostic ignored "-Wswitch-enum" #pragma GCC diagnostic ignored "-Wswitch-enum"
switch (internalType) { switch (internalType) {
case tAttrs: return attrs()->pos; case tAttrs: return attrs()->pos;
case tLambda: return payload.lambda.fun->pos; case tLambda: return lambda().fun->pos;
case tApp: return payload.app.left->determinePos(pos); case tApp: return payload.app.left->determinePos(pos);
default: return pos; default: return pos;
} }
@ -610,7 +610,7 @@ std::optional<EvalState::Doc> EvalState::getDoc(Value & v)
}; };
} }
if (v.isLambda()) { if (v.isLambda()) {
auto exprLambda = v.payload.lambda.fun; auto exprLambda = v.lambda().fun;
std::ostringstream s; std::ostringstream s;
std::string name; std::string name;
@ -1567,13 +1567,13 @@ void EvalState::callFunction(Value & fun, std::span<Value *> args, Value & vRes,
if (vCur.isLambda()) { if (vCur.isLambda()) {
ExprLambda & lambda(*vCur.payload.lambda.fun); ExprLambda & lambda(*vCur.lambda().fun);
auto size = auto size =
(!lambda.arg ? 0 : 1) + (!lambda.arg ? 0 : 1) +
(lambda.hasFormals() ? lambda.formals->formals.size() : 0); (lambda.hasFormals() ? lambda.formals->formals.size() : 0);
Env & env2(allocEnv(size)); Env & env2(allocEnv(size));
env2.up = vCur.payload.lambda.env; env2.up = vCur.lambda().env;
Displacement displ = 0; Displacement displ = 0;
@ -1603,7 +1603,7 @@ void EvalState::callFunction(Value & fun, std::span<Value *> args, Value & vRes,
symbols[i.name]) symbols[i.name])
.atPos(lambda.pos) .atPos(lambda.pos)
.withTrace(pos, "from call site") .withTrace(pos, "from call site")
.withFrame(*fun.payload.lambda.env, lambda) .withFrame(*fun.lambda().env, lambda)
.debugThrow(); .debugThrow();
} }
env2.values[displ++] = i.def->maybeThunk(*this, env2); env2.values[displ++] = i.def->maybeThunk(*this, env2);
@ -1630,7 +1630,7 @@ void EvalState::callFunction(Value & fun, std::span<Value *> args, Value & vRes,
.atPos(lambda.pos) .atPos(lambda.pos)
.withTrace(pos, "from call site") .withTrace(pos, "from call site")
.withSuggestions(suggestions) .withSuggestions(suggestions)
.withFrame(*fun.payload.lambda.env, lambda) .withFrame(*fun.lambda().env, lambda)
.debugThrow(); .debugThrow();
} }
unreachable(); unreachable();
@ -1825,14 +1825,14 @@ void EvalState::autoCallFunction(const Bindings & args, Value & fun, Value & res
} }
} }
if (!fun.isLambda() || !fun.payload.lambda.fun->hasFormals()) { if (!fun.isLambda() || !fun.lambda().fun->hasFormals()) {
res = fun; res = fun;
return; return;
} }
auto attrs = buildBindings(std::max(static_cast<uint32_t>(fun.payload.lambda.fun->formals->formals.size()), args.size())); auto attrs = buildBindings(std::max(static_cast<uint32_t>(fun.lambda().fun->formals->formals.size()), args.size()));
if (fun.payload.lambda.fun->formals->ellipsis) { if (fun.lambda().fun->formals->ellipsis) {
// If the formals have an ellipsis (eg the function accepts extra args) pass // If the formals have an ellipsis (eg the function accepts extra args) pass
// all available automatic arguments (which includes arguments specified on // all available automatic arguments (which includes arguments specified on
// the command line via --arg/--argstr) // the command line via --arg/--argstr)
@ -1840,7 +1840,7 @@ void EvalState::autoCallFunction(const Bindings & args, Value & fun, Value & res
attrs.insert(v); attrs.insert(v);
} else { } else {
// Otherwise, only pass the arguments that the function accepts // Otherwise, only pass the arguments that the function accepts
for (auto & i : fun.payload.lambda.fun->formals->formals) { for (auto & i : fun.lambda().fun->formals->formals) {
auto j = args.get(i.name); auto j = args.get(i.name);
if (j) { if (j) {
attrs.insert(*j); attrs.insert(*j);
@ -1850,7 +1850,7 @@ Nix attempted to evaluate a function as a top level expression; in
this case it must have its arguments supplied either by default this case it must have its arguments supplied either by default
values, or passed explicitly with '--arg' or '--argstr'. See values, or passed explicitly with '--arg' or '--argstr'. See
https://nixos.org/manual/nix/stable/language/constructs.html#functions.)", symbols[i.name]) https://nixos.org/manual/nix/stable/language/constructs.html#functions.)", symbols[i.name])
.atPos(i.pos).withFrame(*fun.payload.lambda.env, *fun.payload.lambda.fun).debugThrow(); .atPos(i.pos).withFrame(*fun.lambda().env, *fun.lambda().fun).debugThrow();
} }
} }
} }

View file

@ -482,6 +482,9 @@ public:
NixFloat fpoint() const NixFloat fpoint() const
{ return payload.fpoint; } { return payload.fpoint; }
Lambda lambda() const
{ return payload.lambda; }
}; };

View file

@ -3138,12 +3138,12 @@ static void prim_functionArgs(EvalState & state, const PosIdx pos, Value * * arg
if (!args[0]->isLambda()) if (!args[0]->isLambda())
state.error<TypeError>("'functionArgs' requires a function").atPos(pos).debugThrow(); state.error<TypeError>("'functionArgs' requires a function").atPos(pos).debugThrow();
if (!args[0]->payload.lambda.fun->hasFormals()) { if (!args[0]->lambda().fun->hasFormals()) {
v.mkAttrs(&state.emptyBindings); v.mkAttrs(&state.emptyBindings);
return; return;
} }
const auto &formals = args[0]->payload.lambda.fun->formals->formals; const auto &formals = args[0]->lambda().fun->formals->formals;
auto attrs = state.buildBindings(formals.size()); auto attrs = state.buildBindings(formals.size());
for (auto & i : formals) for (auto & i : formals)
attrs.insert(i.name, state.getBool(i.def), i.pos); attrs.insert(i.name, state.getBool(i.def), i.pos);

View file

@ -453,13 +453,13 @@ private:
if (v.isLambda()) { if (v.isLambda()) {
output << "lambda"; output << "lambda";
if (v.payload.lambda.fun) { if (v.lambda().fun) {
if (v.payload.lambda.fun->name) { if (v.lambda().fun->name) {
output << " " << state.symbols[v.payload.lambda.fun->name]; output << " " << state.symbols[v.lambda().fun->name];
} }
std::ostringstream s; std::ostringstream s;
s << state.positions[v.payload.lambda.fun->pos]; s << state.positions[v.lambda().fun->pos];
output << " @ " << filterANSIEscapes(toView(s)); output << " @ " << filterANSIEscapes(toView(s));
} }
} else if (v.isPrimOp()) { } else if (v.isPrimOp()) {

View file

@ -126,18 +126,18 @@ static void printValueAsXML(EvalState & state, bool strict, bool location,
break; break;
} }
XMLAttrs xmlAttrs; XMLAttrs xmlAttrs;
if (location) posToXML(state, xmlAttrs, state.positions[v.payload.lambda.fun->pos]); if (location) posToXML(state, xmlAttrs, state.positions[v.lambda().fun->pos]);
XMLOpenElement _(doc, "function", xmlAttrs); XMLOpenElement _(doc, "function", xmlAttrs);
if (v.payload.lambda.fun->hasFormals()) { if (v.lambda().fun->hasFormals()) {
XMLAttrs attrs; XMLAttrs attrs;
if (v.payload.lambda.fun->arg) attrs["name"] = state.symbols[v.payload.lambda.fun->arg]; if (v.lambda().fun->arg) attrs["name"] = state.symbols[v.lambda().fun->arg];
if (v.payload.lambda.fun->formals->ellipsis) attrs["ellipsis"] = "1"; if (v.lambda().fun->formals->ellipsis) attrs["ellipsis"] = "1";
XMLOpenElement _(doc, "attrspat", attrs); XMLOpenElement _(doc, "attrspat", attrs);
for (auto & i : v.payload.lambda.fun->formals->lexicographicOrder(state.symbols)) for (auto & i : v.lambda().fun->formals->lexicographicOrder(state.symbols))
doc.writeEmptyElement("attr", singletonAttrs("name", state.symbols[i.name])); doc.writeEmptyElement("attr", singletonAttrs("name", state.symbols[i.name]));
} else } else
doc.writeEmptyElement("varpat", singletonAttrs("name", state.symbols[v.payload.lambda.fun->arg])); doc.writeEmptyElement("varpat", singletonAttrs("name", state.symbols[v.lambda().fun->arg]));
break; break;
} }

View file

@ -252,8 +252,8 @@ static Flake readFlake(
if (auto outputs = vInfo.attrs()->get(sOutputs)) { if (auto outputs = vInfo.attrs()->get(sOutputs)) {
expectType(state, nFunction, *outputs->value, outputs->pos); expectType(state, nFunction, *outputs->value, outputs->pos);
if (outputs->value->isLambda() && outputs->value->payload.lambda.fun->hasFormals()) { if (outputs->value->isLambda() && outputs->value->lambda().fun->hasFormals()) {
for (auto & formal : outputs->value->payload.lambda.fun->formals->formals) { for (auto & formal : outputs->value->lambda().fun->formals->formals) {
if (formal.name != state.sSelf) if (formal.name != state.sSelf)
flake.inputs.emplace(state.symbols[formal.name], FlakeInput { flake.inputs.emplace(state.symbols[formal.name], FlakeInput {
.ref = parseFlakeRef(state.fetchSettings, std::string(state.symbols[formal.name])) .ref = parseFlakeRef(state.fetchSettings, std::string(state.symbols[formal.name]))

View file

@ -387,8 +387,8 @@ static void main_nix_build(int argc, char * * argv)
return false; return false;
} }
bool add = false; bool add = false;
if (v.type() == nFunction && v.payload.lambda.fun->hasFormals()) { if (v.type() == nFunction && v.lambda().fun->hasFormals()) {
for (auto & i : v.payload.lambda.fun->formals->formals) { for (auto & i : v.lambda().fun->formals->formals) {
if (state->symbols[i.name] == "inNixShell") { if (state->symbols[i.name] == "inNixShell") {
add = true; add = true;
break; break;

View file

@ -492,8 +492,8 @@ struct CmdFlakeCheck : FlakeCommand
if (!v.isLambda()) { if (!v.isLambda()) {
throw Error("overlay is not a function, but %s instead", showType(v)); throw Error("overlay is not a function, but %s instead", showType(v));
} }
if (v.payload.lambda.fun->hasFormals() if (v.lambda().fun->hasFormals()
|| !argHasName(v.payload.lambda.fun->arg, "final")) || !argHasName(v.lambda().fun->arg, "final"))
throw Error("overlay does not take an argument named 'final'"); throw Error("overlay does not take an argument named 'final'");
// FIXME: if we have a 'nixpkgs' input, use it to // FIXME: if we have a 'nixpkgs' input, use it to
// evaluate the overlay. // evaluate the overlay.