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:
parent
371fcf91c3
commit
6587e7bcff
11 changed files with 36 additions and 33 deletions
|
@ -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
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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())
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -482,6 +482,9 @@ public:
|
||||||
|
|
||||||
NixFloat fpoint() const
|
NixFloat fpoint() const
|
||||||
{ return payload.fpoint; }
|
{ return payload.fpoint; }
|
||||||
|
|
||||||
|
Lambda lambda() const
|
||||||
|
{ return payload.lambda; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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()) {
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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]))
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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.
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue