aboutsummaryrefslogtreecommitdiff
path: root/src/libexpr/eval.cc
diff options
context:
space:
mode:
authoreldritch horrors <pennae@lix.systems>2024-03-08 03:05:47 +0100
committereldritch horrors <pennae@lix.systems>2024-03-09 03:50:06 +0100
commit512c1f05c37c612347dd1fda4771a09744a1a3cd (patch)
tree9ae77da1a45060b12520326b426efc5014a51c0b /src/libexpr/eval.cc
parent0e8f505f666d9b0714840e4fe878e6aece918908 (diff)
Unify and refactor value printing
Previously, there were two mostly-identical value printers -- one in `libexpr/eval.cc` (which didn't force values) and one in `libcmd/repl.cc` (which did force values and also printed ANSI color codes). This PR unifies both of these printers into `print.cc` and provides a `PrintOptions` struct for controlling the output, which allows for toggling whether values are forced, whether repeated values are tracked, and whether ANSI color codes are displayed. Additionally, `PrintOptions` allows tuning the maximum number of attributes, list items, and bytes in a string that will be displayed; this makes it ideal for contexts where printing too much output (e.g. all of Nixpkgs) is distracting. (As requested by @roberth in https://github.com/NixOS/nix/pull/9554#issuecomment-1845095735) Please read the tests for example output. Future work: - It would be nice to provide this function as a builtin, perhaps `builtins.toStringDebug` -- a printing function that never fails would be useful when debugging Nix code. - It would be nice to support customizing `PrintOptions` members on the command line, e.g. `--option to-string-max-attrs 1000`. (cherry picked from commit 0fa08b451682fb3311fe58112ff05c4fe5bee3a4, ) === Restore ambiguous value printer for `nix-instantiate` The Nix team has requested that this output format remain unchanged. I've added a warning to the man page explaining that `nix-instantiate --eval` output will not parse correctly in many situations. (cherry picked from commit df84dd4d8dd3fd6381ac2ca3064432ab31a16b79) Change-Id: I7cca6b4b53cd0642f2d49af657d5676a8554c9f8
Diffstat (limited to 'src/libexpr/eval.cc')
-rw-r--r--src/libexpr/eval.cc126
1 files changed, 26 insertions, 100 deletions
diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc
index 8e3077a67..729b17887 100644
--- a/src/libexpr/eval.cc
+++ b/src/libexpr/eval.cc
@@ -100,117 +100,23 @@ RootValue allocRootValue(Value * v)
#endif
}
-void Value::print(const SymbolTable &symbols, std::ostream &str,
- std::set<const void *> *seen, int depth) const
-
-{
- checkInterrupt();
-
- if (depth <= 0) {
- str << "«too deep»";
- return;
- }
- switch (internalType) {
- case tInt:
- str << integer;
- break;
- case tBool:
- printLiteralBool(str, boolean);
- break;
- case tString:
- printLiteralString(str, string.s);
- break;
- case tPath:
- str << path().to_string(); // !!! escaping?
- break;
- case tNull:
- str << "null";
- break;
- case tAttrs: {
- if (seen && !attrs->empty() && !seen->insert(attrs).second)
- str << "«repeated»";
- else {
- str << "{ ";
- for (auto & i : attrs->lexicographicOrder(symbols)) {
- str << symbols[i->name] << " = ";
- i->value->print(symbols, str, seen, depth - 1);
- str << "; ";
- }
- str << "}";
- }
- break;
- }
- case tList1:
- case tList2:
- case tListN:
- if (seen && listSize() && !seen->insert(listElems()).second)
- str << "«repeated»";
- else {
- str << "[ ";
- for (auto v2 : listItems()) {
- if (v2)
- v2->print(symbols, str, seen, depth - 1);
- else
- str << "(nullptr)";
- str << " ";
- }
- str << "]";
- }
- break;
- case tThunk:
- case tApp:
- if (!isBlackhole()) {
- str << "<CODE>";
- } else {
- // Although we know for sure that it's going to be an infinite recursion
- // when this value is accessed _in the current context_, it's likely
- // that the user will misinterpret a simpler «infinite recursion» output
- // as a definitive statement about the value, while in fact it may be
- // a valid value after `builtins.trace` and perhaps some other steps
- // have completed.
- str << "«potential infinite recursion»";
- }
- break;
- case tLambda:
- str << "<LAMBDA>";
- break;
- case tPrimOp:
- str << "<PRIMOP>";
- break;
- case tPrimOpApp:
- str << "<PRIMOP-APP>";
- break;
- case tExternal:
- str << *external;
- break;
- case tFloat:
- str << fpoint;
- break;
- default:
- printError("Nix evaluator internal error: Value::print(): invalid value type %1%", internalType);
- abort();
- }
-}
-
-void Value::print(const SymbolTable &symbols, std::ostream &str,
- bool showRepeated, int depth) const {
- std::set<const void *> seen;
- print(symbols, str, showRepeated ? nullptr : &seen, depth);
-}
-
// Pretty print types for assertion errors
std::ostream & operator << (std::ostream & os, const ValueType t) {
os << showType(t);
return os;
}
-std::string printValue(const EvalState & state, const Value & v)
+std::string printValue(EvalState & state, Value & v)
{
std::ostringstream out;
- v.print(state.symbols, out);
+ v.print(state, out);
return out.str();
}
+void Value::print(EvalState & state, std::ostream & str, PrintOptions options)
+{
+ printValue(state, str, *this, options);
+}
const Value * getPrimOp(const Value &v) {
const Value * primOp = &v;
@@ -717,6 +623,26 @@ void PrimOp::check()
}
+std::ostream & operator<<(std::ostream & output, PrimOp & primOp)
+{
+ output << "primop " << primOp.name;
+ return output;
+}
+
+
+PrimOp * Value::primOpAppPrimOp() const
+{
+ Value * left = primOpApp.left;
+ while (left && !left->isPrimOp()) {
+ left = left->primOpApp.left;
+ }
+
+ if (!left)
+ return nullptr;
+ return left->primOp;
+}
+
+
void Value::mkPrimOp(PrimOp * p)
{
p->check();